Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions internal/handlers/admin_allowed_tiers_registry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package handlers

// admin_allowed_tiers_registry_test.go — rule-18 drift guard.
//
// adminAllowedTiers (admin_customers.go) is a hand-maintained closed set of
// the tiers an admin may set on a team. The capabilities-contract regression
// (a hardcoded slice that silently dropped hobby_plus for 3h) is the bug class
// this guards: a NEW tier added to plans.yaml must be consciously filed as
// either admin-settable OR explicitly excluded — never silently forgotten.
//
// Per rule 18 the test iterates the LIVE plans registry rather than a
// hand-typed tier list, so adding a tier to plans.yaml reds CI until someone
// makes the decision.

import (
"testing"

"instant.dev/internal/plans"
)

func TestAdminAllowedTiers_StaysInSyncWithPlanRegistry(t *testing.T) {
// Tiers that are deliberately NOT admin-settable, each with the reason.
// Adding a tier here is the conscious "this is not an admin headline tier"
// decision the guard forces.
adminExcluded := map[string]string{
"anonymous": "unclaimed default; not a settable account tier",
"growth": "upsell-only API tier; admin UI exposes headline tiers only",
"hobby_plus": "upsell-only API tier; admin UI exposes headline tiers only",
"hobby_plus_yearly": "yearly variant of an upsell-only tier",
"hobby_yearly": "yearly billing variant; admin sets the monthly headline tier",
"pro_yearly": "yearly billing variant; admin sets the monthly headline tier",
"team_yearly": "yearly billing variant; admin sets the monthly headline tier",
}

all := plans.Default().All()
if len(all) == 0 {
t.Fatal("plans registry is empty — cannot validate adminAllowedTiers drift")
}

for tier := range all {
settable := adminAllowedTiers[tier]
_, excluded := adminExcluded[tier]
switch {
case settable && excluded:
t.Errorf("tier %q is BOTH admin-settable and in the exclude set — contradiction; "+
"remove it from one (admin_customers.go / this test)", tier)
case !settable && !excluded:
t.Errorf("tier %q exists in plans.yaml but is neither in adminAllowedTiers nor the "+
"documented exclude set — file it on one side (rule 18)", tier)
}
}

// Belt: no stale entry in adminAllowedTiers that no longer exists in the
// registry (a removed/renamed tier left behind).
for tier := range adminAllowedTiers {
if _, ok := all[tier]; !ok {
t.Errorf("adminAllowedTiers contains %q which is not present in plans.yaml", tier)
}
}
// Belt: no stale exclude entry either.
for tier := range adminExcluded {
if _, ok := all[tier]; !ok {
t.Errorf("adminExcluded test set contains %q which is not present in plans.yaml — "+
"drop the stale entry", tier)
}
}
}
Loading