Test signup completion freshness and account helper callers
1 file changed,
+98
−0
internal/console/signupconsumer_test.go+98 −0
CI passed — run details
diff --git a/internal/console/signupconsumer_test.go b/internal/console/signupconsumer_test.go| new file mode 100644 |
| index 000000000..a8e50a845 |
| --- /dev/null |
| +++ b/internal/console/signupconsumer_test.go |
| @@ -0,0 +1,98 @@ |
| +package console |
| + |
| +import ( |
| + "bytes" |
| + "errors" |
| + "go/ast" |
| + "go/parser" |
| + "go/token" |
| + "os" |
| + "sort" |
| + "strings" |
| + "testing" |
| + "time" |
| +) |
| + |
| +func TestCreateAccountTxProductionCallerInventory(t *testing.T) { |
| + entries, err := os.ReadDir(".") |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + callers := map[string]bool{} |
| + for _, entry := range entries { |
| + name := entry.Name() |
| + if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { |
| + continue |
| + } |
| + file, err := parser.ParseFile(token.NewFileSet(), name, nil, 0) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + for _, declaration := range file.Decls { |
| + fn, ok := declaration.(*ast.FuncDecl) |
| + if !ok || fn.Body == nil || fn.Name.Name == "createAccountTx" { |
| + continue |
| + } |
| + ast.Inspect(fn.Body, func(node ast.Node) bool { |
| + call, ok := node.(*ast.CallExpr) |
| + if !ok { |
| + return true |
| + } |
| + id, ok := call.Fun.(*ast.Ident) |
| + if ok && id.Name == "createAccountTx" { |
| + callers[name+":"+fn.Name.Name] = true |
| + } |
| + return true |
| + }) |
| + } |
| + } |
| + got := make([]string, 0, len(callers)) |
| + for caller := range callers { |
| + got = append(got, caller) |
| + } |
| + sort.Strings(got) |
| + want := []string{"signuprecords.go:completeSignup", "store.go:CreateAccount"} |
| + if !bytes.Equal([]byte(strings.Join(got, "\n")), []byte(strings.Join(want, "\n"))) { |
| + t.Fatalf("createAccountTx production callers = %v, want %v", got, want) |
| + } |
| +} |
| + |
| +func TestSignupONBirthRequiresCurrentFreshnessAndHistoricalReplayStaysOFF(t *testing.T) { |
| + f := newSignupFixture(t, true) |
| + f.seal(t, true) |
| + f.candidate(t) |
| + f.live(t) |
| + intentBefore := signupTableSnapshot(t, f.s, "signup_intents") |
| + attemptBefore := signupTableSnapshot(t, f.s, "signup_mint_attempts") |
| + if err := f.s.ClearStepUp(f.raw); err != nil { |
| + t.Fatal(err) |
| + } |
| + if _, err := f.complete(true); !errors.Is(err, errOveragePreferenceDenied) { |
| + t.Fatalf("ON birth without current freshness = %v", err) |
| + } |
| + for _, table := range []string{"accounts", "memberships", "overage_preferences", "overage_preference_receipts", "account_birth_receipts"} { |
| + if signupCount(t, f.s, `SELECT count(*) FROM `+table) != 0 { |
| + t.Fatalf("freshness refusal wrote %s", table) |
| + } |
| + } |
| + if got := signupTableSnapshot(t, f.s, "signup_intents"); !bytes.Equal(got, intentBefore) { |
| + t.Fatal("freshness refusal rewrote immutable intent evidence") |
| + } |
| + if got := signupTableSnapshot(t, f.s, "signup_mint_attempts"); !bytes.Equal(got, attemptBefore) { |
| + t.Fatal("freshness refusal rewrote immutable attempt evidence") |
| + } |
| + if err := f.s.RecordStepUp(f.raw, overageOwner, f.now.Add(-time.Second), f.now); err != nil { |
| + t.Fatal(err) |
| + } |
| + birth, err := f.complete(true) |
| + if err != nil || !birth.Preference.RequestedOn { |
| + t.Fatalf("same intended birth after fresh step-up = %+v, %v", birth, err) |
| + } |
| + if _, err := f.s.changeOveragePreference(overageChange(f.a.AccountID, overageOwner, 1, false, 75), f.now.Add(time.Second)); err != nil { |
| + t.Fatal(err) |
| + } |
| + replay, err := f.complete(true) |
| + if err != nil || replay.Preference.RequestedOn || replay.Preference.Revision != 2 { |
| + t.Fatalf("historical ON replay after OFF = %+v, %v", replay, err) |
| + } |
| +} |