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
3// claim_invariant_regionha_test.go covers what region HA (CARLOS_REGION_HA,
4// Config.RegionHA) adds to a host-claim console's routes, on a console built
5// with it on: the operator's box and group role doors (region HA spec 2 §7,
6// apiboxroles.go). With region HA off they are not registered, so the base
7// console's census (testdata/claim-routes.txt) is main's (Astra 2a final
8// review, P3). Each is a nonApp entry, probed here on a region-HA console.
9
10import (
11 "context"
12 "net/http"
13 "os"
14 "slices"
15 "strings"
16 "testing"
17
18 "github.com/carlosframework/platform/internal/hostactors"
19 "github.com/carlosframework/platform/internal/release"
20)
21
22// claimRegionHAOn builds the console the way cmd/console builds it with
23// CARLOS_REGION_HA on (the switch is read before NewServer).
24func claimRegionHAOn(c *Config) { c.RegionHA = true }
25
26// claimRegionHAFixtures are the entries that exist only on a region-HA
27// console.
28var claimRegionHAFixtures = map[string]claimFixture{
29 "route POST /api/cli/system/boxes/{box}/role": claimNonApp("operator box role (region HA spec 2 §7): one signed roster write to control/host-actors.json; names no app"),
30 "route POST /api/cli/system/groups/{region}/role": claimNonApp("operator group role (region HA spec 2 §7): one signed roster write to control/host-actors.json, the group and the boxes it enrolled; names no app"),
31}
32
33// claimRegionHAProbes drive the entries above: one signed roster write each.
34var claimRegionHAProbes = map[string]claimProbe{
35 "route POST /api/cli/system/boxes/{box}/role": {
36 do: claimAPIReply(http.MethodPost, "/api/cli/system/boxes/box-ie-default/role", `{"role":"legacy"}`),
37 body: []string{`"role":"legacy"`},
38 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
39 o, err := cx.claimFixtureDirectory().Read(context.Background())
40 if err != nil || o.Roster.Boxes["box-ie-default"].Role != hostactors.RoleLegacy {
41 return "box-ie-default does not have the legacy role in the signed roster"
42 }
43 return ""
44 },
45 },
46 "route POST /api/cli/system/groups/{region}/role": {
47 setup: func(t *testing.T, cx *claimCase) {
48 ctx := context.Background()
49 o, err := cx.claimFixtureDirectory().Read(ctx)
50 if err != nil {
51 t.Fatal(err)
52 }
53 next := hostactors.Clone(o.Roster)
54 g := next.Regions["ie"]
55 g.GroupName, g.GroupARN = "routers", "arn:aws:autoscaling:eu-west-1:123456789012:autoScalingGroup:routers"
56 next.Regions["ie"] = g
57 b := next.Boxes["box-ie-default"]
58 b.Group = "routers"
59 next.Boxes["box-ie-default"] = b
60 next.Revision++
61 raw, err := release.SignRootEnvelope(release.RootSigner(cx.priv), next)
62 if err != nil {
63 t.Fatal(err)
64 }
65 if _, err = cx.rel.Put(ctx, hostactors.Key, raw, o.ETag); err != nil {
66 t.Fatal(err)
67 }
68 },
69 do: claimAPIReply(http.MethodPost, "/api/cli/system/groups/ie/role", `{"role":"legacy"}`),
70 body: []string{`"boxes":["box-ie-default"]`},
71 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
72 o, err := cx.claimFixtureDirectory().Read(context.Background())
73 if err != nil || o.Roster.Regions["ie"].Role != hostactors.RoleLegacy || o.Roster.Boxes["box-ie-default"].Role != hostactors.RoleLegacy {
74 return "the group in ie and its box do not have the legacy role in the signed roster"
75 }
76 return ""
77 },
78 },
79}
80
81// claimRegionHAMerged is the fixture table a region-HA console must match
82// exactly, and claimRegionHAMergedProbes its probe table.
83func claimRegionHAMerged() map[string]claimFixture {
84 merged := map[string]claimFixture{}
85 for k, v := range claimFixtures {
86 merged[k] = v
87 }
88 for k, v := range claimRegionHAFixtures {
89 merged[k] = v
90 }
91 return merged
92}
93
94func claimRegionHAMergedProbes() map[string]claimProbe {
95 merged := map[string]claimProbe{}
96 for k, v := range claimProbes {
97 merged[k] = v
98 }
99 for k, v := range claimRegionHAProbes {
100 merged[k] = v
101 }
102 return merged
103}
104
105// TestClaimRegionHAConsoleRouteCensus: a region-HA console serves exactly
106// what an enabled console serves plus the entries in
107// testdata/claim-routes-region-ha.txt, and every one has a fixture and a
108// probe. The base console registers none of them.
109func TestClaimRegionHAConsoleRouteCensus(t *testing.T) {
110 b, err := os.ReadFile("testdata/claim-routes-region-ha.txt")
111 if err != nil {
112 t.Fatal(err)
113 }
114 extra := strings.Split(strings.TrimSpace(string(b)), "\n")
115 base := claimInventoryKeys(newClaimCase(t).srv.claimEntries.snapshot())
116 for _, k := range extra {
117 if slices.Contains(base, k) {
118 t.Fatalf("%s is registered with region HA off", k)
119 }
120 if _, ok := claimRegionHAFixtures[k]; !ok {
121 t.Errorf("%s has no region HA fixture", k)
122 }
123 }
124 cx := newClaimCaseWith(t, claimRegionHAOn)
125 if !cx.srv.cfg.RegionHA || !cx.srv.cfg.HostClaim {
126 t.Fatal("the region HA console is not built with both switches on")
127 }
128 want := append(slices.Clone(base), extra...)
129 slices.Sort(want)
130 entries := cx.srv.claimEntries.snapshot()
131 got := claimInventoryKeys(entries)
132 if !slices.Equal(got, want) {
133 for _, k := range got {
134 if !slices.Contains(want, k) {
135 t.Errorf("new with region HA: %s", k)
136 }
137 }
138 for _, k := range want {
139 if !slices.Contains(got, k) {
140 t.Errorf("missing with region HA: %s", k)
141 }
142 }
143 t.FailNow()
144 }
145 for _, p := range claimFixtureCensus(entries, claimRegionHAMerged()) {
146 t.Error(p)
147 }
148 for _, p := range claimProbeCensus(claimRegionHAMerged(), claimRegionHAMergedProbes()) {
149 t.Error(p)
150 }
151 for key := range claimRegionHAProbes {
152 if _, ok := claimProbes[key]; ok {
153 t.Errorf("%s is probed on the base console too", key)
154 }
155 }
156}
157
158// TestClaimRegionHAEntriesAreProbed drives every region-HA-only entry's
159// probe on a console built with region HA on.
160func TestClaimRegionHAEntriesAreProbed(t *testing.T) {
161 runClaimProbes(t, claimRegionHAFixtures, claimRegionHAProbes, 0, claimRegionHAOn)
162}
163