Files
at-container-registry/pkg/hold/billing/config_test.go
T

358 lines
8.5 KiB
Go

//go:build billing
package billing
import (
"os"
"path/filepath"
"testing"
)
func TestParseBillingConfig_Disabled(t *testing.T) {
yaml := []byte(`
billing:
enabled: false
`)
cfg, err := parseBillingConfig(yaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg != nil {
t.Error("expected nil config when billing disabled")
}
}
func TestParseBillingConfig_NoBillingSection(t *testing.T) {
yaml := []byte(`
quota:
tiers:
deckhand:
quota: 5GB
`)
cfg, err := parseBillingConfig(yaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg != nil {
t.Error("expected nil config when no billing section")
}
}
func TestParseBillingConfig_Enabled(t *testing.T) {
yaml := []byte(`
billing:
enabled: true
currency: usd
success_url: "{hold_url}/billing/success"
cancel_url: "{hold_url}/billing/cancel"
plankowner_crew_tier: bosun
tiers:
deckhand:
description: Starter tier
bosun:
description: Standard tier
stripe_price_monthly: price_bosun_monthly
stripe_price_yearly: price_bosun_yearly
`)
cfg, err := parseBillingConfig(yaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg == nil {
t.Fatal("expected non-nil config")
}
if !cfg.Enabled {
t.Error("expected Enabled=true")
}
if cfg.Currency != "usd" {
t.Errorf("expected currency 'usd', got %q", cfg.Currency)
}
if cfg.PlankOwnerCrewTier != "bosun" {
t.Errorf("expected plankowner_crew_tier 'bosun', got %q", cfg.PlankOwnerCrewTier)
}
if cfg.SuccessURL != "{hold_url}/billing/success" {
t.Errorf("unexpected success_url: %q", cfg.SuccessURL)
}
// Check tier pricing
bosun := cfg.GetTierPricing("bosun")
if bosun == nil {
t.Fatal("expected bosun tier pricing")
}
if bosun.StripePriceMonthly != "price_bosun_monthly" {
t.Errorf("expected bosun monthly price 'price_bosun_monthly', got %q", bosun.StripePriceMonthly)
}
if bosun.StripePriceYearly != "price_bosun_yearly" {
t.Errorf("expected bosun yearly price 'price_bosun_yearly', got %q", bosun.StripePriceYearly)
}
if bosun.Description != "Standard tier" {
t.Errorf("expected bosun description 'Standard tier', got %q", bosun.Description)
}
// Deckhand has no prices
deckhand := cfg.GetTierPricing("deckhand")
if deckhand == nil {
t.Fatal("expected deckhand tier pricing entry")
}
if deckhand.StripePriceMonthly != "" {
t.Error("expected no monthly price for deckhand")
}
}
func TestParseBillingConfig_EnabledButNoPrices(t *testing.T) {
yaml := []byte(`
billing:
enabled: true
currency: usd
`)
cfg, err := parseBillingConfig(yaml)
if err == nil {
t.Error("expected error when billing enabled but no prices configured")
}
if cfg != nil {
t.Error("expected nil config on error")
}
}
func TestGetTierByPriceID(t *testing.T) {
cfg := &BillingConfig{
Tiers: map[string]BillingTierConfig{
"deckhand": {},
"bosun": {StripePriceMonthly: "price_m", StripePriceYearly: "price_y"},
},
}
if got := cfg.GetTierByPriceID("price_m"); got != "bosun" {
t.Errorf("expected 'bosun' for monthly price, got %q", got)
}
if got := cfg.GetTierByPriceID("price_y"); got != "bosun" {
t.Errorf("expected 'bosun' for yearly price, got %q", got)
}
if got := cfg.GetTierByPriceID("price_unknown"); got != "" {
t.Errorf("expected empty for unknown price, got %q", got)
}
if got := cfg.GetTierByPriceID(""); got != "" {
t.Errorf("expected empty for empty price, got %q", got)
}
// nil receiver
var nilCfg *BillingConfig
if got := nilCfg.GetTierByPriceID("price_m"); got != "" {
t.Errorf("expected empty from nil config, got %q", got)
}
}
func TestGetTierPricing_NilConfig(t *testing.T) {
var cfg *BillingConfig
if cfg.GetTierPricing("anything") != nil {
t.Error("expected nil from nil config")
}
}
func TestLoadBillingConfig_MissingFile(t *testing.T) {
cfg, err := LoadBillingConfig("/nonexistent/config.yaml")
if err != nil {
t.Fatalf("expected no error for missing file, got: %v", err)
}
if cfg != nil {
t.Error("expected nil config for missing file")
}
}
func TestLoadBillingConfig_EmptyPath(t *testing.T) {
cfg, err := LoadBillingConfig("")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg != nil {
t.Error("expected nil config for empty path")
}
}
func TestLoadBillingConfig_FromFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "config.yaml")
content := `
billing:
enabled: true
currency: usd
tiers:
bosun:
stripe_price_monthly: price_test
`
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
t.Fatal(err)
}
cfg, err := LoadBillingConfig(path)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg == nil {
t.Fatal("expected non-nil config")
}
if cfg.GetTierByPriceID("price_test") != "bosun" {
t.Error("expected bosun tier for price_test")
}
}
func TestParseBillingConfig_TopLevelTiers(t *testing.T) {
yaml := []byte(`
billing:
enabled: true
currency: usd
tiers:
deckhand:
description: "Starter tier"
bosun:
description: "Standard tier"
stripe_price_monthly: price_bosun_m
stripe_price_yearly: price_bosun_y
quartermaster:
description: "Pro tier"
stripe_price_monthly: price_qm_m
`)
cfg, err := parseBillingConfig(yaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg == nil {
t.Fatal("expected non-nil config")
}
if len(cfg.Tiers) != 3 {
t.Errorf("expected 3 tiers, got %d", len(cfg.Tiers))
}
bosun := cfg.GetTierPricing("bosun")
if bosun == nil {
t.Fatal("expected bosun tier")
}
if bosun.Description != "Standard tier" {
t.Errorf("expected description 'Standard tier', got %q", bosun.Description)
}
if bosun.StripePriceMonthly != "price_bosun_m" {
t.Errorf("expected monthly price 'price_bosun_m', got %q", bosun.StripePriceMonthly)
}
if bosun.StripePriceYearly != "price_bosun_y" {
t.Errorf("expected yearly price 'price_bosun_y', got %q", bosun.StripePriceYearly)
}
qm := cfg.GetTierPricing("quartermaster")
if qm == nil {
t.Fatal("expected quartermaster tier")
}
if qm.StripePriceMonthly != "price_qm_m" {
t.Errorf("expected monthly price 'price_qm_m', got %q", qm.StripePriceMonthly)
}
deckhand := cfg.GetTierPricing("deckhand")
if deckhand == nil {
t.Fatal("expected deckhand tier")
}
if deckhand.Description != "Starter tier" {
t.Errorf("expected description 'Starter tier', got %q", deckhand.Description)
}
if deckhand.StripePriceMonthly != "" {
t.Error("expected no monthly price for deckhand")
}
}
func TestParseBillingConfig_PlankOwnerCrewTier(t *testing.T) {
yaml := []byte(`
billing:
enabled: true
currency: usd
plankowner_crew_tier: bosun
tiers:
bosun:
stripe_price_monthly: price_bosun_m
`)
cfg, err := parseBillingConfig(yaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg == nil {
t.Fatal("expected non-nil config")
}
if cfg.PlankOwnerCrewTier != "bosun" {
t.Errorf("expected plankowner_crew_tier 'bosun', got %q", cfg.PlankOwnerCrewTier)
}
}
func TestParseBillingConfig_IgnoresQuotaSection(t *testing.T) {
// Billing parser should work even if quota section is missing entirely
yaml := []byte(`
billing:
enabled: true
currency: usd
tiers:
bosun:
stripe_price_monthly: price_bosun_m
`)
cfg, err := parseBillingConfig(yaml)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg == nil {
t.Fatal("expected non-nil config")
}
// Also works with quota present but unrelated
yaml2 := []byte(`
quota:
tiers:
swabbie:
quota: 1GB
billing:
enabled: true
currency: usd
tiers:
bosun:
stripe_price_monthly: price_bosun_m
`)
cfg2, err := parseBillingConfig(yaml2)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg2 == nil {
t.Fatal("expected non-nil config")
}
// Billing should only see its own tiers, not quota tiers
if cfg2.GetTierPricing("swabbie") != nil {
t.Error("billing should not contain quota-only tiers")
}
}
func TestParseBillingConfig_EmptyTiers(t *testing.T) {
// Billing enabled with explicit empty tiers
yaml := []byte(`
billing:
enabled: true
currency: usd
tiers: {}
`)
cfg, err := parseBillingConfig(yaml)
if err == nil {
t.Error("expected error when billing enabled with empty tiers")
}
if cfg != nil {
t.Error("expected nil config on error")
}
// Billing enabled with tiers omitted entirely
yaml2 := []byte(`
billing:
enabled: true
currency: usd
`)
cfg2, err := parseBillingConfig(yaml2)
if err == nil {
t.Error("expected error when billing enabled with no tiers")
}
if cfg2 != nil {
t.Error("expected nil config on error")
}
}