//go:build testing package agent import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // writeFile creates path with parents and writes contents. func writeFile(t *testing.T, path, contents string) { t.Helper() require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755)) require.NoError(t, os.WriteFile(path, []byte(contents), 0o644)) } // TestReadHwmonFans verifies the /sys/class/hwmon walker: // - picks up fan*_input from every chip, // - keys entries by chip name + sensor label (or fan idx if no label), // - retains 0 RPM for stopped fans, // - tolerates chips with no fan files at all. func TestReadHwmonFans(t *testing.T) { root := t.TempDir() // hwmon0: Raspberry Pi 5 active cooler — one fan, no label. writeFile(t, filepath.Join(root, "hwmon0", "name"), "pwmfan\n") writeFile(t, filepath.Join(root, "hwmon0", "fan1_input"), "6500\n") // hwmon1: a thermal-only chip, no fan files. Must not error. writeFile(t, filepath.Join(root, "hwmon1", "name"), "cpu_thermal\n") writeFile(t, filepath.Join(root, "hwmon1", "temp1_input"), "55000\n") // hwmon2: two fans — one stopped (0 RPM) and one labeled "chassis". writeFile(t, filepath.Join(root, "hwmon2", "name"), "nct6798\n") writeFile(t, filepath.Join(root, "hwmon2", "fan1_input"), "0\n") writeFile(t, filepath.Join(root, "hwmon2", "fan2_input"), "1200\n") writeFile(t, filepath.Join(root, "hwmon2", "fan2_label"), "chassis\n") fans, err := readHwmonFans(root) require.NoError(t, err) assert.Equal(t, map[string]uint16{ "pwmfan_fan1": 6500, "nct6798_fan1": 0, "nct6798_chassis": 1200, }, fans) } // TestReadHwmonFansMissingRoot returns an error rather than panicking when the // hwmon root doesn't exist (e.g. running on a kernel without hwmon support). func TestReadHwmonFansMissingRoot(t *testing.T) { _, err := readHwmonFans(filepath.Join(t.TempDir(), "does-not-exist")) assert.Error(t, err) } // TestReadHwmonFansEmpty returns an empty map (not nil error) when the root // exists but contains no chips at all. func TestReadHwmonFansEmpty(t *testing.T) { root := t.TempDir() fans, err := readHwmonFans(root) require.NoError(t, err) assert.Empty(t, fans) } func TestFanDiscoveryCache(t *testing.T) { root := t.TempDir() input := filepath.Join(root, "hwmon0", "fan1_input") writeFile(t, filepath.Join(root, "hwmon0", "name"), "chip\n") writeFile(t, input, "1000\n") getSensors := newFanSensorCache(root) sensors, err := getSensors() require.NoError(t, err) fans := readFanSensors(sensors) assert.Equal(t, uint16(1000), fans["chip_fan1"]) writeFile(t, input, "1200\n") writeFile(t, filepath.Join(root, "hwmon0", "fan1_label"), "case\n") sensors, err = getSensors() require.NoError(t, err) fans = readFanSensors(sensors) assert.Equal(t, map[string]uint16{"chip_fan1": 1200}, fans) }