package main // 🤖 enterprise_test.go — the Enterprise Edition checkout (enterprise.go): // the mint path against a fake Stripe, the compiled-in amounts, the Stripe // 8-digit cap, the blessed-intern rule, and the CORS scoping that makes a // public billing endpoint tolerable. import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "net/url" "strings" "testing" "time" ) // enterpriseTestCloud is newTestCloud plus an enterpriseCheckout pointed at // the fake Stripe (reused from cloud_billing_test.go — same sessions path). func enterpriseTestCloud(t *testing.T) (*httptest.Server, *cloudServer, *url.Values) { t.Helper() stripe, captured := fakeStripe(t) srv, s := newTestCloud(t, okControl(t)) s.enterprise = newEnterpriseCheckout("sk_test_enterprise", stripe.URL, "https://elevenmessenger.com") return srv, s, captured } func postEnterprise(t *testing.T, srv *httptest.Server, body map[string]any) *http.Response { t.Helper() raw, _ := json.Marshal(body) resp, err := http.Post(srv.URL+"/api/enterprise/checkout", "application/json", bytes.NewReader(raw)) if err != nil { t.Fatal(err) } t.Cleanup(func() { resp.Body.Close() }) return resp } func TestEnterpriseCheckoutMintsSession(t *testing.T) { srv, _, captured := enterpriseTestCloud(t) resp := postEnterprise(t, srv, map[string]any{"seats": 1010, "intern": true, "currency": "eur"}) if resp.StatusCode != http.StatusOK { t.Fatalf("status = %d, want 200", resp.StatusCode) } if u, _ := decodeBody(t, resp)["url"].(string); !strings.Contains(u, "checkout.stripe.com") { t.Errorf("url = %q, want the hosted checkout page", u) } if got := resp.Header.Get("Access-Control-Allow-Origin"); got != "https://elevenmessenger.com" { t.Errorf("Access-Control-Allow-Origin = %q", got) } // The compiled-in invoice: €979,000 base (after the −€121,000 offer), // €11 × 1,010 seats, and the €1 intern — €990,111, all in minor units, // under Stripe's 8-digit per-charge cap. f := *captured if f.Get("mode") != "payment" { t.Errorf("mode = %q, want payment", f.Get("mode")) } if f.Get("line_items[0][price_data][unit_amount]") != "97900000" || f.Get("line_items[1][price_data][unit_amount]") != "1100" || f.Get("line_items[1][quantity]") != "1010" || f.Get("line_items[2][price_data][unit_amount]") != "100" { t.Errorf("amounts: %v", f) } for i := 0; i < 3; i++ { if got := f.Get("line_items[" + string(rune('0'+i)) + "][price_data][currency]"); got != "eur" { t.Errorf("line %d currency = %q, want eur", i, got) } } // Redirects are ours, fixed server-side; the client picked nothing. if !strings.HasPrefix(f.Get("success_url"), "https://elevenmessenger.com/enterprise/") || !strings.HasPrefix(f.Get("cancel_url"), "https://elevenmessenger.com/enterprise/") { t.Errorf("redirects: success=%q cancel=%q", f.Get("success_url"), f.Get("cancel_url")) } for k := range f { if strings.Contains(k, "customer") || strings.Contains(k, "email") { t.Errorf("checkout form leaks a customer field: %s", k) } } } func TestEnterpriseCheckoutWithoutIntern(t *testing.T) { srv, _, captured := enterpriseTestCloud(t) if resp := postEnterprise(t, srv, map[string]any{"seats": 3, "currency": "usd"}); resp.StatusCode != http.StatusOK { t.Fatalf("status = %d, want 200", resp.StatusCode) } f := *captured if f.Get("line_items[1][quantity]") != "3" || f.Get("line_items[1][price_data][currency]") != "usd" { t.Errorf("seat line: %v", f) } if f.Has("line_items[2][price_data][unit_amount]") { t.Errorf("no intern was ordered, but one is on the invoice: %v", f) } } func TestEnterpriseCheckoutValidation(t *testing.T) { srv, _, _ := enterpriseTestCloud(t) cases := []struct { name string body map[string]any code string }{ {"bad currency", map[string]any{"seats": 10, "currency": "chf"}, "bad_request"}, {"zero seats", map[string]any{"seats": 0, "currency": "eur"}, "bad_request"}, {"intern needs 1010", map[string]any{"seats": 11, "intern": true, "currency": "eur"}, "bad_request"}, // 1,910 seats pushes the invoice past Stripe's 99,999,999-minor-unit // per-charge maximum; 1,909 (asserted below) is the last legal count. {"over the Stripe cap", map[string]any{"seats": 1910, "currency": "eur"}, "over_stripe_cap"}, } for _, tc := range cases { resp := postEnterprise(t, srv, tc.body) if resp.StatusCode != http.StatusBadRequest { t.Errorf("%s: status = %d, want 400", tc.name, resp.StatusCode) continue } if got, _ := decodeBody(t, resp)["error"].(string); got != tc.code { t.Errorf("%s: error = %q, want %q", tc.name, got, tc.code) } } if enterpriseMaxSeats != 1909 { t.Errorf("enterpriseMaxSeats = %d, want 1909 ((99,999,999 − 97,900,000) / 1,100)", enterpriseMaxSeats) } if resp := postEnterprise(t, srv, map[string]any{"seats": 1909, "currency": "gbp"}); resp.StatusCode != http.StatusOK { t.Errorf("1,909 seats (the cap) = %d, want 200", resp.StatusCode) } } func TestEnterpriseCheckoutUnconfigured(t *testing.T) { srv, s, _ := enterpriseTestCloud(t) s.enterprise = nil if resp := postEnterprise(t, srv, map[string]any{"seats": 10, "currency": "eur"}); resp.StatusCode != http.StatusNotImplemented { t.Errorf("status = %d, want 501", resp.StatusCode) } // And the empty-key constructor is how "off" happens in production. if newEnterpriseCheckout("", "https://api.stripe.com", "https://elevenmessenger.com") != nil { t.Error("empty key should disable enterprise checkout") } } func TestEnterprisePreflight(t *testing.T) { srv, _, _ := enterpriseTestCloud(t) req, _ := http.NewRequest("OPTIONS", srv.URL+"/api/enterprise/checkout", nil) resp, err := http.DefaultClient.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusNoContent { t.Fatalf("status = %d, want 204", resp.StatusCode) } h := resp.Header if h.Get("Access-Control-Allow-Origin") != "https://elevenmessenger.com" || !strings.Contains(h.Get("Access-Control-Allow-Methods"), "POST") || !strings.Contains(strings.ToLower(h.Get("Access-Control-Allow-Headers")), "content-type") { t.Errorf("preflight headers: %v", h) } } func TestEnterpriseMintLimiter(t *testing.T) { l := mintLimiter{max: 2, window: time.Minute} now := time.Now() if !l.allow(now) || !l.allow(now) { t.Fatal("first two mints should pass") } if l.allow(now) { t.Error("third mint inside the window should be refused") } if !l.allow(now.Add(2 * time.Minute)) { t.Error("a fresh window should allow again") } }