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_probes_worker_test.go is the probe table for the recorded
4// workers that are not doors. A worker answers nothing, so the proof is its
5// work: a bucket object, a SQL row or the line it logs, read from the world
6// after one bounded run. A run that did nothing (no pointer to expire, no
7// alert to send, no box to report on) is not coverage.
8
9import (
10 "context"
11 "encoding/json"
12 "strings"
13 "testing"
14 "time"
15
16 "github.com/carlosframework/platform/internal/economics"
17 "github.com/carlosframework/platform/internal/geoip"
18 "github.com/carlosframework/platform/internal/hostfloor"
19 "github.com/carlosframework/platform/internal/hostops"
20 "github.com/carlosframework/platform/internal/infraview"
21 "github.com/carlosframework/platform/internal/metrics"
22 "github.com/carlosframework/platform/internal/moves"
23 "github.com/carlosframework/platform/internal/plans"
24 "github.com/carlosframework/platform/internal/provision"
25 "github.com/carlosframework/platform/internal/registry"
26 "github.com/carlosframework/platform/internal/release"
27 "github.com/carlosframework/platform/internal/usage"
28)
29
30// claimLogWorkerProbe runs a worker that only logs, and answers the log: the
31// reply's body is what the worker said, so the probe's markers are the lines
32// it must have said about a real finding.
33func claimLogWorkerProbe(name string, setup func(*testing.T, *claimCase), want ...string) claimProbe {
34 return claimProbe{
35 serial: "captures the process-wide log output (captureLogTo): another case's log lines would land in its answer",
36 setup: setup,
37 do: func(t *testing.T, cx *claimCase) claimReply {
38 claimMustRunAlone(t, "log worker probe "+name)
39 var logs strings.Builder
40 restore := captureLogTo(&logs)
41 reply := claimWorkerReply(name)(t, cx)
42 restore()
43 reply.Body = logs.String()
44 return reply
45 },
46 body: want,
47 }
48}
49
50// claimRegionalApp is app blog homed in uk with a no-region instance record
51// created after it: the shape a console rolled below the floor writes, which
52// the placement check lists as a discrepancy candidate.
53func claimRegionalApp(t *testing.T, cx *claimCase) {
54 t.Helper()
55 scope := []claimSQLScope{{AccountID: OpsAccountID, App: "blog", AppID: "claim-bab-blog", Mode: claimModeEffect}}
56 err := cx.st.withClaimSQL(gateCtx(t), scope, allowAllClaimSQL, func(v *Store) error {
57 if _, err := v.CreateAppInRegion(OpsAccountID, "blog", claimFxOwner, "uk", "chosen", time.Now().Add(-time.Hour)); err != nil {
58 return err
59 }
60 return v.BindClaimAppIdentity(OpsAccountID, "blog", "claim-bab-blog")
61 })
62 if err != nil {
63 t.Fatalf("stage the regional app: %v", err)
64 }
65 cx.putAdmission(t, "bab", "blog", hostops.AppAdmission{V: 1, AppID: "claim-bab-blog", Revision: 1, Epoch: 1, State: "open",
66 Registrations: map[string]hostops.Registration{}, Effects: map[string]hostops.Effect{}})
67 rec := provision.Record{Schema: 1, Host: "drift.go.tito.io", App: "blog", Account: release.OpsAccount, Channel: "stable", CreatedAt: time.Now()}
68 if err := provision.CreateRecord(context.Background(), cx.rel, rec); err != nil {
69 t.Fatalf("stage the drifting record: %v", err)
70 }
71}
72
73var claimWorkerProbes = map[string]claimProbe{
74 // ---- reads: they say what they found ----
75 "worker ReportApexSquats": claimLogWorkerProbe("ReportApexSquats", func(t *testing.T, cx *claimCase) {
76 // A route at titogo's platform apex that belongs to another app.
77 cx.addRoute(t, registry.Route{Host: "titogo.bab.oncarlos.com", Kind: "instance", Status: "ready",
78 App: "kass", Account: "bab", Addr: "127.0.0.1:9301"})
79 }, "apex squat", "titogo.bab.oncarlos.com"),
80 "worker StartRunSweep": claimLogWorkerProbe("StartRunSweep", nil, "run sweep", "host-claim console"),
81 "worker StartSeedsPass": claimLogWorkerProbe("StartSeedsPass", nil, "seeds pass", "host-claim console"),
82 "worker LogPlacementDiscrepancies": claimLogWorkerProbe("LogPlacementDiscrepancies", claimRegionalApp,
83 msgPlacementDiscrepancy("drift.go.tito.io", "blog", "uk")),
84
85 // ---- nonApp: they write deployment state ----
86 "worker PublishMovesConsole": {
87 setup: func(t *testing.T, cx *claimCase) { cx.srv.cfg.MovesEnabled = true },
88 do: claimWorkerReply("PublishMovesConsole"),
89 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
90 var rec moves.ConsoleRecord
91 if !cx.bucketJSON(moves.ConsoleKey, &rec) {
92 return "no " + moves.ConsoleKey + " was published"
93 }
94 if rec.V != 1 || rec.Protocol != moves.ProtocolVersion || rec.At.IsZero() {
95 return "the published moves console record is not this console's"
96 }
97 return ""
98 },
99 },
100 "worker StartAlertWatcher": {
101 setup: func(t *testing.T, cx *claimCase) {
102 // One box with a disk alert firing; the owner holds a Keymail grant
103 // (they signed in), so the watcher can mail them and must record it.
104 now := time.Now().UTC()
105 state := metrics.AlertState{V: 1, Box: "box1", UpdatedAt: now,
106 Rules: map[string]metrics.RuleState{"disk": {Firing: true, FiredAt: now, Value: 91}}}
107 body, err := json.Marshal(state)
108 if err != nil {
109 t.Fatal(err)
110 }
111 if _, err := cx.rel.Put(context.Background(), metrics.AlertKey("box1"), body, ""); err != nil {
112 t.Fatal(err)
113 }
114 },
115 do: claimWorkerReply("StartAlertWatcher"),
116 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
117 if cx.sqlCount(t, `SELECT COUNT(*) FROM alert_seen`) == 0 {
118 return "no operator was told about the firing alert (alert_seen is empty)"
119 }
120 return ""
121 },
122 },
123 "worker StartEconomicsPass": {
124 setup: func(t *testing.T, cx *claimCase) {
125 // The bill pull is the one stage that would reach AWS: a seam answers it.
126 cx.srv.ceCosts = func(context.Context, time.Time, time.Time) (map[string]float64, error) {
127 return map[string]float64{"AmazonEC2": 1}, nil
128 }
129 },
130 do: claimWorkerReply("StartEconomicsPass"),
131 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
132 day := usage.DayOf(time.Now())
133 var census usage.CensusDay
134 if !cx.bucketJSON(usage.CensusDayKey(day), &census) || census.Date != day {
135 return "no census day was written for " + day
136 }
137 var bill economics.Bill
138 if !cx.bucketJSON(economics.BillKey(time.Now().UTC().Format("2006-01")), &bill) || bill.TotalUSD != 1 {
139 return "no bill was pulled for the month"
140 }
141 return ""
142 },
143 },
144 "worker StartGeoipJobs": {
145 setup: func(t *testing.T, cx *claimCase) {
146 // A blob no pointer names: the orphan a crashed publish leaves.
147 if _, err := cx.rel.Put(context.Background(), geoip.BlobKey(strings.Repeat("a", 64)), []byte("x"), ""); err != nil {
148 t.Fatal(err)
149 }
150 },
151 do: claimWorkerReply("StartGeoipJobs"),
152 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
153 if cx.bucketHas(geoip.BlobKey(strings.Repeat("a", 64))) {
154 return "the orphan blob survived the sweep"
155 }
156 return ""
157 },
158 },
159 "worker StartHostReports": {
160 serial: "swaps the package variable hostRunningImage",
161 setup: func(t *testing.T, cx *claimCase) {
162 claimMustRunAlone(t, "worker StartHostReports")
163 // The box's guard files are not here; the seam says what this
164 // process is running, as the guard would.
165 prev := hostRunningImage
166 hostRunningImage = func() (hostfloor.Running, error) {
167 return hostfloor.Running{ReleaseTag: "v1.0.0", Hash: claimFxConsoleSHA, Protocol: 1, BootID: "claim-fixture-boot", GuardReady: true}, nil
168 }
169 t.Cleanup(func() { hostRunningImage = prev })
170 },
171 do: claimWorkerReply("StartHostReports"),
172 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
173 var report struct {
174 Actor string `json:"actor"`
175 Component string `json:"component"`
176 }
177 if !cx.bucketJSON("status/consoles/"+claimFxConsole+".json", &report) {
178 return "this console's census report was not written"
179 }
180 if report.Actor != claimFxConsole || report.Component != "console" {
181 return "the census report is not this console's"
182 }
183 return ""
184 },
185 },
186 "worker StartInfraPass": {
187 setup: claimInventorySeam,
188 do: claimWorkerReply("StartInfraPass"),
189 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
190 var inv infraview.Inventory
191 if !cx.bucketJSON(infraview.InventoryKey, &inv) || inv.Provider != "aws" {
192 return "no inventory snapshot was stored"
193 }
194 return ""
195 },
196 },
197 "worker PublishPlansMarker": {
198 setup: func(t *testing.T, cx *claimCase) { cx.srv.cfg.PlanCatalog = examplePlanCatalog(t) },
199 do: claimWorkerReply("PublishPlansMarker"),
200 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
201 var m plans.Marker
202 if !cx.bucketJSON(plans.MarkerKey(), &m) || !m.Enabled {
203 return "no enabled plans marker was published"
204 }
205 return ""
206 },
207 },
208 "worker StartPlanLimitsPass": {
209 setup: func(t *testing.T, cx *claimCase) { cx.srv.cfg.PlanCatalog = examplePlanCatalog(t) },
210 do: claimWorkerReply("StartPlanLimitsPass"),
211 effect: func(t *testing.T, cx *claimCase, r claimReply) string {
212 var rec plans.Record
213 if !cx.bucketJSON(plans.LimitsKey("bab"), &rec) {
214 return "no limits record was published for bab"
215 }
216 if rec.Plan != "free" || rec.Limits.RunningThings != 3 {
217 return "the published limits record is not the default plan's"
218 }
219 return ""
220 },
221 },
222}
223