Files
beszel-ipv6/agent/battery/battery_linux_test.go

202 lines
5.1 KiB
Go

//go:build testing && linux
package battery
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
// setupFakeSysfs creates a temporary sysfs-like tree under t.TempDir(),
// swaps sysfsPowerSupply, resets the sync.Once caches, and restores
// everything on cleanup. Returns a helper to create battery directories.
func setupFakeSysfs(t *testing.T) (tmpDir string, addBattery func(name, capacity, status string)) {
t.Helper()
tmp := t.TempDir()
resetBatteryState(tmp)
write := func(path, content string) {
t.Helper()
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatal(err)
}
}
addBattery = func(name, capacity, status string) {
t.Helper()
batDir := filepath.Join(tmp, name)
write(filepath.Join(batDir, "type"), "Battery")
write(filepath.Join(batDir, "capacity"), capacity)
write(filepath.Join(batDir, "status"), status)
}
return tmp, addBattery
}
func TestParseSysfsState(t *testing.T) {
tests := []struct {
input string
want uint8
}{
{"Empty", stateEmpty},
{"Full", stateFull},
{"Charging", stateCharging},
{"Discharging", stateDischarging},
{"Not charging", stateIdle},
{"", stateUnknown},
{"SomethingElse", stateUnknown},
}
for _, tt := range tests {
assert.Equal(t, tt.want, parseSysfsState(tt.input), "parseSysfsState(%q)", tt.input)
}
}
func TestGetBatteryStats_SingleBattery(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "72", "Discharging")
pct, state, err := GetBatteryStats()
assert.NoError(t, err)
assert.Equal(t, uint8(72), pct)
assert.Equal(t, stateDischarging, state)
}
func TestGetBatteryStats_MultipleBatteries(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "80", "Charging")
addBattery("BAT1", "40", "Charging")
pct, state, err := GetBatteryStats()
assert.NoError(t, err)
// average of 80 and 40 = 60
assert.EqualValues(t, 60, pct)
assert.Equal(t, stateCharging, state)
}
func TestGetBatteryStats_FullBattery(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "100", "Full")
pct, state, err := GetBatteryStats()
assert.NoError(t, err)
assert.Equal(t, uint8(100), pct)
assert.Equal(t, stateFull, state)
}
func TestGetBatteryStats_EmptyBattery(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "0", "Empty")
pct, state, err := GetBatteryStats()
assert.NoError(t, err)
assert.Equal(t, uint8(0), pct)
assert.Equal(t, stateEmpty, state)
}
func TestGetBatteryStats_NotCharging(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "80", "Not charging")
pct, state, err := GetBatteryStats()
assert.NoError(t, err)
assert.Equal(t, uint8(80), pct)
assert.Equal(t, stateIdle, state)
}
func TestGetBatteryStats_NoBatteries(t *testing.T) {
setupFakeSysfs(t) // empty directory, no batteries
_, _, err := GetBatteryStats()
assert.Error(t, err)
}
func TestGetBatteryStats_NonBatterySupplyIgnored(t *testing.T) {
tmp, addBattery := setupFakeSysfs(t)
// Add a real battery
addBattery("BAT0", "55", "Charging")
// Add an AC adapter (type != Battery) - should be ignored
acDir := filepath.Join(tmp, "AC0")
if err := os.MkdirAll(acDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(acDir, "type"), []byte("Mains"), 0o644); err != nil {
t.Fatal(err)
}
pct, state, err := GetBatteryStats()
assert.NoError(t, err)
assert.Equal(t, uint8(55), pct)
assert.Equal(t, stateCharging, state)
}
func TestGetBatteryStats_InvalidCapacitySkipped(t *testing.T) {
tmp, addBattery := setupFakeSysfs(t)
// One battery with valid capacity
addBattery("BAT0", "90", "Discharging")
// Another with invalid capacity text
badDir := filepath.Join(tmp, "BAT1")
if err := os.MkdirAll(badDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(badDir, "type"), []byte("Battery"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(badDir, "capacity"), []byte("not-a-number"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(badDir, "status"), []byte("Discharging"), 0o644); err != nil {
t.Fatal(err)
}
pct, _, err := GetBatteryStats()
assert.NoError(t, err)
// Only BAT0 counted
assert.Equal(t, uint8(90), pct)
}
func TestGetBatteryStats_UnknownStatusOnly(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "50", "SomethingWeird")
_, _, err := GetBatteryStats()
assert.Error(t, err)
}
func TestHasReadableBattery_True(t *testing.T) {
_, addBattery := setupFakeSysfs(t)
addBattery("BAT0", "50", "Charging")
assert.True(t, HasReadableBattery())
}
func TestHasReadableBattery_False(t *testing.T) {
setupFakeSysfs(t) // no batteries
assert.False(t, HasReadableBattery())
}
func TestHasReadableBattery_NoCapacityFile(t *testing.T) {
tmp, _ := setupFakeSysfs(t)
// Battery dir with type file but no capacity file
batDir := filepath.Join(tmp, "BAT0")
err := os.MkdirAll(batDir, 0o755)
assert.NoError(t, err)
err = os.WriteFile(filepath.Join(batDir, "type"), []byte("Battery"), 0o644)
assert.NoError(t, err)
assert.False(t, HasReadableBattery())
}