package monitor_test import ( "context" "sync" "testing" "time" "git.eeqj.de/sneak/rtnetmon/internal/monitor" "git.eeqj.de/sneak/rtnetmon/internal/starlink" ) // fakeDish is a Starlink client for tests: no dish, no network. It records // how often each method is called and returns programmed results. type fakeDish struct { mu sync.Mutex probeOK bool status starlink.Status statusErr error probeCalls int statusCalls int } func (f *fakeDish) Probe(_ context.Context) bool { f.mu.Lock() defer f.mu.Unlock() f.probeCalls++ return f.probeOK } func (f *fakeDish) Status(_ context.Context) (starlink.Status, error) { f.mu.Lock() defer f.mu.Unlock() f.statusCalls++ return f.status, f.statusErr } func (f *fakeDish) counts() (int, int) { f.mu.Lock() defer f.mu.Unlock() return f.probeCalls, f.statusCalls } func newTwoPaneMonitor() *monitor.Monitor { return monitor.NewMonitor([]monitor.IfaceSpec{ {Name: ifaceTest0, Label: "A"}, {Name: ifaceTest1, Label: "B"}, }, "") } func TestEnableStarlinkSelectsPane(t *testing.T) { t.Parallel() mon := newTwoPaneMonitor() mon.EnableStarlink(ifaceTest1) if !mon.StarlinkEnabled() { t.Fatal("StarlinkEnabled = false, want true") } if got := mon.StarlinkPaneName(); got != ifaceTest1 { t.Errorf("StarlinkPaneName = %q, want %q", got, ifaceTest1) } } func TestEnableStarlinkUnknownInterface(t *testing.T) { t.Parallel() mon := newTwoPaneMonitor() mon.EnableStarlink("does-not-exist") if mon.StarlinkEnabled() { t.Error("StarlinkEnabled = true for an unknown interface, want false") } } // TestStarlinkNoDishNoStatus verifies that when no dish answers, no status // is ever fetched and nothing is marked detected. func TestStarlinkNoDishNoStatus(t *testing.T) { t.Parallel() mon := newTwoPaneMonitor() fake := &fakeDish{probeOK: false} mon.SetStarlinkClient(ifaceTest1, fake) ctx := context.Background() mon.StarlinkProbeStep(ctx) mon.StarlinkRefreshStep(ctx) detected, haveStatus, _ := mon.StarlinkSnapshot() if detected || haveStatus { t.Errorf("detected=%v haveStatus=%v, want both false", detected, haveStatus) } if _, status := fake.counts(); status != 0 { t.Errorf("status calls = %d, want 0 (no probing noise)", status) } } // TestStarlinkDetectedFetchesStatus verifies that once a dish answers, // detection triggers a status fetch and later refreshes fetch again. func TestStarlinkDetectedFetchesStatus(t *testing.T) { t.Parallel() mon := newTwoPaneMonitor() want := starlink.Status{ State: "CONNECTED", Uptime: 2 * time.Hour, DownlinkMbps: 100, } fake := &fakeDish{probeOK: true, status: want} mon.SetStarlinkClient(ifaceTest1, fake) ctx := context.Background() mon.StarlinkProbeStep(ctx) detected, haveStatus, got := mon.StarlinkSnapshot() if !detected || !haveStatus { t.Fatalf("detected=%v haveStatus=%v, want both true", detected, haveStatus) } if got != want { t.Errorf("status = %+v, want %+v", got, want) } mon.StarlinkRefreshStep(ctx) probe, status := fake.counts() if probe != 1 { t.Errorf("probe calls = %d, want 1", probe) } if status != 2 { t.Errorf("status calls = %d, want 2", status) } }