package outbox import ( "context" "path/filepath" "testing" ) // openTemp opens a fresh outbox in a temp dir. func openTemp(t *testing.T) *Store { t.Helper() s, err := Open(filepath.Join(t.TempDir(), "stars.db")) if err != nil { t.Fatalf("open: %v", err) } t.Cleanup(func() { _ = s.Close() }) return s } func TestOutboxAddPendingMark(t *testing.T) { ctx := context.Background() s := openTemp(t) rec := Record{ChargeID: "ch1", OrderID: "ord1", Amount: 40, UserID: 777} if err := s.Add(ctx, rec); err != nil { t.Fatalf("add: %v", err) } pending, err := s.Pending(ctx, 10) if err != nil { t.Fatalf("pending: %v", err) } if len(pending) != 1 || pending[0] != rec { t.Fatalf("pending = %+v, want [%+v]", pending, rec) } if err := s.MarkForwarded(ctx, "ch1"); err != nil { t.Fatalf("mark: %v", err) } pending, err = s.Pending(ctx, 10) if err != nil { t.Fatalf("pending after mark: %v", err) } if len(pending) != 0 { t.Fatalf("pending after mark = %+v, want empty", pending) } } func TestOutboxAddIdempotent(t *testing.T) { ctx := context.Background() s := openTemp(t) rec := Record{ChargeID: "dup", OrderID: "ord1", Amount: 80, UserID: 1} if err := s.Add(ctx, rec); err != nil { t.Fatalf("add 1: %v", err) } // A re-delivered payment (same charge id) must not add a second row, even with different fields. if err := s.Add(ctx, Record{ChargeID: "dup", OrderID: "other", Amount: 999, UserID: 2}); err != nil { t.Fatalf("add 2: %v", err) } pending, err := s.Pending(ctx, 10) if err != nil { t.Fatalf("pending: %v", err) } if len(pending) != 1 || pending[0] != rec { t.Fatalf("pending = %+v, want the single original row", pending) } } func TestOutboxAddIgnoresForwarded(t *testing.T) { ctx := context.Background() s := openTemp(t) rec := Record{ChargeID: "ch", OrderID: "o", Amount: 40, UserID: 5} if err := s.Add(ctx, rec); err != nil { t.Fatalf("add: %v", err) } if err := s.MarkForwarded(ctx, "ch"); err != nil { t.Fatalf("mark: %v", err) } // A re-delivery after forwarding must not resurrect the row as pending (no double credit). if err := s.Add(ctx, rec); err != nil { t.Fatalf("re-add: %v", err) } pending, err := s.Pending(ctx, 10) if err != nil { t.Fatalf("pending: %v", err) } if len(pending) != 0 { t.Fatalf("pending = %+v, want empty (already forwarded)", pending) } } // TestOutboxReopenReDrives proves a restart re-drives undelivered payments: a payment persisted but // not marked forwarded is still pending after the store is reopened from the same file. func TestOutboxReopenReDrives(t *testing.T) { ctx := context.Background() dir := t.TempDir() path := filepath.Join(dir, "stars.db") s, err := Open(path) if err != nil { t.Fatalf("open: %v", err) } rec := Record{ChargeID: "persist", OrderID: "o1", Amount: 40, UserID: 9} if err := s.Add(ctx, rec); err != nil { t.Fatalf("add: %v", err) } if err := s.Close(); err != nil { t.Fatalf("close: %v", err) } reopened, err := Open(path) if err != nil { t.Fatalf("reopen: %v", err) } defer func() { _ = reopened.Close() }() pending, err := reopened.Pending(ctx, 10) if err != nil { t.Fatalf("pending: %v", err) } if len(pending) != 1 || pending[0] != rec { t.Fatalf("pending after reopen = %+v, want the undelivered payment", pending) } }