eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3// πŸ€– enterprise_test.go β€” the Enterprise Edition checkout (enterprise.go):
4// the mint path against a fake Stripe, the compiled-in amounts, the Stripe
5// 8-digit cap, the blessed-intern rule, and the CORS scoping that makes a
6// public billing endpoint tolerable.
7
8import (
9 "bytes"
10 "encoding/json"
11 "net/http"
12 "net/http/httptest"
13 "net/url"
14 "strings"
15 "testing"
16 "time"
17)
18
19// enterpriseTestCloud is newTestCloud plus an enterpriseCheckout pointed at
20// the fake Stripe (reused from cloud_billing_test.go β€” same sessions path).
21func enterpriseTestCloud(t *testing.T) (*httptest.Server, *cloudServer, *url.Values) {
22 t.Helper()
23 stripe, captured := fakeStripe(t)
24 srv, s := newTestCloud(t, okControl(t))
25 s.enterprise = newEnterpriseCheckout("sk_test_enterprise", stripe.URL, "https://elevenmessenger.com")
26 return srv, s, captured
27}
28
29func postEnterprise(t *testing.T, srv *httptest.Server, body map[string]any) *http.Response {
30 t.Helper()
31 raw, _ := json.Marshal(body)
32 resp, err := http.Post(srv.URL+"/api/enterprise/checkout", "application/json", bytes.NewReader(raw))
33 if err != nil {
34 t.Fatal(err)
35 }
36 t.Cleanup(func() { resp.Body.Close() })
37 return resp
38}
39
40func TestEnterpriseCheckoutMintsSession(t *testing.T) {
41 srv, _, captured := enterpriseTestCloud(t)
42
43 resp := postEnterprise(t, srv, map[string]any{"seats": 1010, "intern": true, "currency": "eur"})
44 if resp.StatusCode != http.StatusOK {
45 t.Fatalf("status = %d, want 200", resp.StatusCode)
46 }
47 if u, _ := decodeBody(t, resp)["url"].(string); !strings.Contains(u, "checkout.stripe.com") {
48 t.Errorf("url = %q, want the hosted checkout page", u)
49 }
50 if got := resp.Header.Get("Access-Control-Allow-Origin"); got != "https://elevenmessenger.com" {
51 t.Errorf("Access-Control-Allow-Origin = %q", got)
52 }
53
54 // The compiled-in invoice: €979,000 base (after the βˆ’β‚¬121,000 offer),
55 // €11 Γ— 1,010 seats, and the €1 intern β€” €990,111, all in minor units,
56 // under Stripe's 8-digit per-charge cap.
57 f := *captured
58 if f.Get("mode") != "payment" {
59 t.Errorf("mode = %q, want payment", f.Get("mode"))
60 }
61 if f.Get("line_items[0][price_data][unit_amount]") != "97900000" ||
62 f.Get("line_items[1][price_data][unit_amount]") != "1100" ||
63 f.Get("line_items[1][quantity]") != "1010" ||
64 f.Get("line_items[2][price_data][unit_amount]") != "100" {
65 t.Errorf("amounts: %v", f)
66 }
67 for i := 0; i < 3; i++ {
68 if got := f.Get("line_items[" + string(rune('0'+i)) + "][price_data][currency]"); got != "eur" {
69 t.Errorf("line %d currency = %q, want eur", i, got)
70 }
71 }
72 // Redirects are ours, fixed server-side; the client picked nothing.
73 if !strings.HasPrefix(f.Get("success_url"), "https://elevenmessenger.com/enterprise/") ||
74 !strings.HasPrefix(f.Get("cancel_url"), "https://elevenmessenger.com/enterprise/") {
75 t.Errorf("redirects: success=%q cancel=%q", f.Get("success_url"), f.Get("cancel_url"))
76 }
77 for k := range f {
78 if strings.Contains(k, "customer") || strings.Contains(k, "email") {
79 t.Errorf("checkout form leaks a customer field: %s", k)
80 }
81 }
82}
83
84func TestEnterpriseCheckoutWithoutIntern(t *testing.T) {
85 srv, _, captured := enterpriseTestCloud(t)
86 if resp := postEnterprise(t, srv, map[string]any{"seats": 3, "currency": "usd"}); resp.StatusCode != http.StatusOK {
87 t.Fatalf("status = %d, want 200", resp.StatusCode)
88 }
89 f := *captured
90 if f.Get("line_items[1][quantity]") != "3" || f.Get("line_items[1][price_data][currency]") != "usd" {
91 t.Errorf("seat line: %v", f)
92 }
93 if f.Has("line_items[2][price_data][unit_amount]") {
94 t.Errorf("no intern was ordered, but one is on the invoice: %v", f)
95 }
96}
97
98func TestEnterpriseCheckoutValidation(t *testing.T) {
99 srv, _, _ := enterpriseTestCloud(t)
100 cases := []struct {
101 name string
102 body map[string]any
103 code string
104 }{
105 {"bad currency", map[string]any{"seats": 10, "currency": "chf"}, "bad_request"},
106 {"zero seats", map[string]any{"seats": 0, "currency": "eur"}, "bad_request"},
107 {"intern needs 1010", map[string]any{"seats": 11, "intern": true, "currency": "eur"}, "bad_request"},
108 // 1,910 seats pushes the invoice past Stripe's 99,999,999-minor-unit
109 // per-charge maximum; 1,909 (asserted below) is the last legal count.
110 {"over the Stripe cap", map[string]any{"seats": 1910, "currency": "eur"}, "over_stripe_cap"},
111 }
112 for _, tc := range cases {
113 resp := postEnterprise(t, srv, tc.body)
114 if resp.StatusCode != http.StatusBadRequest {
115 t.Errorf("%s: status = %d, want 400", tc.name, resp.StatusCode)
116 continue
117 }
118 if got, _ := decodeBody(t, resp)["error"].(string); got != tc.code {
119 t.Errorf("%s: error = %q, want %q", tc.name, got, tc.code)
120 }
121 }
122 if enterpriseMaxSeats != 1909 {
123 t.Errorf("enterpriseMaxSeats = %d, want 1909 ((99,999,999 βˆ’ 97,900,000) / 1,100)", enterpriseMaxSeats)
124 }
125 if resp := postEnterprise(t, srv, map[string]any{"seats": 1909, "currency": "gbp"}); resp.StatusCode != http.StatusOK {
126 t.Errorf("1,909 seats (the cap) = %d, want 200", resp.StatusCode)
127 }
128}
129
130func TestEnterpriseCheckoutUnconfigured(t *testing.T) {
131 srv, s, _ := enterpriseTestCloud(t)
132 s.enterprise = nil
133 if resp := postEnterprise(t, srv, map[string]any{"seats": 10, "currency": "eur"}); resp.StatusCode != http.StatusNotImplemented {
134 t.Errorf("status = %d, want 501", resp.StatusCode)
135 }
136 // And the empty-key constructor is how "off" happens in production.
137 if newEnterpriseCheckout("", "https://api.stripe.com", "https://elevenmessenger.com") != nil {
138 t.Error("empty key should disable enterprise checkout")
139 }
140}
141
142func TestEnterprisePreflight(t *testing.T) {
143 srv, _, _ := enterpriseTestCloud(t)
144 req, _ := http.NewRequest("OPTIONS", srv.URL+"/api/enterprise/checkout", nil)
145 resp, err := http.DefaultClient.Do(req)
146 if err != nil {
147 t.Fatal(err)
148 }
149 defer resp.Body.Close()
150 if resp.StatusCode != http.StatusNoContent {
151 t.Fatalf("status = %d, want 204", resp.StatusCode)
152 }
153 h := resp.Header
154 if h.Get("Access-Control-Allow-Origin") != "https://elevenmessenger.com" ||
155 !strings.Contains(h.Get("Access-Control-Allow-Methods"), "POST") ||
156 !strings.Contains(strings.ToLower(h.Get("Access-Control-Allow-Headers")), "content-type") {
157 t.Errorf("preflight headers: %v", h)
158 }
159}
160
161func TestEnterpriseMintLimiter(t *testing.T) {
162 l := mintLimiter{max: 2, window: time.Minute}
163 now := time.Now()
164 if !l.allow(now) || !l.allow(now) {
165 t.Fatal("first two mints should pass")
166 }
167 if l.allow(now) {
168 t.Error("third mint inside the window should be refused")
169 }
170 if !l.allow(now.Add(2 * time.Minute)) {
171 t.Error("a fresh window should allow again")
172 }
173}
174