package daemon import ( "testing" "banger/internal/model" "banger/internal/paths" ) // TestWireServicesInstantiatesStatsService pins that wireServices // leaves d.stats non-nil after construction. A wiring-order bug that // left stats unset would silently break background stats polling and // the vm.stats / vm.health / vm.ping / vm.ports RPC methods — none // of those would nil-deref at cold boot because the daemon might // not get a call for minutes, but the pollStats ticker would // immediately panic on its first fire. func TestWireServicesInstantiatesStatsService(t *testing.T) { d := &Daemon{ runner: &permissiveRunner{}, config: model.DaemonConfig{BridgeIP: model.DefaultBridgeIP}, layout: paths.Layout{ StateDir: t.TempDir(), ConfigDir: t.TempDir(), RuntimeDir: t.TempDir(), VMsDir: t.TempDir(), }, } wireServices(d) if d.stats == nil { t.Fatal("d.stats is nil after wireServices") } // Spot-check the three closures that back every stats method — // a nil closure would be a less-obvious wiring regression than // a nil service. if d.stats.vmAlive == nil { t.Fatal("d.stats.vmAlive closure is nil") } if d.stats.vmHandles == nil { t.Fatal("d.stats.vmHandles closure is nil") } if d.stats.cleanupRuntime == nil { t.Fatal("d.stats.cleanupRuntime closure is nil") } if d.stats.withVMLockByRef == nil { t.Fatal("d.stats.withVMLockByRef closure is nil") } if d.stats.withVMLockByIDErr == nil { t.Fatal("d.stats.withVMLockByIDErr closure is nil") } }