major fixes
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/descrybe/descrybe-v2/apps/api/internal/billing"
|
||||
)
|
||||
|
||||
func TestFeatureKeyForAPIPath(t *testing.T) {
|
||||
cases := []struct {
|
||||
path string
|
||||
want string
|
||||
}{
|
||||
{"/api/products", "catalog.products"},
|
||||
{"/api/products/", "catalog.products"},
|
||||
{"/api/products/8f14e45f-ceea-467a-9e0f-000000000000", "catalog.products"},
|
||||
{"/api/api-keys", "settings.api_keys"},
|
||||
{"/api/api-keys/42", "settings.api_keys"},
|
||||
{"/api/marketing/calendar", "marketing.content_calendar"},
|
||||
{"/api/marketing/calendar/prepare", "marketing.content_calendar"},
|
||||
{"/api/integrations/ai/prompts", "integrations.ai"},
|
||||
{"/api/integrations/email/test", "integrations.email"},
|
||||
{"/api/woocommerce/orders", "stores.woocommerce"},
|
||||
{"/api/billing/checkout", "billing.checkout"},
|
||||
// Unmapped paths stay open — the middleware must not guess.
|
||||
{"/api/auth/me", ""},
|
||||
{"/api/billing/credits", ""},
|
||||
{"/api/billing/capabilities", ""},
|
||||
{"/api/unknown-thing", ""},
|
||||
{"/api", ""},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
if got := featureKeyForAPIPath(tc.path); got != tc.want {
|
||||
t.Errorf("featureKeyForAPIPath(%q) = %q, want %q", tc.path, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A prefix must never match a longer sibling path segment: /api/feeds governs
|
||||
// feeds.list, but /api/feeds-something-else is not a feeds route.
|
||||
func TestFeatureKeyForAPIPathDoesNotMatchPartialSegments(t *testing.T) {
|
||||
if got := featureKeyForAPIPath("/api/feedsomething"); got != "" {
|
||||
t.Errorf("got %q, want empty", got)
|
||||
}
|
||||
if got := featureKeyForAPIPath("/api/products-export"); got != "" {
|
||||
t.Errorf("got %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
// Every key the middleware enforces must be one the owner can actually toggle,
|
||||
// otherwise a route could be blocked with no way to unblock it.
|
||||
func TestAPIFeatureRoutesAreGrantable(t *testing.T) {
|
||||
for path, key := range apiFeatureRoutes {
|
||||
if !billing.IsKnownFeatureKey(key) {
|
||||
t.Errorf("%s maps to unknown feature key %q", path, key)
|
||||
continue
|
||||
}
|
||||
if !billing.IsGrantableFeatureKey(key) {
|
||||
t.Errorf("%s maps to %q, which the owner cannot toggle", path, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The capability matrix itself must stay reachable — it is what tells the
|
||||
// dashboard which surfaces to hide.
|
||||
func TestAlwaysReachablePathsAreNotGated(t *testing.T) {
|
||||
for _, path := range alwaysReachableAPIPaths {
|
||||
if got := featureKeyForAPIPath(path); got != "" {
|
||||
t.Errorf("%s resolved to feature %q but must stay open", path, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user