carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package release
2
3import (
4 "context"
5 "encoding/json"
6 "github.com/carlosframework/platform/internal/registry"
7 "os"
8 "path/filepath"
9 "testing"
10 "time"
11)
12
13func TestPlan14FreshInstallEvidence(t *testing.T) {
14 for _, state := range []string{"fresh", "empty", "observed", "refused", "attempted", "changed", "corrupt", "sync"} {
15 t.Run(state, func(t *testing.T) {
16 h, s, b := rootHistoryFixture(t)
17 if err := os.Remove(filepath.Join(s.dir, historyKey(b))); err != nil {
18 t.Fatal(err)
19 }
20 if state == "empty" {
21 if err := h.RecordInstalledProgram(b, ""); err != nil {
22 t.Fatal(err)
23 }
24 } else {
25 if err := h.RecordCreation(b, "installation"); err != nil {
26 t.Fatal(err)
27 }
28 }
29 switch state {
30 case "observed":
31 if err := h.RecordInstalledProgram(b, ""); err != nil {
32 t.Fatal(err)
33 }
34 case "refused":
35 if err := h.AddRefusal(b, Refusal{Host: b.Host, App: b.App, Version: "v1", RefusedAt: time.Now()}); err != nil {
36 t.Fatal(err)
37 }
38 case "attempted":
39 if err := h.Begin(b, HistoryAttempt{ID: "attempt", Version: "v1", Source: "record", Started: time.Now()}); err != nil {
40 t.Fatal(err)
41 }
42 case "corrupt":
43 if err := os.WriteFile(filepath.Join(s.dir, historyKey(b)), []byte("{"), 0600); err != nil {
44 t.Fatal(err)
45 }
46 case "sync":
47 s.fail = 1
48 }
49 identity := "installation"
50 if state == "changed" {
51 identity = "successor"
52 }
53 fresh, err := h.FreshInstallation(b, identity)
54 if state == "fresh" {
55 if err != nil || !fresh {
56 t.Fatalf("fresh=%v: %v", fresh, err)
57 }
58 } else if err == nil && fresh {
59 t.Fatal("invented fresh installation", state)
60 }
61 })
62 }
63}
64
65func TestPlan14CreationKeepsHistory(t *testing.T) {
66 h, _, b := rootHistoryFixture(t)
67 if err := h.RecordCreation(b, "installation"); err != nil {
68 t.Fatal(err)
69 }
70 p, err := h.Programs(b)
71 if err != nil || len(p) != 1 || p[0] != "old/program" {
72 t.Fatalf("lost history: %v %v", p, err)
73 }
74 if fresh, err := h.FreshInstallation(b, "installation"); err != nil || fresh {
75 t.Fatalf("old history became fresh: %v %v", fresh, err)
76 }
77}
78
79func TestPlan14FreshInstallProgramGate(t *testing.T) {
80 binary := tinyProgram(t, "first/program")
81 for _, mode := range []string{"fresh", "unproven", "changed", "consumed", "missing-provider"} {
82 t.Run(mode, func(t *testing.T) {
83 h, s, b := rootHistoryFixture(t)
84 if err := os.Remove(filepath.Join(s.dir, historyKey(b))); err != nil {
85 t.Fatal(err)
86 }
87 if mode == "unproven" {
88 if err := h.RecordInstalledProgram(b, ""); err != nil {
89 t.Fatal(err)
90 }
91 r, err := h.read(b)
92 if err != nil {
93 t.Fatal(err)
94 }
95 r.Refusals.Complete = true
96 if err = h.write(r); err != nil {
97 t.Fatal(err)
98 }
99 } else if err := h.RecordCreation(b, "installation"); err != nil {
100 t.Fatal(err)
101 }
102 if mode == "consumed" {
103 if err := h.ConsumeCreation(b); err != nil {
104 t.Fatal(err)
105 }
106 }
107 seedRootBake(t, h, b, time.Now().UTC().Add(-time.Hour))
108 st := NewDirStore(t.TempDir())
109 priv, pub := testKeys(t)
110 reg := testRegistry(t)
111 opt := t.TempDir()
112 addRoute(t, reg, b.Host, b.App, "canary/x", false)
113 shipRelease(t, st, b.Account, b.App, "first", adoptPlatform, binary)
114 if err := Promote(t.Context(), st, priv, b.Account, b.App, "canary/x", "first"); err != nil {
115 t.Fatal(err)
116 }
117 calls, effects := 0, 0
118 deps := &RootHistoryPass{History: h, Resolve: func(context.Context, registry.Route) (HistoryBinding, string, error) { return b, "record", nil }, Installed: func(context.Context, registry.Route, string) (string, error) { return "first/program", nil }, Creation: func(context.Context, registry.Route) (string, error) {
119 calls++
120 if mode == "changed" && calls >= 3 {
121 return "successor", nil
122 }
123 return "installation", nil
124 }}
125 if mode == "missing-provider" {
126 deps.Creation = nil
127 }
128 err := Pass(t.Context(), reg, st, pub, opt, func(string) error { effects++; return nil }, WithRootHistory(deps))
129 v, _ := LiveVersion(opt, b.Host)
130 if mode == "fresh" {
131 if err != nil || v != "first" || effects != 1 {
132 t.Fatalf("fresh install: %s %d %v", v, effects, err)
133 }
134 } else if v != "" || effects != 0 {
135 t.Fatalf("%s installed: %s %d %v", mode, v, effects, err)
136 }
137 })
138 }
139}
140
141func TestPlan14FreshInstallVisibleSync(t *testing.T) {
142 h, s, b := rootHistoryFixture(t)
143 if err := os.Remove(filepath.Join(s.dir, historyKey(b))); err != nil {
144 t.Fatal(err)
145 }
146 s.fail = 2
147 if err := h.RecordCreation(b, "installation"); err == nil {
148 t.Fatal("unsynced creation succeeded")
149 }
150 if fresh, err := h.FreshInstallation(b, "installation"); err == nil || fresh {
151 t.Fatal("visible unsynced creation granted")
152 }
153 if fresh, err := h.FreshInstallation(b, "installation"); err != nil || !fresh {
154 t.Fatalf("durability repair: %v %v", fresh, err)
155 }
156 s.fail = 3
157 if err := h.ConsumeCreation(b); err == nil {
158 t.Fatal("unsynced read allowed attempt")
159 }
160 if err := h.ConsumeCreation(b); err == nil {
161 t.Fatal("unsynced read allowed attempt")
162 }
163 if err := h.ConsumeCreation(b); err == nil {
164 t.Fatal("unsynced read allowed attempt")
165 }
166 if err := h.ConsumeCreation(b); err != nil {
167 t.Fatal(err)
168 }
169 if fresh, err := h.FreshInstallation(b, "installation"); err != nil || fresh {
170 t.Fatalf("attempt rearmed: %v %v", fresh, err)
171 }
172}
173
174type creationSyncFailure struct {
175 *healthyRetryStore
176 remaining int
177}
178
179func (s *creationSyncFailure) Write(name string, raw []byte) error {
180 var r historyRecord
181 if err := json.Unmarshal(raw, &r); err != nil {
182 return err
183 }
184 if !r.Fresh && s.remaining > 0 {
185 s.fail = 1
186 s.remaining--
187 }
188 return s.healthyRetryStore.Write(name, raw)
189}
190
191func TestPlan14FreshInstallConsumptionSync(t *testing.T) {
192 h, s, b := rootHistoryFixture(t)
193 if err := os.Remove(filepath.Join(s.dir, historyKey(b))); err != nil {
194 t.Fatal(err)
195 }
196 if err := h.RecordCreation(b, "installation"); err != nil {
197 t.Fatal(err)
198 }
199 h.Store = &creationSyncFailure{healthyRetryStore: s, remaining: 2}
200 if err := h.ConsumeCreation(b); err == nil {
201 t.Fatal("visible unsynced attempt permitted launch")
202 }
203 if fresh, err := h.FreshInstallation(b, "installation"); err == nil || fresh {
204 t.Fatal("unrepaired consumption read succeeded")
205 }
206 if fresh, err := h.FreshInstallation(b, "installation"); err != nil || fresh {
207 t.Fatalf("consumption not recovered: %v %v", fresh, err)
208 }
209 if err := h.RecordCreation(b, "successor"); err != nil {
210 t.Fatal(err)
211 }
212 if fresh, err := h.FreshInstallation(b, "successor"); err != nil || fresh {
213 t.Fatalf("replacement erased retained history: %v %v", fresh, err)
214 }
215}
216