Files
bank/portfolio_test.go
zeekayandHanzo Dev 7f0c9be71f the demo book cannot seed itself into a live bank
seedPortfolio writes two dozen invented customers with invented KYC approvals,
which is right for a demo and would put fabricated identities in a real
compliance queue. It refuses outside sandbox and nothing held it there.

Both halves now do. Outside sandbox it seeds nothing — removing the guard puts
"24 invented customers into a live bank" in the failure message. Inside, it seeds
once: making it non-idempotent takes the book "from 24 accounts to 48", which is
what a second boot would have shown in the console.

Sandbox itself is pinned too, because it decides this and more — simulated chain
sends, the faucet. It defaults ON and is false only for false/0/no/off,
case-insensitively. So an operator who writes BANK_SANDBOX=disabled gets a
sandbox and no complaint, and the accepted words are worth stating rather than
discovering.

Also asserted: every seeded row carries a name, type, country, currency, status
and KYC state, since the console renders all of them and a blank one reads as a
broken customer.

portfolio.go 0.0% -> covered.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-25 12:50:14 -07:00

86 lines
2.9 KiB
Go

package bank
import (
"testing"
"github.com/luxfi/bank/collections"
)
// Sandbox decides whether this deployment fakes things: simulated chain sends,
// a faucet, and a seeded book of invented customers. It defaults to ON — only
// an explicit off word turns it off — so the spellings it accepts are the whole
// of an operator's ability to say "this one is real".
func TestSandboxIsOnUnlessTurnedOff(t *testing.T) {
for _, raw := range []string{"false", "FALSE", "False", "0", "no", "NO", "off", "OFF", " off "} {
t.Setenv("BANK_SANDBOX", raw)
if Sandbox() {
t.Errorf("BANK_SANDBOX=%q left the deployment in sandbox", raw)
}
}
// Unset, empty, and anything it does not recognise all mean sandbox. An
// operator who writes "disabled" gets a sandbox and no complaint, so the
// accepted words are worth knowing exactly.
for _, raw := range []string{"", "true", "1", "yes", "on", "disabled", "n", "prod"} {
t.Setenv("BANK_SANDBOX", raw)
if !Sandbox() {
t.Errorf("BANK_SANDBOX=%q turned sandbox off — it is not one of the off words", raw)
}
}
}
// The demo book is invented customers with invented KYC approvals. Seeding it
// into a live bank would put fabricated identities in the compliance queue, so
// the seeder refuses outside sandbox and this holds it there.
func TestPortfolioSeedRefusesOutsideSandbox(t *testing.T) {
app := newBankApp(t)
t.Setenv("BANK_SANDBOX", "false")
seedPortfolio(app)
found, err := app.FindRecordsByFilter(collections.AccountCollectionName,
"owner ~ {:p}", "", 0, 0, map[string]any{"p": pfOwnerPrefix + "%"})
if err != nil {
t.Fatalf("query: %v", err)
}
if len(found) != 0 {
t.Fatalf("%d invented customers were seeded into a live bank", len(found))
}
}
// In sandbox it seeds the book once. Twice would double every customer in the
// console on the second boot.
func TestPortfolioSeedIsIdempotent(t *testing.T) {
app := newBankApp(t)
t.Setenv("BANK_SANDBOX", "true")
seedPortfolio(app)
first, err := app.FindRecordsByFilter(collections.AccountCollectionName,
"owner ~ {:p}", "", 0, 0, map[string]any{"p": pfOwnerPrefix + "%"})
if err != nil {
t.Fatalf("query: %v", err)
}
if len(first) == 0 {
t.Fatal("the book seeded nothing in sandbox")
}
seedPortfolio(app)
again, err := app.FindRecordsByFilter(collections.AccountCollectionName,
"owner ~ {:p}", "", 0, 0, map[string]any{"p": pfOwnerPrefix + "%"})
if err != nil {
t.Fatalf("query: %v", err)
}
if len(again) != len(first) {
t.Fatalf("a second boot took the book from %d accounts to %d", len(first), len(again))
}
// Every seeded row is a credible book entry, not a half-written record: the
// console reads all of these and a blank one shows as a broken customer.
for _, r := range first {
for _, f := range []string{"entityName", "entityType", "country", "currency", "status", "kycStatus"} {
if r.GetString(f) == "" {
t.Fatalf("seeded account %s has an empty %s", r.Id, f)
}
}
}
}