package postgres import ( "context" "testing" "time" "gl/domain/ledger" ) func TestIgnoreByOperatorRejectsActiveLockedAndTerminalSettlements(t *testing.T) { for _, state := range []struct{ status, lock string }{ {"PENDING", ""}, {"SUBMITTED", ""}, {"CONFIRMED", ""}, {"IGNORED", ""}, {"RETRYABLE", "worker"}, } { tx := &fakeTx{rows: []Row{fakeRow{values: []any{state.status, state.lock}}}} repository := NewSettlementRepository(&fakeDatabase{tx: tx}) if _, err := repository.IgnoreByOperator(context.Background(), "id", "actor", "reviewed"); err == nil { t.Fatalf("dismissed ineligible state: %+v", state) } if tx.execCount != 0 || tx.committed || !tx.rolledBack { t.Fatalf("ineligible dismissal changed state: %+v", tx) } } } func TestIgnoreByOperatorAuditsAndResolvesAtomically(t *testing.T) { tx := &fakeTx{rows: []Row{fakeRow{values: []any{"MANUAL_REVIEW", ""}}}} repository := NewSettlementRepository(&fakeDatabase{tx: tx, directRow: fakeRow{values: []any{ "id", "wallet", "110", "wallet:110:kuknos", ledger.SettlementIgnored, "kuknos", "", 1, time.Now(), "tx_bad_seq", "signed-xdr", }}}) got, err := repository.IgnoreByOperator(context.Background(), "id", "actor", "reviewed") if err != nil || got.Status != ledger.SettlementIgnored || got.LastError != "tx_bad_seq" || !tx.committed || tx.execCount != 3 { t.Fatalf("unexpected dismissal: %+v tx=%+v err=%v", got, tx, err) } for _, failedStep := range []int{2, 3} { tx := &fakeTx{rows: []Row{fakeRow{values: []any{"RETRYABLE", ""}}}, execErrAt: failedStep} repository := NewSettlementRepository(&fakeDatabase{tx: tx}) if _, err := repository.IgnoreByOperator(context.Background(), "id", "actor", "reviewed"); err == nil || tx.committed || !tx.rolledBack { t.Fatalf("audit or issue failure did not roll back: %+v err=%v", tx, err) } } } func TestIgnoredSettlementCannotBeRetried(t *testing.T) { tx := &fakeTx{rows: []Row{fakeRow{values: []any{ledger.SettlementIgnored}}}} repository := NewSettlementRepository(&fakeDatabase{tx: tx}) if _, err := repository.RetryByOperator(context.Background(), "id", "actor", "retry", time.Now()); err == nil || tx.execCount != 0 { t.Fatal("ignored settlement was queued again") } } func TestReconcileConfirmationEvidenceCommitsDurableIssueStats(t *testing.T) { tx := &fakeTx{rows: []Row{ fakeRow{values: []any{int64(1)}}, fakeRow{values: []any{int64(2)}}, }} repository := NewSettlementRepository(&fakeDatabase{tx: tx}) stats, err := repository.ReconcileConfirmationEvidence(context.Background(), 10*time.Minute) if err != nil { t.Fatal(err) } if stats.Detected != 1 || stats.Resolved != 1 || stats.Open != 2 { t.Fatalf("unexpected reconciliation stats: %+v", stats) } if !tx.committed || tx.execCount != 1 { t.Fatalf("unexpected transaction state: %+v", tx) } } func TestReconcileConfirmationEvidenceRollsBackResolutionFailure(t *testing.T) { tx := &fakeTx{ rows: []Row{fakeRow{values: []any{int64(1)}}}, execErrAt: 1, } repository := NewSettlementRepository(&fakeDatabase{tx: tx}) if _, err := repository.ReconcileConfirmationEvidence(context.Background(), time.Minute); err == nil { t.Fatal("expected resolution error") } if !tx.rolledBack || tx.committed { t.Fatalf("failed reconciliation was not rolled back: %+v", tx) } }