Files
descrybe/apps/api/internal/billing/feature_enforcement_test.go
T

130 lines
3.7 KiB
Go
Raw Normal View History

package billing
import (
"errors"
"fmt"
"testing"
)
func TestDefaultPlanFeaturesFreeDeniesAI(t *testing.T) {
m := DefaultPlanFeatures("Free", false)
for _, key := range []string{
"capability.ai_processing",
"catalog.products.process_ai_titles",
"marketing.campaigns.generate_ai",
"settings.api_keys",
"capability.api_access",
"capability.email_live_send",
} {
if m[key] {
t.Fatalf("Free should deny %s", key)
}
}
if !m["catalog.products"] || !m["capability.normalize_specs_fill"] {
t.Fatal("Free should allow catalog + normalize")
}
}
func TestDefaultPlanFeaturesCustomEnableAll(t *testing.T) {
m := DefaultPlanFeatures("Acme Deal", true)
for _, k := range FeatureCatalogKeys {
if !m[k] {
t.Fatalf("custom should enable all; missing %s", k)
}
}
m2 := DefaultPlanFeatures("Enterprise", true)
for _, k := range FeatureCatalogKeys {
if !m2[k] {
t.Fatalf("Enterprise (is_custom) should enable all; missing %s", k)
}
}
}
func TestResolveEffectiveFeaturesGlobalSectionDisableAll(t *testing.T) {
gates := emptyGatesView()
gates.Sections["marketing"] = false
features, sections, disabled := ResolveEffectiveFeatures("Growth", false, nil, gates)
if sections["marketing"] {
t.Fatal("marketing section should be off")
}
if features["marketing.campaigns"] || features["marketing.campaigns.generate_ai"] {
t.Fatal("marketing keys must be false when section disabled")
}
found := false
for _, d := range disabled {
if d == "marketing.campaigns.generate_ai" {
found = true
break
}
}
if !found {
t.Fatal("disabled_features should list marketing.campaigns.generate_ai")
}
if !features["catalog.products"] {
t.Fatal("catalog should remain on")
}
}
func TestResolveEffectiveFeaturesCustomOverrideFalse(t *testing.T) {
gates := emptyGatesView()
overrides := map[string]bool{"settings.api_keys": false}
features, _, _ := ResolveEffectiveFeatures("Client Deal", true, overrides, gates)
if features["settings.api_keys"] {
t.Fatal("override false must win on custom")
}
if !features["capability.ai_processing"] {
t.Fatal("other keys stay on for custom")
}
}
func TestPlanAllowsFeatureCapabilityResolution(t *testing.T) {
if PlanAllowsFeature("Free", false, nil, "capability.ai_processing") {
t.Fatal("Free deny AI capability")
}
if !PlanAllowsFeature("Starter", false, nil, "capability.ai_processing") {
t.Fatal("Starter allow AI capability")
}
if PlanAllowsFeature("Starter", false, nil, "capability.byok") {
t.Fatal("Starter deny BYOK")
}
if !PlanAllowsFeature("Growth", false, nil, "capability.byok") {
t.Fatal("Growth allow BYOK")
}
}
func TestFeatureKeyFromError(t *testing.T) {
err := fmt.Errorf("%w: %s", ErrFeatureDisabled, "marketing.campaigns.generate_ai")
if got := FeatureKeyFromError(err); got != "marketing.campaigns.generate_ai" {
t.Fatalf("got %q", got)
}
if FeatureKeyFromError(errors.New("other")) != "" {
t.Fatal("non-feature error should yield empty")
}
}
func TestFeatureKeysForProcessingType(t *testing.T) {
keys := FeatureKeysForProcessingType("title")
if len(keys) != 2 || keys[0] != "capability.ai_processing" {
t.Fatalf("title keys: %v", keys)
}
keys = FeatureKeysForProcessingType("normalize")
if len(keys) != 1 || keys[0] != "capability.normalize_specs_fill" {
t.Fatalf("normalize keys: %v", keys)
}
}
func TestCloneGatesViewIndependent(t *testing.T) {
src := emptyGatesView()
src.Sections["marketing"] = false
src.Features["capability.ai_processing"] = false
dst := cloneGatesView(src)
dst.Sections["marketing"] = true
dst.Features["capability.ai_processing"] = true
if src.Sections["marketing"] {
t.Fatal("clone must not share sections map")
}
if src.Features["capability.ai_processing"] {
t.Fatal("clone must not share features map")
}
}