package billing import ( "errors" "strings" "testing" ) func TestRecordDueCycleAttempt(t *testing.T) { permanent := errors.New("insert failed") cases := []struct { name string ok bool err error wantProcessed int wantFailed int wantErrSubstr string wantWrapped error }{ { name: "success", ok: true, wantProcessed: 1, }, { name: "skipped claim is neither processed nor failed", ok: false, }, { name: "permanent failure increments failed and wraps", err: permanent, wantFailed: 1, wantErrSubstr: "company_plan 42:", wantWrapped: permanent, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { var res DueBillingCyclesResult gotErr := recordDueCycleAttempt(&res, 42, tc.ok, tc.err) if res.Processed != tc.wantProcessed || res.Failed != tc.wantFailed { t.Fatalf("processed=%d failed=%d want processed=%d failed=%d", res.Processed, res.Failed, tc.wantProcessed, tc.wantFailed) } if tc.wantErrSubstr == "" { if gotErr != nil { t.Fatalf("unexpected err: %v", gotErr) } return } if gotErr == nil { t.Fatal("expected error") } if !strings.Contains(gotErr.Error(), tc.wantErrSubstr) { t.Fatalf("err=%q missing %q", gotErr.Error(), tc.wantErrSubstr) } if tc.wantWrapped != nil && !errors.Is(gotErr, tc.wantWrapped) { t.Fatalf("errors.Is(%v, %v)=false", gotErr, tc.wantWrapped) } }) } } func TestRecordDueCycleAttemptBestEffortAggregation(t *testing.T) { var res DueBillingCyclesResult var errs []error for _, attempt := range []struct { rowID int64 ok bool err error }{ {1, true, nil}, {2, false, errors.New("update failed")}, {3, false, nil}, {4, true, nil}, {5, false, errors.New("commit failed")}, } { if attemptErr := recordDueCycleAttempt(&res, attempt.rowID, attempt.ok, attempt.err); attemptErr != nil { errs = append(errs, attemptErr) } } if res.Processed != 2 || res.Failed != 2 { t.Fatalf("processed=%d failed=%d want 2/2", res.Processed, res.Failed) } joined := errors.Join(errs...) if joined == nil { t.Fatal("expected aggregated error") } msg := joined.Error() for _, want := range []string{"company_plan 2:", "company_plan 5:", "update failed", "commit failed"} { if !strings.Contains(msg, want) { t.Fatalf("aggregated err %q missing %q", msg, want) } } }