carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1// End-to-end acceptance test for `carlos sidecars` (Task 14): the member
2// verbs — enable/create/ls/wake/rm — working through the console API with
3// `carlos auth login` alone, mirroring TestE2EInstancesThroughConsole's
4// shape (instances_e2e_test.go) exactly: a REAL console.Server over a
5// DirStore, a device-flow login landing a real bearer token in a temp
6// credential file, then — with NO store env set — the real run* functions
7// driven in-process. Ground truth is the DirStore's own manifest and
8// record objects, plus the `stdout` seam's confirmation lines.
9package main
10
11import (
12 "context"
13 "net/http"
14 "net/http/httptest"
15 "path/filepath"
16 "strings"
17 "testing"
18 "time"
19
20 "github.com/carlosframework/platform/internal/console"
21 "github.com/carlosframework/platform/internal/provision"
22 "github.com/carlosframework/platform/internal/release"
23)
24
25func TestE2ESidecarsThroughConsole(t *testing.T) {
26 useTempCredentials(t)
27 clearDeploymentEnv(t)
28 checkNoRegistry := requireNoRegistryTouch(t)
29
30 tmp := t.TempDir()
31 relStore := release.NewDirStore(filepath.Join(tmp, "store"))
32 seed, pubB64, err := release.GenerateKey()
33 if err != nil {
34 t.Fatal(err)
35 }
36 priv, err := release.ParseSigningKey(seed, "e2e")
37 if err != nil {
38 t.Fatal(err)
39 }
40 pub, err := release.ParsePublicKey(pubB64, "e2e")
41 if err != nil {
42 t.Fatal(err)
43 }
44 cst, err := console.Open(filepath.Join(tmp, "console.db"))
45 if err != nil {
46 t.Fatal(err)
47 }
48 t.Cleanup(func() { cst.Close() })
49
50 var srv *console.Server
51 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
52 srv.ServeHTTP(w, r)
53 }))
54 t.Cleanup(ts.Close)
55 srv, err = console.NewServer(console.Config{
56 Origin: ts.URL,
57 Keymail: "http://keymail.invalid", // never dialled — see e2eDeviceLogin
58 Registry: filepath.Join(tmp, "registry.db"),
59 Releases: relStore,
60 ReleasePub: pub,
61 Key: priv,
62 AppScheme: "http",
63 AppsDomain: "oncarlos.test",
64 }, cst)
65 if err != nil {
66 t.Fatal(err)
67 }
68
69 const addr = "paul@keymail.dev"
70 if err := cst.AddMember(console.OpsAccountID, addr, console.RoleOwner, time.Now()); err != nil {
71 t.Fatal(err)
72 }
73 if _, err := cst.CreateAppIn(console.OpsAccountID, "titogo", addr, time.Now()); err != nil {
74 t.Fatal(err)
75 }
76
77 token, expiresAt := e2eDeviceLogin(t, ts.URL, cst, addr, "e2e@laptop")
78 credFile, err := loadCredentials()
79 if err != nil {
80 t.Fatal(err)
81 }
82 credFile.put(credential{Console: ts.URL, Address: addr, Token: token, ExpiresAt: expiresAt})
83 if err := credFile.save(); err != nil {
84 t.Fatal(err)
85 }
86
87 // --- enable: member-facing manifest write, no domain/host to pin -------
88 buf := captureStdout(t)
89 runSidecarsEnable([]string{"-app", "titogo", "-account", "ops", "-channel", "beta",
90 "-args", "sidecar run", "-placement", "no-inbound"})
91 if want := "enabled sidecars for titogo"; !strings.Contains(buf.String(), want) {
92 t.Fatalf("enable stdout = %q, want to contain %q", buf.String(), want)
93 }
94 m, err := provision.GetSidecarManifest(context.Background(), relStore, release.OpsAccount, "titogo")
95 if err != nil {
96 t.Fatalf("manifest after enable: %v", err)
97 }
98 if m.Channel != "beta" || m.Placement != "no-inbound" ||
99 len(m.Args) != 2 || m.Args[0] != "sidecar" || m.Args[1] != "run" {
100 t.Fatalf("manifest = %+v, want channel beta, placement no-inbound, args [sidecar run]", m)
101 }
102
103 // --- create: the derived synthetic host, one label under the account's
104 // sqid (release.OpsAccount == "bab" in this harness, instances_e2e_test.go's
105 // own pin) ---------------------------------------------------------------
106 const wantHost = "bot-acme.titogo.bab.sidecar.internal"
107 buf.Reset()
108 runSidecarsCreate([]string{"-app", "titogo", "-account", "ops", "bot-acme"})
109 if want := "created sidecar bot-acme (channel beta)"; !strings.Contains(buf.String(), want) {
110 t.Fatalf("create stdout = %q, want %q", buf.String(), want)
111 }
112 rec, err := provision.GetSidecarRecord(context.Background(), relStore, release.OpsAccount, "titogo", "bot-acme")
113 if err != nil {
114 t.Fatalf("record after create: %v", err)
115 }
116 if rec.Channel != "beta" || rec.Name != "bot-acme" || rec.CreatedBy != addr || rec.Host != wantHost {
117 t.Fatalf("record = %+v, want beta/bot-acme created by %s at host %s", rec, addr, wantHost)
118 }
119
120 // --- ls: short name by default, honest "unknown" version since no box
121 // has ever reported this fresh record ------------------------------------
122 buf.Reset()
123 runSidecarsList([]string{"-app", "titogo", "-account", "ops"})
124 shortOut := buf.String()
125 if !strings.Contains(shortOut, "bot-acme") {
126 t.Fatalf("ls stdout = %q, want the short name bot-acme", shortOut)
127 }
128 if strings.Contains(shortOut, wantHost) {
129 t.Fatalf("ls stdout = %q, must NOT show the synthetic host without -long", shortOut)
130 }
131 if !strings.Contains(shortOut, "unknown") {
132 t.Fatalf("ls stdout = %q, want VERSION unknown — the honesty rule: a stamp that overclaims is worse than an absent one", shortOut)
133 }
134
135 // --- ls -long: the synthetic host, not the short name alone -------------
136 buf.Reset()
137 runSidecarsList([]string{"-app", "titogo", "-account", "ops", "-long"})
138 longOut := buf.String()
139 if !strings.Contains(longOut, wantHost) {
140 t.Fatalf("ls -long stdout = %q, want the synthetic host %q", longOut, wantHost)
141 }
142
143 // --- wake -----------------------------------------------------------
144 buf.Reset()
145 runSidecarsWake([]string{"-app", "titogo", "-account", "ops", "bot-acme"})
146 if want := "requested wake for bot-acme"; !strings.Contains(buf.String(), want) {
147 t.Fatalf("wake stdout = %q, want %q", buf.String(), want)
148 }
149
150 // --- rm: idempotent record retirement ------------------------------
151 buf.Reset()
152 runSidecarsRm([]string{"-app", "titogo", "-account", "ops", "bot-acme"})
153 if want := "deleted sidecar bot-acme"; !strings.Contains(buf.String(), want) {
154 t.Fatalf("rm stdout = %q, want %q", buf.String(), want)
155 }
156 if _, err := provision.GetSidecarRecord(context.Background(), relStore, release.OpsAccount, "titogo", "bot-acme"); err == nil {
157 t.Fatalf("record survived rm")
158 }
159
160 // The whole flow ran through the console: nothing here may have touched
161 // a local registry.
162 checkNoRegistry()
163}
164