| new file mode 100644 |
| index 000000000..3661e1133 |
| --- /dev/null |
| +++ b/internal/mail/walk_grant_test.go |
| @@ -0,0 +1,55 @@ |
| +package mail |
| + |
| +import ( |
| + "context" |
| + "testing" |
| + "time" |
| + |
| + "github.com/carlosframework/platform/internal/release" |
| +) |
| + |
| +// An operator's deliberate cap must survive a tier recompute. Source is |
| +// what distinguishes "this account is on the free tier" from "someone |
| +// decided this account may send more", and a tier pass that flattened the |
| +// second into the first would silently revoke a decision (spec §10). |
| +func TestTierRecomputeDoesNotClobberAnOperatorGrant(t *testing.T) { |
| + ctx, s := context.Background(), release.NewDirStore(t.TempDir()) |
| + now := time.Date(2026, 8, 19, 12, 0, 0, 0, time.UTC) |
| + if _, err := Declare(ctx, s, "bag", "seapointish", "SEAPOINTISH_SMTP", |
| + "n@x.com", "paul@rslw.com", now); err != nil { |
| + t.Fatal(err) |
| + } |
| + if _, err := ApplyGrant(ctx, s, "bag", "seapointish", []string{"x.com"}, 5000, "operator", "paul@rslw.com", now); err != nil { |
| + t.Fatal(err) |
| + } |
| + rec, err := ApplyGrant(ctx, s, "bag", "seapointish", []string{"x.com"}, 50, "tier:free", "tier", now) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if rec.Grant.DailyCap != 5000 || rec.Grant.Source != "operator" { |
| + t.Fatalf("tier recompute clobbered the operator grant: %+v", rec.Grant) |
| + } |
| +} |
| + |
| +// A tier change DOES move a tier-sourced cap — that is the whole point of |
| +// recording the source. |
| +func TestTierRecomputeMovesATierGrant(t *testing.T) { |
| + ctx, s := context.Background(), release.NewDirStore(t.TempDir()) |
| + now := time.Date(2026, 8, 19, 12, 0, 0, 0, time.UTC) |
| + Declare(ctx, s, "bag", "seapointish", "SEAPOINTISH_SMTP", "n@x.com", "paul@rslw.com", now) |
| + ApplyGrant(ctx, s, "bag", "seapointish", []string{"x.com"}, 50, "tier:free", "tier", now) |
| + rec, err := ApplyGrant(ctx, s, "bag", "seapointish", []string{"x.com"}, 1000, "tier:starter", "tier", now) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if rec.Grant.DailyCap != 1000 { |
| + t.Fatalf("DailyCap = %d, want 1000", rec.Grant.DailyCap) |
| + } |
| +} |
| + |
| +func TestGrantRefusesAnUndeclaredApp(t *testing.T) { |
| + ctx, s := context.Background(), release.NewDirStore(t.TempDir()) |
| + if _, err := ApplyGrant(ctx, s, "bag", "seapointish", []string{"x.com"}, 50, "tier:free", "tier", time.Now().UTC()); err != ErrNotDeclared { |
| + t.Fatalf("= %v, want ErrNotDeclared", err) |
| + } |
| +} |