-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirstrun_wiring_test.go
More file actions
165 lines (149 loc) · 6.18 KB
/
Copy pathfirstrun_wiring_test.go
File metadata and controls
165 lines (149 loc) · 6.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package main
import (
"context"
"io"
"log/slog"
"os"
"strings"
"testing"
"time"
"github.com/pingular/pingularity/internal/netinfo"
"github.com/pingular/pingularity/internal/settings"
"github.com/pingular/pingularity/internal/speedtest"
"github.com/pingular/pingularity/internal/store"
)
// The production assembly IS the feature: package tests cover injected hooks,
// but deleting `ni.WakeFn = set.Changed` (or miswiring it) would leave every
// package test green while the first speedtest quietly went back to racing an
// empty netinfo. This drives the REAL settings controller's close-and-replace
// broadcast into the REAL netinfo loop, wired exactly as main.go wires them.
func TestFirstRunWiringSettingsBroadcastWakesNetinfo(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
st, err := store.Open(":memory:")
if err != nil {
t.Fatalf("open store: %v", err)
}
defer st.Close()
set, err := settings.New(ctx, st, settings.Values{Monitoring: false, NetinfoEnabled: true})
if err != nil {
t.Fatalf("settings: %v", err)
}
ni := netinfo.NewManager(slog.New(slog.NewTextHandler(io.Discard, nil)))
ni.EnabledFn = func() bool { return set.Monitoring() && set.NetinfoEnabled() }
ni.WakeFn = set.Changed // the production wiring under test (main.go)
loopCtx, loopCancel := context.WithCancel(ctx)
done := make(chan struct{})
defer func() { loopCancel(); <-done }()
go func() { defer close(done); ni.Loop(loopCtx, time.Hour) }()
time.Sleep(150 * time.Millisecond)
if ni.Get().UpdatedAt != 0 {
t.Fatal("lookup attempted while monitoring was off")
}
// The power button. A real mutate -> a real broadcast -> the loop must
// attempt a refresh well inside its one-minute disabled poll.
if err := set.SetMonitoring(ctx, true); err != nil {
t.Fatalf("SetMonitoring: %v", err)
}
deadline := time.Now().Add(15 * time.Second)
for ni.Get().UpdatedAt == 0 {
if time.Now().After(deadline) {
t.Fatal("power-on broadcast never reached the netinfo loop; the ni.WakeFn = set.Changed wiring is dead")
}
time.Sleep(20 * time.Millisecond)
}
}
// newFirstRunReadyFn's truth table, against the real controller and manager -
// this is the composition main.go hands to the scheduler, so a reordered or
// dropped short-circuit here is a 20-second stall (or a defeated wait) on
// every fresh install's first test.
func TestFirstRunReadyFnComposition(t *testing.T) {
ctx := context.Background()
mk := func(v settings.Values) (*settings.Controller, *netinfo.Manager) {
st, err := store.Open(":memory:")
if err != nil {
t.Fatalf("open store: %v", err)
}
t.Cleanup(func() { st.Close() })
set, err := settings.New(ctx, st, v)
if err != nil {
t.Fatalf("settings: %v", err)
}
return set, netinfo.NewManager(slog.New(slog.NewTextHandler(io.Discard, nil)))
}
// Fresh install, netinfo on, nothing published: not ready (the wait is the
// feature - without it the first run races an empty netinfo).
set, ni := mk(settings.Values{NetinfoEnabled: true})
if newFirstRunReadyFn(set, ni)() {
t.Error("fresh install with netinfo pending must NOT be ready")
}
// Pinned server: the race is irrelevant.
set, ni = mk(settings.Values{NetinfoEnabled: true, SpeedServerID: "12345"})
if !newFirstRunReadyFn(set, ni)() {
t.Error("pinned server must be ready immediately")
}
// Connection info off: nothing is ever coming.
set, ni = mk(settings.Values{NetinfoEnabled: false})
if !newFirstRunReadyFn(set, ni)() {
t.Error("netinfo disabled must be ready immediately")
}
// iperf3 engine: ready only when the binary is actually usable - an
// unavailable iperf3 falls back to Ookla, which DOES need the race.
set, ni = mk(settings.Values{NetinfoEnabled: true, SpeedEngine: "iperf3"})
if got, want := newFirstRunReadyFn(set, ni)(), speedtest.IperfAvailable(); got != want {
t.Errorf("iperf3 engine readiness = %v, want %v (IperfAvailable on this host)", got, want)
}
}
// The pending->PUBLISHED half of the readiness truth table. TestFirstRunReadyFnComposition
// only pins the pending (false) side, so a mutation that leaves readiness
// permanently false AFTER netinfo publishes slips past it. This drives a real
// publish (even a failed lookup stamps UpdatedAt) and asserts readiness flips.
func TestFirstRunReadyFnReleasesAfterPublish(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
st, err := store.Open(":memory:")
if err != nil {
t.Fatalf("open store: %v", err)
}
defer st.Close()
set, err := settings.New(ctx, st, settings.Values{Monitoring: true, NetinfoEnabled: true})
if err != nil {
t.Fatalf("settings: %v", err)
}
ni := netinfo.NewManager(slog.New(slog.NewTextHandler(io.Discard, nil)))
ni.EnabledFn = func() bool { return set.Monitoring() && set.NetinfoEnabled() }
ready := newFirstRunReadyFn(set, ni)
if ready() {
t.Fatal("must NOT be ready before netinfo publishes (UpdatedAt still 0)")
}
loopCtx, loopCancel := context.WithCancel(ctx)
done := make(chan struct{})
defer func() { loopCancel(); <-done }()
go func() { defer close(done); ni.Loop(loopCtx, time.Hour) }()
deadline := time.Now().Add(15 * time.Second)
for !ready() {
if time.Now().After(deadline) {
t.Fatalf("readiness never released after netinfo published (UpdatedAt=%d)", ni.Get().UpdatedAt)
}
time.Sleep(20 * time.Millisecond)
}
}
// The wiring lives in main.go's run() assembly, which isn't unit-testable, and
// the tests above re-create it locally - so deleting it from main.go leaves them
// green (the exact gap that shipped). This source-presence guard fails if the
// production wiring is removed or renamed. It is deliberately literal.
func TestMainWiresFirstRunAndOptsHooks(t *testing.T) {
src, err := os.ReadFile("main.go")
if err != nil {
t.Fatal(err)
}
for _, want := range []string{
"ni.WakeFn = set.Changed", // #3: first speedtest must not race an empty netinfo
"sched.ReadyFn = newFirstRunReadyFn(set, ni)", // #3: selection readiness predicate
"replayIgnoredOpts(", // #7: ignored-PINGULARITY_OPTS warning is replayed at boot
} {
if !strings.Contains(string(src), want) {
t.Errorf("main.go no longer wires %q - package tests won't catch it; the behavior is silently dead", want)
}
}
}