carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "context"
5 "encoding/json"
6 "testing"
7)
8
9// Hosting is answered PER BOX, from that box's own hibernation_configured
10// field, and is never inferred from what another box publishes. An earlier
11// version keyed hosting on data_bucket alone, and because an absent
12// data_bucket is what an OLD WRITER and a bucket-less new box both produce,
13// it decided when silence meant "no" by asking whether any OTHER box had
14// spoken. One box adopting a bucket-publishing build then withdrew every
15// region that had not yet rolled, all of them healthy. These tests pin the
16// three states apart.
17func TestPlacementsAnswersHostingPerBox(t *testing.T) {
18 fx, _ := instanceFixture(t, "code-inst-placementcaps")
19 ctx := context.Background()
20 put := func(key, body string) {
21 t.Helper()
22 if _, err := fx.rel.Put(ctx, key, []byte(body), ""); err != nil {
23 t.Fatal(err)
24 }
25 }
26
27 // uk: an old writer — no hibernation_configured, no data_bucket. UNKNOWN,
28 // and unknown keeps the eligibility it had before the field existed.
29 put("control/edges/uk-box.json", `{"v":1,"box":"uk-box","eip":"1.2.3.4","placement":"uk","hosts":{}}`)
30 // ie: a new writer that can host.
31 put("control/edges/ie-box.json", `{"v":1,"box":"ie-box","eip":"5.6.7.8","placement":"ie","data_bucket":"carlos-ie","hibernation_configured":true,"hosts":{}}`)
32 // de: a new writer that CANNOT host, and says so explicitly. This is the
33 // state no earlier version could express.
34 put("control/edges/de-box.json", `{"v":1,"box":"de-box","eip":"9.9.9.9","placement":"de","hibernation_configured":false,"hosts":{}}`)
35 // se: reachable by nothing.
36 put("control/edges/se-box.json", `{"v":1,"box":"se-box","eip":"","placement":"se","data_bucket":"carlos-se","hibernation_configured":true,"hosts":{}}`)
37
38 caps, published := placements(ctx, fx.rel)
39 if !published {
40 t.Fatal("published = false, want true")
41 }
42
43 // The whole point: ie publishing a bucket must not make uk's silence
44 // mean "no". uk stays eligible until uk itself says otherwise.
45 if !caps["uk"].Hosting {
46 t.Error("uk not hosting: it is an OLD WRITER with no opinion, and one box's upgrade must not withdraw another box's region")
47 }
48 if !caps["ie"].Hosting || !caps["ie"].Staging {
49 t.Errorf("ie = %+v, want hosting and staging", caps["ie"])
50 }
51 if caps["de"].Hosting {
52 t.Error("de hosting: it published hibernation_configured false, which is an explicit no")
53 }
54 if !caps["de"].Reachable {
55 t.Error("de unreachable: it has an EIP — a box that cannot host is still an edge")
56 }
57 if caps["se"].Reachable || caps["se"].Hosting || caps["se"].Staging {
58 t.Errorf("se = %+v, want nothing: no EIP gates every capability", caps["se"])
59 }
60
61 // Staging is strictly stronger than Hosting, and uk is where they part:
62 // eligible to host (unknown), but publishing no bucket coordinates, so
63 // no move can name it — internal/host's moveTargets would drop it and
64 // the worker would wait forever.
65 if caps["uk"].Staging {
66 t.Error("uk staging: it publishes no data_bucket, so a move there could never be prepared")
67 }
68}
69
70// An explicit false is believed even when a SIBLING box in the same region
71// can host: the fold is an OR across boxes, so one capable box arms the
72// region, and that is correct — the record only needs one box to land on.
73func TestPlacementsFoldsAcrossBoxesInARegion(t *testing.T) {
74 fx, _ := instanceFixture(t, "code-inst-placementfold")
75 ctx := context.Background()
76 put := func(key, body string) {
77 t.Helper()
78 if _, err := fx.rel.Put(ctx, key, []byte(body), ""); err != nil {
79 t.Fatal(err)
80 }
81 }
82 put("control/edges/uk-a.json", `{"v":1,"box":"uk-a","eip":"1.1.1.1","placement":"uk","hibernation_configured":false,"hosts":{}}`)
83 put("control/edges/uk-b.json", `{"v":1,"box":"uk-b","eip":"2.2.2.2","placement":"uk","data_bucket":"carlos-uk","hibernation_configured":true,"hosts":{}}`)
84
85 caps, _ := placements(ctx, fx.rel)
86 if !caps["uk"].Hosting || !caps["uk"].Staging {
87 t.Errorf("uk = %+v, want hosting and staging: one capable box in the region is enough", caps["uk"])
88 }
89}
90
91// The dormancy that remains is the one the placement field itself shipped
92// with, and it is about placement codes, not about hosting: a fleet where no
93// box publishes a code at all leaves the create gate entirely dormant.
94func TestPlacementsDormantWithoutAnyPlacementCode(t *testing.T) {
95 fx, _ := instanceFixture(t, "code-inst-placementdormant")
96 ctx := context.Background()
97 if _, err := fx.rel.Put(ctx, "control/edges/solo.json",
98 []byte(`{"v":1,"box":"solo","eip":"1.2.3.4","hosts":{}}`), ""); err != nil {
99 t.Fatal(err)
100 }
101 if _, published := placements(ctx, fx.rel); published {
102 t.Error("published = true with no placement code anywhere — the gate must stay dormant")
103 }
104}
105
106// The seeds fields are additive: an edges file from a box that predates
107// them parses, and reads as no protocol, no floor and no verdict.
108func TestEdgesFilePlacementViewSeedsFields(t *testing.T) {
109 var old edgesFilePlacementView
110 if err := json.Unmarshal([]byte(`{"box":"kass-1","moves_protocol":1}`), &old); err != nil {
111 t.Fatal(err)
112 }
113 if old.SeedsProtocol != 0 || old.SeedsFloorMinRelease != "" || old.PrevSeedsAllowedFor != "" {
114 t.Fatalf("old writer = %+v", old)
115 }
116 var cur edgesFilePlacementView
117 body := `{"box":"kass-1","seeds_protocol":2,"seeds_floor_min_release":"v0.27.0","prev_seeds_allowed_for":"v0.27.0"}`
118 if err := json.Unmarshal([]byte(body), &cur); err != nil {
119 t.Fatal(err)
120 }
121 if cur.SeedsProtocol != 2 || cur.SeedsFloorMinRelease != "v0.27.0" || cur.PrevSeedsAllowedFor != "v0.27.0" {
122 t.Fatalf("current writer = %+v", cur)
123 }
124}
125