eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3// Tests for meshstats.go: the band thresholds must match
4// deploy/status-publish.sh's pct_band/load_word bit-for-bit (both sides
5// compute the same word for the same box, whichever process does it), the
6// whimsical label algorithm must match status-publish.sh's box_label
7// bit-for-bit too (TestBoxLabelMatchesBash pins a real bash-computed
8// example), and computeBoxStats must derive asleep from awake (never probe
9// them separately, so the two counts can't disagree).
10
11import (
12 "os"
13 "path/filepath"
14 "strconv"
15 "testing"
16 "time"
17)
18
19func TestPctBandThresholds(t *testing.T) {
20 cases := []struct {
21 pct int
22 want int
23 }{
24 {0, 0}, {69, 0}, {70, 1}, {90, 1}, {91, 2}, {100, 2},
25 }
26 for _, c := range cases {
27 if got := pctBand(c.pct); got != c.want {
28 t.Errorf("pctBand(%d) = %d, want %d", c.pct, got, c.want)
29 }
30 }
31}
32
33func TestLoadWord(t *testing.T) {
34 if loadWord(0) != "comfortable" || loadWord(1) != "busy" || loadWord(2) != "critical" {
35 t.Fatal("loadWord vocabulary must match status-publish.sh's load_word exactly")
36 }
37}
38
39func TestMemLoadWord(t *testing.T) {
40 dir := t.TempDir()
41 write := func(total, avail int64) {
42 content := ""
43 if total > 0 {
44 content += "MemTotal: " + strconv.FormatInt(total, 10) + " kB\n"
45 }
46 if avail > 0 {
47 content += "MemAvailable: " + strconv.FormatInt(avail, 10) + " kB\n"
48 }
49 if err := os.WriteFile(filepath.Join(dir, "meminfo"), []byte(content), 0o644); err != nil {
50 t.Fatal(err)
51 }
52 }
53 orig := meminfoPath
54 meminfoPath = filepath.Join(dir, "meminfo")
55 defer func() { meminfoPath = orig }()
56
57 write(1000, 500) // 50% used -> comfortable
58 if w, ok := memLoadWord(); !ok || w != "comfortable" {
59 t.Fatalf("50%% used: got %q, %v", w, ok)
60 }
61 write(1000, 250) // 75% used -> busy
62 if w, ok := memLoadWord(); !ok || w != "busy" {
63 t.Fatalf("75%% used: got %q, %v", w, ok)
64 }
65 write(1000, 50) // 95% used -> critical
66 if w, ok := memLoadWord(); !ok || w != "critical" {
67 t.Fatalf("95%% used: got %q, %v", w, ok)
68 }
69
70 meminfoPath = filepath.Join(dir, "does-not-exist")
71 if _, ok := memLoadWord(); ok {
72 t.Fatal("unreadable meminfo should report ok=false, never guess")
73 }
74}
75
76// Cross-checked against the real bash script: running status-publish.sh's own
77// box_label() function against the same seed input produces the identical
78// "phileas-juggling" — pinning that the two word lists and hash-index math
79// haven't drifted apart.
80func TestBoxLabelMatchesBash(t *testing.T) {
81 dir := t.TempDir()
82 idFile := filepath.Join(dir, "machine-id")
83 if err := os.WriteFile(idFile, []byte("test-machine-id-fixture-12345"), 0o644); err != nil {
84 t.Fatal(err)
85 }
86 orig := machineIDPath
87 machineIDPath = idFile
88 defer func() { machineIDPath = orig }()
89
90 if got, want := boxLabel(), "phileas-juggling"; got != want {
91 t.Fatalf("boxLabel() = %q, want %q (bash's box_label for the same seed)", got, want)
92 }
93}
94
95// computeBoxStats must derive asleep = hibernating total - awake, never
96// probe them independently, and count only actAwake (not a mid-wake/mid-stop
97// transient) as "awake".
98func TestComputeBoxStats(t *testing.T) {
99 reg, err := openRegistry(filepath.Join(t.TempDir(), "registry.db"))
100 if err != nil {
101 t.Fatalf("open registry: %v", err)
102 }
103 for _, h := range []string{"a.11ch.at", "b.11ch.at", "c.11ch.at"} {
104 if err := reg.upsert(Route{Host: h, Kind: "instance", Socket: "/tmp/" + h + ".sock", Hibernate: true}); err != nil {
105 t.Fatal(err)
106 }
107 }
108 // A non-hibernating route must not count toward the hibernating total.
109 if err := reg.upsert(Route{Host: "systemd.11ch.at", Kind: "instance", Socket: "/tmp/x.sock", Hibernate: false}); err != nil {
110 t.Fatal(err)
111 }
112
113 act := newActivator(hibernateConfig{Bucket: "test-bucket"}, &fakeBackend{}, reg)
114 act.entries["a.11ch.at"] = &actEntry{host: "a.11ch.at", state: actAwake}
115 act.entries["b.11ch.at"] = &actEntry{host: "b.11ch.at", state: actWaking} // not yet awake
116
117 stats := computeBoxStats(reg, act, nil)
118 if stats.Label == "" {
119 t.Fatal("Label must be populated")
120 }
121 if stats.Awake == nil || *stats.Awake != 1 {
122 t.Fatalf("Awake = %v, want 1 (only actAwake counts)", stats.Awake)
123 }
124 if stats.Asleep == nil || *stats.Asleep != 2 {
125 t.Fatalf("Asleep = %v, want 2 (3 hibernating - 1 awake)", stats.Asleep)
126 }
127 if stats.Region != "" {
128 t.Fatalf("Region = %q, want empty (LCHAT_BOX_REGION unset)", stats.Region)
129 }
130}
131
132// boxRegion is an explicit-override-only read of LCHAT_BOX_REGION — absent
133// env means empty (never guessed), and computeBoxStats must carry whatever
134// it resolves straight into BoxStats.Region.
135func TestBoxRegionExplicitOverride(t *testing.T) {
136 t.Setenv("LCHAT_BOX_REGION", "")
137 if got := boxRegion(); got != "" {
138 t.Fatalf("boxRegion() = %q, want empty when LCHAT_BOX_REGION is unset", got)
139 }
140
141 t.Setenv("LCHAT_BOX_REGION", "UK · London")
142 if got, want := boxRegion(), "UK · London"; got != want {
143 t.Fatalf("boxRegion() = %q, want %q", got, want)
144 }
145
146 reg, err := openRegistry(filepath.Join(t.TempDir(), "registry.db"))
147 if err != nil {
148 t.Fatalf("open registry: %v", err)
149 }
150 act := newActivator(hibernateConfig{Bucket: "test-bucket"}, &fakeBackend{}, reg)
151 if got := computeBoxStats(reg, act, nil).Region; got != "UK · London" {
152 t.Fatalf("computeBoxStats().Region = %q, want %q", got, "UK · London")
153 }
154}
155
156// Two boxes that both know about the same mesh-replicated routes must never
157// both count the same route as hibernating in their own published snapshot —
158// that's exactly the "same instance reads as asleep on two hosts" confusion
159// the Fleet page must not show. computeBoxStats filters to routes THIS box
160// currently HRW-owns, so each box's own count is a genuine, non-overlapping
161// slice of the fleet: every in-scope route is owned by exactly one live box,
162// and an out-of-scope route (never replicated anywhere else) always counts
163// locally regardless of ownership.
164func TestComputeBoxStatsPartitionsOwnershipAcrossBoxes(t *testing.T) {
165 clk := &fakeClock{t: time.Now()}
166 store := newFakeMeshStore(clk.now)
167 domains := []string{"test"}
168
169 meshA := newMesh("http://box-a", store, domains)
170 meshB := newMesh("http://box-b", store, domains)
171 meshA.now, meshB.now = clk.now, clk.now
172 meshA.beat()
173 meshB.beat()
174 meshA.beat() // refresh A's view so it now also sees B as live
175
176 boxes := []string{meshA.self, meshB.self}
177 var ownedByA, ownedByB []string
178 for i := 0; len(ownedByA) < 2 || len(ownedByB) < 2; i++ {
179 h := "space-" + strconv.Itoa(i) + ".test"
180 switch hrwOwner(h, boxes) {
181 case meshA.self:
182 if len(ownedByA) < 2 {
183 ownedByA = append(ownedByA, h)
184 }
185 case meshB.self:
186 if len(ownedByB) < 2 {
187 ownedByB = append(ownedByB, h)
188 }
189 }
190 }
191
192 regA, err := openRegistry(filepath.Join(t.TempDir(), "a.db"))
193 if err != nil {
194 t.Fatalf("open registry A: %v", err)
195 }
196 regB, err := openRegistry(filepath.Join(t.TempDir(), "b.db"))
197 if err != nil {
198 t.Fatalf("open registry B: %v", err)
199 }
200 // Full replication: both boxes know about all 4 in-scope routes, exactly
201 // like mesh-seed/fanOutMeshRoute leave them today. Plus one out-of-scope
202 // route that only box A ever knew about (never replicated anywhere).
203 for _, reg := range []*Registry{regA, regB} {
204 for _, h := range append(append([]string{}, ownedByA...), ownedByB...) {
205 if err := reg.upsert(Route{Host: h, Kind: "instance", Socket: "/tmp/" + h + ".sock", Hibernate: true}); err != nil {
206 t.Fatal(err)
207 }
208 }
209 }
210 if err := regA.upsert(Route{Host: "local-only.example", Kind: "instance", Socket: "/tmp/local.sock", Hibernate: true}); err != nil {
211 t.Fatal(err)
212 }
213
214 actA := newActivator(hibernateConfig{Bucket: "test-bucket"}, &fakeBackend{}, regA)
215 actB := newActivator(hibernateConfig{Bucket: "test-bucket"}, &fakeBackend{}, regB)
216
217 statsA := computeBoxStats(regA, actA, meshA)
218 statsB := computeBoxStats(regB, actB, meshB)
219
220 // A owns its 2 + the 1 out-of-scope local-only route = 3; B owns its 2.
221 if statsA.Asleep == nil || *statsA.Asleep != 3 {
222 t.Fatalf("box A asleep = %v, want 3 (its 2 owned in-scope + 1 out-of-scope, never B's)", statsA.Asleep)
223 }
224 if statsB.Asleep == nil || *statsB.Asleep != 2 {
225 t.Fatalf("box B asleep = %v, want 2 (only its own 2 owned in-scope routes)", statsB.Asleep)
226 }
227 // The whole point: summed across both boxes' own reports, no route is
228 // ever double-counted, even though both registries physically hold all 4
229 // in-scope rows.
230 if got, want := *statsA.Asleep+*statsB.Asleep, 5; got != want {
231 t.Fatalf("fleet-wide total = %d, want %d (5 unique routes, no double count)", got, want)
232 }
233}
234