113 lines
3.6 KiB
Go
113 lines
3.6 KiB
Go
|
|
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)
|
||
|
|
}
|
||
|
|
}
|