carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "context"
5 "encoding/json"
6 "io"
7 "net/http"
8 "net/http/httptest"
9 "strings"
10 "testing"
11)
12
13// instanceCreate carries the config binding when one is asked for, and omits
14// the key entirely when it is not — so a create from a caller that never
15// heard of the flag is byte-identical to what it always sent.
16func TestInstanceCreateSendsEnvironmentOnlyWhenGiven(t *testing.T) {
17 var gotBody string
18 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
19 b, _ := io.ReadAll(r.Body)
20 gotBody = string(b)
21 w.WriteHeader(http.StatusCreated)
22 json.NewEncoder(w).Encode(map[string]any{
23 "host": "canary.example.com", "channel": "canary/x", "environment": "jam-canary",
24 })
25 }))
26 defer ts.Close()
27 s := newTestSession(ts.URL)
28
29 rec, err := s.instanceCreate(context.Background(), apiAcct{Seg: "bah"}, "app",
30 "canary.example.com", "", "canary/x", "", "jam-canary", nil, nil, nil)
31 if err != nil {
32 t.Fatalf("instanceCreate: %v", err)
33 }
34 if !strings.Contains(gotBody, `"environment":"jam-canary"`) {
35 t.Errorf("request body = %s, want it to carry the environment", gotBody)
36 }
37 // The decode matters as much as the send: `canary ls` prints this column,
38 // and the whole point of the column is that a wrong binding is otherwise
39 // invisible — the host serves GETs perfectly either way.
40 if rec.Environment != "jam-canary" {
41 t.Errorf("decoded environment = %q, want jam-canary", rec.Environment)
42 }
43
44 gotBody = ""
45 if _, err := s.instanceCreate(context.Background(), apiAcct{Seg: "bah"}, "app",
46 "plain.example.com", "", "", "", "", nil, nil, nil); err != nil {
47 t.Fatalf("instanceCreate (no environment): %v", err)
48 }
49 if strings.Contains(gotBody, "environment") {
50 t.Errorf("request body = %s, want no environment key when none was given", gotBody)
51 }
52}
53
54// instanceSetEnvironment sends the field ALWAYS, empty string included:
55// clearing a binding — returning a route to the app's default bundle — is a
56// real request, and an omitempty here would silently turn it into a no-op
57// PATCH the door then refuses as "nothing to update".
58func TestInstanceSetEnvironmentSendsAnEmptyValue(t *testing.T) {
59 var gotBody, gotMethod string
60 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
61 gotMethod = r.Method
62 b, _ := io.ReadAll(r.Body)
63 gotBody = string(b)
64 json.NewEncoder(w).Encode(map[string]any{"host": "canary.example.com", "environment": ""})
65 }))
66 defer ts.Close()
67 s := newTestSession(ts.URL)
68
69 rec, err := s.instanceSetEnvironment(context.Background(), apiAcct{Seg: "bah"}, "app",
70 "canary.example.com", "")
71 if err != nil {
72 t.Fatalf("instanceSetEnvironment: %v", err)
73 }
74 if gotMethod != http.MethodPatch {
75 t.Errorf("method = %s, want PATCH — this rides the same door as set-upstreams", gotMethod)
76 }
77 if !strings.Contains(gotBody, `"environment":""`) {
78 t.Errorf("request body = %s, want an explicit empty environment", gotBody)
79 }
80 if rec.Environment != "" {
81 t.Errorf("decoded environment = %q, want empty", rec.Environment)
82 }
83}
84
85// environmentSuffix renders nothing for the default bundle. The empty case is
86// the common one, and printing "environment default" on every create would
87// train people to skim the parenthetical in the case that matters.
88func TestEnvironmentSuffix(t *testing.T) {
89 for _, tc := range []struct{ env, want string }{
90 {"", ""},
91 {" ", ""},
92 {"jam-canary", ", environment jam-canary"},
93 } {
94 if got := environmentSuffix(tc.env); got != tc.want {
95 t.Errorf("environmentSuffix(%q) = %q, want %q", tc.env, got, tc.want)
96 }
97 }
98}
99