apcupsd_exporter/upscollector_test.go
Rolf Schäuble 290f3ea806 New metrics: XOnBattery, XOffBattery, LastSelfTest, NominalPower (#2)
* Produce metrics for XOnBattery, XOffBattery and LastSelftest.

* Produce metrics for nominal output power.

* Fix cosmetic issues: order of imports and dots at end of sentences.
2017-04-14 13:48:42 -04:00

134 lines
4.1 KiB
Go

package apcupsdexporter
import (
"regexp"
"strings"
"testing"
"time"
"github.com/mdlayher/apcupsd"
)
func TestUPSCollector(t *testing.T) {
var tests = []struct {
desc string
ss *testStatusSource
matches []*regexp.Regexp
}{
{
desc: "empty",
ss: &testStatusSource{
s: &apcupsd.Status{},
},
matches: []*regexp.Regexp{
regexp.MustCompile(`apcupsd_battery_charge_percent{hostname="",model="",ups_name=""} 0`),
},
},
{
desc: "full",
ss: &testStatusSource{
s: &apcupsd.Status{
Hostname: "a",
Model: "b",
UPSName: "c",
BatteryChargePercent: 100.0,
CumulativeTimeOnBattery: 30 * time.Second,
NominalBatteryVoltage: 12.0,
TimeLeft: 2 * time.Minute,
TimeOnBattery: 10 * time.Second,
BatteryVoltage: 13.2,
NominalInputVoltage: 120.0,
LineVoltage: 121.1,
LoadPercent: 16.0,
NumberTransfers: 1,
XOnBattery: time.Unix(100001, 0),
XOffBattery: time.Unix(100002, 0),
LastSelftest: time.Unix(100003, 0),
NominalPower: 50.0,
},
},
matches: []*regexp.Regexp{
regexp.MustCompile(`apcupsd_battery_charge_percent{hostname="a",model="b",ups_name="c"} 100`),
regexp.MustCompile(`apcupsd_battery_cumulative_time_on_seconds_total{hostname="a",model="b",ups_name="c"} 30`),
regexp.MustCompile(`apcupsd_battery_nominal_volts{hostname="a",model="b",ups_name="c"} 12`),
regexp.MustCompile(`apcupsd_battery_time_left_seconds{hostname="a",model="b",ups_name="c"} 120`),
regexp.MustCompile(`apcupsd_battery_time_on_seconds{hostname="a",model="b",ups_name="c"} 10`),
regexp.MustCompile(`apcupsd_battery_volts{hostname="a",model="b",ups_name="c"} 13.2`),
regexp.MustCompile(`apcupsd_battery_number_transfers_total{hostname="a",model="b",ups_name="c"} 1`),
regexp.MustCompile(`apcupsd_line_nominal_volts{hostname="a",model="b",ups_name="c"} 120`),
regexp.MustCompile(`apcupsd_line_volts{hostname="a",model="b",ups_name="c"} 121.1`),
regexp.MustCompile(`apcupsd_ups_load_percent{hostname="a",model="b",ups_name="c"} 16`),
regexp.MustCompile(`apcupsd_last_transfer_on_battery{hostname="a",model="b",ups_name="c"} 100001`),
regexp.MustCompile(`apcupsd_last_transfer_off_battery{hostname="a",model="b",ups_name="c"} 100002`),
regexp.MustCompile(`apcupsd_last_selftest{hostname="a",model="b",ups_name="c"} 100003`),
regexp.MustCompile(`apcupsd_nominal_power_watts{hostname="a",model="b",ups_name="c"} 50`),
},
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
out := testCollector(t, NewUPSCollector(tt.ss))
for _, m := range tt.matches {
name := metricName(t, m.String())
t.Run(name, func(t *testing.T) {
if !m.Match(out) {
t.Fatalf("\toutput failed to match regex (regexp: %v)", m)
}
})
}
})
}
}
// TestZeroTimesAreIgnored tests that times with a zero value (time.IsZero() == true)
// are not collected.
func TestZeroTimesAreIgnored(t *testing.T) {
ss := &testStatusSource{
s: &apcupsd.Status{
XOnBattery: time.Unix(123456, 0),
XOffBattery: time.Time{},
},
}
out := testCollector(t, NewUPSCollector(ss))
// Test that in general timestamps are collected.
if !regexp.MustCompile(`apcupsd_last_transfer_on_battery.* 123456`).Match(out) {
t.Error("non-zero timestamp is not reported properly")
}
// Test that zero timestamps, however, are ignored.
if regexp.MustCompile(`apcupsd_last_transfer_off_battery`).Match(out) {
t.Error("Zero time is reported")
}
}
func metricName(t *testing.T, metric string) string {
ss := strings.Split(metric, " ")
if len(ss) != 2 {
t.Fatalf("malformed metric: %v", metric)
}
if !strings.Contains(ss[0], "{") {
return ss[0]
}
ss = strings.Split(ss[0], "{")
if len(ss) != 2 {
t.Fatalf("malformed metric: %v", metric)
}
return ss[0]
}
var _ StatusSource = &testStatusSource{}
type testStatusSource struct {
s *apcupsd.Status
}
func (ss *testStatusSource) Status() (*apcupsd.Status, error) {
return ss.s, nil
}