ananke/testing/ups/nut_quality_test.go

113 lines
3.6 KiB
Go
Raw Normal View History

package upsquality
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"scm.bstein.dev/bstein/ananke/internal/ups"
)
// TestNUTProviderReadRejectsEmptyTarget runs one orchestration or CLI step.
// Signature: TestNUTProviderReadRejectsEmptyTarget(t *testing.T).
// Why: validates that provider configuration errors fail fast before shelling out.
func TestNUTProviderReadRejectsEmptyTarget(t *testing.T) {
p := ups.NewNUTProvider("")
_, err := p.Read(context.Background())
if err == nil || !strings.Contains(err.Error(), "must not be empty") {
t.Fatalf("expected empty target validation error, got %v", err)
}
}
// TestNUTProviderReadParsesNominalSample runs one orchestration or CLI step.
// Signature: TestNUTProviderReadParsesNominalSample(t *testing.T).
// Why: covers normal NUT parsing for runtime, charge, load, and nominal power fields.
func TestNUTProviderReadParsesNominalSample(t *testing.T) {
dir := t.TempDir()
upsc := filepath.Join(dir, "upsc")
script := `#!/usr/bin/env sh
cat <<'EOF'
ups.status: OB LB
battery.runtime: 812.0
battery.charge: 72.5
ups.load: 41
ups.realpower.nominal: 900
EOF
`
if err := os.WriteFile(upsc, []byte(script), 0o755); err != nil {
t.Fatalf("write fake upsc: %v", err)
}
t.Setenv("PATH", dir+":"+os.Getenv("PATH"))
p := ups.NewNUTProvider("statera@localhost")
sample, err := p.Read(context.Background())
if err != nil {
t.Fatalf("read sample: %v", err)
}
if !sample.OnBattery || !sample.LowBattery {
t.Fatalf("expected OB+LB status, got %+v", sample)
}
if sample.RuntimeSeconds != 812 || sample.BatteryCharge != 72.5 || sample.LoadPercent != 41 || sample.NominalPowerW != 900 {
t.Fatalf("unexpected parsed values: %+v", sample)
}
}
// TestNUTProviderReadHandlesMissingStatusAndNoisyNumbers runs one orchestration or CLI step.
// Signature: TestNUTProviderReadHandlesMissingStatusAndNoisyNumbers(t *testing.T).
// Why: covers parse failure paths for missing status and non-numeric field content.
func TestNUTProviderReadHandlesMissingStatusAndNoisyNumbers(t *testing.T) {
dir := t.TempDir()
upsc := filepath.Join(dir, "upsc")
// First script invocation: missing ups.status should fail.
missingStatus := `#!/usr/bin/env sh
cat <<'EOF'
battery.runtime: 120
battery.charge: n/a
ups.load: unknown
EOF
`
if err := os.WriteFile(upsc, []byte(missingStatus), 0o755); err != nil {
t.Fatalf("write fake upsc: %v", err)
}
t.Setenv("PATH", dir+":"+os.Getenv("PATH"))
p := ups.NewNUTProvider("pyrphoros@localhost")
if _, err := p.Read(context.Background()); err == nil || !strings.Contains(err.Error(), "ups.status missing") {
t.Fatalf("expected missing status error, got %v", err)
}
// Second script invocation: noisy numbers should parse to zeros where invalid.
noisyNumbers := `#!/usr/bin/env sh
cat <<'EOF'
ups.status: OL
battery.runtime: 61.4
battery.charge: --not-a-number--
ups.load: 34%
ups.realpower.nominal: ###watts###
EOF
`
if err := os.WriteFile(upsc, []byte(noisyNumbers), 0o755); err != nil {
t.Fatalf("rewrite fake upsc: %v", err)
}
sample, err := p.Read(context.Background())
if err != nil {
t.Fatalf("read noisy sample: %v", err)
}
if sample.OnBattery {
t.Fatalf("expected OL to clear OnBattery, got %+v", sample)
}
if sample.RuntimeSeconds != 61 {
t.Fatalf("expected runtime integer parse from decimal, got %d", sample.RuntimeSeconds)
}
if sample.BatteryCharge != 0 {
t.Fatalf("expected invalid charge to parse as 0, got %f", sample.BatteryCharge)
}
if sample.LoadPercent != 34 {
t.Fatalf("expected percentage load parse, got %f", sample.LoadPercent)
}
if sample.NominalPowerW != 0 {
t.Fatalf("expected invalid nominal power to parse as 0, got %f", sample.NominalPowerW)
}
}