carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5 "strings"
6 "testing"
7 "time"
8
9 "github.com/carlosframework/platform/internal/hostclaim"
10 "github.com/carlosframework/platform/internal/lease"
11 "github.com/carlosframework/platform/internal/moves"
12 "github.com/carlosframework/platform/internal/park"
13 "github.com/carlosframework/platform/internal/provision"
14)
15
16// Ruling R-PARK (settings-4 Task 8b): <holder.Location>/build-state.json is
17// live state beside the lease, the generation marker's twin. Every path
18// that lists the holder location passes it over where it passes over the
19// marker; anywhere else it is residue like any other object.
20
21// A landing onto a location that already holds a build state (an earlier
22// stay's) parks the earlier stay's generations, passes the build state over
23// as it passes the marker over, and completes: the install then places the
24// moved state over it.
25func TestALandingOntoALocationHoldingABuildStateCompletes(t *testing.T) {
26 t.Parallel()
27 h := newLandingHarness(t)
28 storeState(h.phase1Harness, "data-ie", cutRoot+"/build-state.json", "v6")
29 h.flip(t)
30 keys := h.residue(t)
31 dst := cutRoot + "/build-state.json"
32 if _, err := h.vs.PutIfAbsent(context.Background(), "data-uk", dst, []byte(p1StateBody("v3"))); err != nil {
33 t.Fatal(err)
34 }
35 for i := 0; i < 4 && h.read(t, p1Host).Move.LandingPhase != provision.LandRestored; i++ {
36 h.land(t)
37 }
38 h.installed(t)
39 if got := h.f.buckets["data-uk"][dst].body; got != p1StateBody("v6") {
40 t.Fatalf("the location holds %q, want the moved v6", got)
41 }
42 for _, k := range keys {
43 if _, ok := h.f.buckets["data-uk"][k]; ok && k != cutRoot+"/generation.json" {
44 t.Fatalf("the earlier stay's %s was not parked", k)
45 }
46 }
47 for k := range h.f.buckets["data-uk"] {
48 if strings.HasPrefix(k, "parked/") && strings.Contains(k, "/build-state.json@") {
49 t.Fatalf("the location's build state was parked: %s", k)
50 }
51 }
52}
53
54// A dirty return whose source location holds the pre-move build state
55// classifies the location, parks the pre-move generations and installs;
56// the returned state is placed over the pre-move one.
57func TestADirtyReturnOverAPreMoveBuildStateClassifies(t *testing.T) {
58 t.Parallel()
59 h := newReturnHarness(t, true)
60 ctx := context.Background()
61 if _, err := h.vs.PutIfAbsent(ctx, "data-ie", cutRoot+"/build-state.json", []byte(p1StateBody("v5"))); err != nil {
62 t.Fatal(err)
63 }
64 key := moves.BuildStateKey(p1Host, p1RB)
65 ver, err := h.vs.PutIfAbsent(ctx, "data-ie", key, []byte(p1StateBody("v8")))
66 if err != nil {
67 t.Fatal(err)
68 }
69 h.seal.State = []moves.SealedObject{{Key: key, VersionID: ver, Size: int64(len(p1StateBody("v8")))}}
70 if err := h.seal.Validate(); err != nil {
71 t.Fatal(err)
72 }
73 pinned := h.read(t, p1Host).Move.Inputs
74 if refused, err := h.install(t); err != nil || refused != "" {
75 t.Fatalf("install: %q %v", refused, err)
76 }
77 h.installedReturn(t, pinned)
78 if got := h.f.buckets["data-ie"][cutRoot+"/build-state.json"].body; got != p1StateBody("v8") {
79 t.Fatalf("the source's location holds %q, want the returned v8", got)
80 }
81}
82
83// TestMovesHolderBuildStateMatchesTheEngine keeps the host's twin key in
84// step with the park engine's, in the spirit of
85// TestMovesParkLockMatchesTheEngine: park.Decide is the oracle. In the
86// authoritative region, with a classifier that places every key (so a
87// skip is the engine's alone), Decide makes no candidate of a one-key
88// census exactly when the host says the key is the holder location's
89// build state. The same file name anywhere else is a candidate.
90func TestMovesHolderBuildStateMatchesTheEngine(t *testing.T) {
91 for name, bare := range map[string]bool{"scoped": false, "bare": true} {
92 t.Run(name, func(t *testing.T) {
93 f := newEvFixture(t)
94 if bare {
95 f.bare(t)
96 }
97 obs := f.observe(t)
98 view := park.View{ClaimETag: obs.ETag, Region: "ie", AuthoritativeRegion: "ie", MarkerKnown: true, MarkerGeneration: evMoveID,
99 Marker: park.Ref{Key: f.location + "/generation.json"},
100 GenerationOf: func(r park.Ref) (string, bool) {
101 if g, ok := landingGenerationOf(f.location, r.Key); ok {
102 return g, true
103 }
104 return "stale", true
105 }}
106 other := strings.Repeat("ab", 32)
107 keys := []string{
108 f.location + "/build-state.json",
109 f.location + "/g-old/build-state.json",
110 f.location + "/build-state.json.old",
111 f.location + "/state/build-state.json",
112 "instances/" + evHost + "/" + other + "/build-state.json",
113 "moves/" + evHost + "/build-state.json",
114 "moves/" + evHost + "/" + evMoveID + "/state/build-state.json",
115 }
116 if bare {
117 keys = append(keys, "instances/"+evHost+"/"+f.inc+"/build-state.json")
118 } else {
119 keys = append(keys, "instances/"+evHost+"/build-state.json")
120 }
121 skipped := 0
122 for _, key := range keys {
123 d, err := park.Decide(obs, view, []lease.ObjectVersion{{Key: key, VersionID: "v1"}, {Key: key, VersionID: "v0"}}, f.inc)
124 if err != nil {
125 t.Fatalf("%s: %v", key, err)
126 }
127 engine, mirror := len(d.Candidates) == 0, movesHolderBuildState(f.location, key)
128 if engine != mirror {
129 t.Errorf("%s: the engine skips it %v, the host's twin key says %v", key, engine, mirror)
130 }
131 if engine {
132 skipped++
133 }
134 }
135 if skipped != 1 {
136 t.Errorf("the engine skipped %d keys, want the holder location's build state alone", skipped)
137 }
138 })
139 }
140}
141
142// The close need not vouch for the live location's build state: it is the
143// location's own, as the marker is. A lane's copy written after the close
144// still has an unknown writer.
145func TestTheLiveLocationsBuildStateNeedsNoVouching(t *testing.T) {
146 for name, bare := range map[string]bool{"scoped": false, "bare": true} {
147 t.Run(name, func(t *testing.T) {
148 f := newEvFixture(t)
149 if bare {
150 f.bare(t)
151 }
152 f.lane(evMoveID, "move.json")
153 f.bucket.Put("data", f.genKey(evMoveID), []byte("live"))
154 f.bucket.Put("data", f.location+"/generation.json", []byte("marker"))
155 f.bucket.Put("data", f.location+"/build-state.json", []byte("older"))
156 f.bucket.Put("data", f.location+"/build-state.json", []byte("current"))
157 if _, _, err := f.provider().VerifyRetirement(t.Context(), f.observe(t), f.census(t)); err != nil {
158 t.Fatalf("VerifyRetirement refused the live build state: %v", err)
159 }
160 })
161 }
162 t.Run("a lane's state written after the close", func(t *testing.T) {
163 f := newEvFixture(t)
164 f.rec.LastMove.At = time.Date(2026, 10, 4, 0, 0, 0, 0, time.UTC) // before every write
165 f.lane("mv_unknown", moves.BuildStateSuffix)
166 bothRefuse(t, f, true)
167 })
168}
169
170// returnBeforeInstall is a rollback harness whose landing stopped at
171// building, before the install placed anything, with the forward seal's
172// state edited by edit.
173func returnBeforeInstall(t *testing.T, edit func(h *rollbackHarness, s *moves.SealedObject)) *rollbackHarness {
174 t.Helper()
175 h := &rollbackHarness{landingHarness: newLandingHarness(t)}
176 h.f.keepHistory = true
177 storeState(h.phase1Harness, "data-ie", cutRoot+"/build-state.json", "v6")
178 h.flip(t)
179 h.landAt = "after-record-" + provision.LandBuilding
180 h.crashLand(t)
181 h.uncover(t)
182 rewriteP1Claim(t, h.s, func(c *hostclaim.Claim) {
183 s, err := journalledSeal(c)
184 if err != nil {
185 t.Fatal(err)
186 }
187 if len(s.State) != 1 {
188 t.Fatalf("seal state %+v", s.State)
189 }
190 edit(h, &s.State[0])
191 c.Op.Journal[hostclaim.JournalSeal] = s.Encode()
192 })
193 h.rollBack(t)
194 h.rollbackPass(t)
195 return h
196}
197
198// Task 8 re-review minor 1: a return before the install reads the forward
199// seal's state only at the move's own lane key, and only at the size the
200// seal names, as copyAsGiven reads every other sealed object.
201func TestAReturnBeforeTheInstallReadsOnlyItsOwnSealedState(t *testing.T) {
202 t.Parallel()
203 refused := func(t *testing.T, h *rollbackHarness) {
204 t.Helper()
205 rb := h.rb(t)
206 if rb.TargetPhase == provision.RbTargetReturned {
207 t.Fatalf("the return sealed: %+v", rb)
208 }
209 if _, ok := h.f.buckets["data-ie"][moves.BuildStateKey(p1Host, rb.ID)]; ok {
210 t.Fatal("a build state went back")
211 }
212 }
213 t.Run("the control returns", func(t *testing.T) {
214 h := returnBeforeInstall(t, func(*rollbackHarness, *moves.SealedObject) {})
215 if rb := h.rb(t); rb.TargetPhase != provision.RbTargetReturned {
216 t.Fatalf("rollback %+v", rb)
217 }
218 })
219 t.Run("another lane's key", func(t *testing.T) {
220 h := returnBeforeInstall(t, func(h *rollbackHarness, s *moves.SealedObject) {
221 key := moves.BuildStateKey(p1Host, "mv_other")
222 body := p1StateBody("v4")
223 ver, err := h.vs.PutIfAbsent(context.Background(), "data-uk", key, []byte(body))
224 if err != nil {
225 t.Fatal(err)
226 }
227 s.Key, s.VersionID, s.Size = key, ver, int64(len(body))
228 })
229 refused(t, h)
230 })
231 t.Run("a size the version is not", func(t *testing.T) {
232 h := returnBeforeInstall(t, func(_ *rollbackHarness, s *moves.SealedObject) { s.Size++ })
233 refused(t, h)
234 })
235}
236
237// Task 8 re-review minor 2: once the landing reached probing a writer may
238// have recorded over the placed state, so the target's location is the
239// source of the returned state even if the landing's journal lost its
240// install step (installManifest rebuilds it then; the build state is not
241// rebuilt).
242func TestAReturnPastProbingTakesTheTargetsStateWithoutTheInstallStep(t *testing.T) {
243 t.Parallel()
244 h := &rollbackHarness{landingHarness: newLandingHarness(t)}
245 storeState(h.phase1Harness, "data-ie", cutRoot+"/build-state.json", "v6")
246 h.flip(t)
247 h.land(t)
248 h.installed(t)
249 h.step(t, provision.LandRestored, provision.LandProbing)
250 h.tpos = h.n
251 storeState(h.phase1Harness, "data-uk", cutRoot+"/build-state.json", "v8")
252 j := h.landJournal(t)
253 j.Unmark(landStepInstall)
254 if err := j.Commit(h.tdir); err != nil {
255 t.Fatal(err)
256 }
257 h.uncover(t)
258 h.rollBack(t)
259 h.rollbackPass(t)
260 rb := h.rb(t)
261 if !rb.Dirty || rb.TargetPhase != provision.RbTargetReturned {
262 t.Fatalf("rollback %+v", rb)
263 }
264 if _, body := returnSealState(t, h, rb.ID); body != p1StateBody("v8") {
265 t.Fatalf("the return lane holds %q, want the target's v8", body)
266 }
267}
268