telegraf/plugins/inputs/upsd/upsd_test.go

296 lines
7.4 KiB
Go

package upsd
import (
"context"
"net"
"testing"
"time"
"github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/require"
)
func TestUpsdGather(t *testing.T) {
nut := &Upsd{}
var (
tests = []struct {
name string
forceFloat bool
err bool
tags map[string]string
fields map[string]interface{}
out func() []interaction
}{
{
name: "test listening server with output",
forceFloat: false,
err: false,
tags: map[string]string{
"serial": "ABC123",
"ups_name": "fake",
"model": "Model 12345",
"status_OL": "true",
},
fields: map[string]interface{}{
"battery_charge_percent": float64(100),
"battery_date": nil,
"battery_mfr_date": "2016-07-26",
"battery_voltage": float64(13.4),
"firmware": "CUSTOM_FIRMWARE",
"input_voltage": float64(242),
"load_percent": float64(23),
"nominal_battery_voltage": float64(24),
"nominal_input_voltage": float64(230),
"nominal_power": int64(700),
"output_voltage": float64(230),
"real_power": float64(41),
"status_flags": uint64(8),
"time_left_ns": int64(600000000000),
"ups_status": "OL",
},
out: genOutput,
},
{
name: "test listening server with output & force floats",
forceFloat: true,
err: false,
tags: map[string]string{
"serial": "ABC123",
"ups_name": "fake",
"model": "Model 12345",
"status_OL": "true",
},
fields: map[string]interface{}{
"battery_charge_percent": float64(100),
"battery_date": nil,
"battery_mfr_date": "2016-07-26",
"battery_voltage": float64(13.4),
"firmware": "CUSTOM_FIRMWARE",
"input_voltage": float64(242),
"load_percent": float64(23),
"nominal_battery_voltage": float64(24),
"nominal_input_voltage": float64(230),
"nominal_power": int64(700),
"output_voltage": float64(230),
"real_power": float64(41),
"status_flags": uint64(8),
"time_left_ns": int64(600000000000),
"ups_status": "OL",
},
out: genOutput,
},
}
acc testutil.Accumulator
)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
lAddr, err := listen(ctx, t, tt.out())
require.NoError(t, err)
nut.Server = (lAddr.(*net.TCPAddr)).IP.String()
nut.Port = (lAddr.(*net.TCPAddr)).Port
nut.ForceFloat = tt.forceFloat
err = nut.Gather(&acc)
if tt.err {
require.Error(t, err)
} else {
require.NoError(t, err)
acc.AssertContainsFields(t, "upsd", tt.fields)
acc.AssertContainsTaggedFields(t, "upsd", tt.fields, tt.tags)
}
cancel()
})
}
}
func TestUpsdGatherFail(t *testing.T) {
nut := &Upsd{}
var (
tests = []struct {
name string
err bool
tags map[string]string
fields map[string]interface{}
out func() []interaction
}{
{
name: "test with bad output",
err: true,
out: genBadOutput,
},
}
acc testutil.Accumulator
)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
lAddr, err := listen(ctx, t, tt.out())
require.NoError(t, err)
nut.Server = (lAddr.(*net.TCPAddr)).IP.String()
nut.Port = (lAddr.(*net.TCPAddr)).Port
err = nut.Gather(&acc)
if tt.err {
require.Error(t, err)
} else {
require.NoError(t, err)
acc.AssertContainsTaggedFields(t, "upsd", tt.fields, tt.tags)
}
cancel()
})
}
}
func listen(ctx context.Context, t *testing.T, out []interaction) (net.Addr, error) {
lc := net.ListenConfig{}
ln, err := lc.Listen(ctx, "tcp4", "127.0.0.1:0")
if err != nil {
return nil, err
}
go func() {
defer ln.Close()
for ctx.Err() == nil {
func() {
conn, err := ln.Accept()
if err != nil {
return
}
defer conn.Close()
require.NoError(t, conn.SetReadDeadline(time.Now().Add(time.Minute)))
in := make([]byte, 128)
for _, interaction := range out {
n, err := conn.Read(in)
require.NoError(t, err, "failed to read from connection")
expectedBytes := []byte(interaction.Expected)
want, got := expectedBytes, in[:n]
require.Equal(t, want, got)
_, err = conn.Write([]byte(interaction.Response))
require.NoError(t, err, "failed to respond to LIST UPS")
}
// Append EOF to end of output bytes
_, err = conn.Write([]byte{0, 0})
require.NoError(t, err, "failed to write EOF")
}()
}
}()
return ln.Addr(), nil
}
type interaction struct {
Expected string
Response string
}
func genOutput() []interaction {
m := make([]interaction, 0)
m = append(m, interaction{
Expected: "VER\n",
Response: "1\n",
})
m = append(m, interaction{
Expected: "NETVER\n",
Response: "1\n",
})
m = append(m, interaction{
Expected: "LIST UPS\n",
Response: `BEGIN LIST UPS
UPS fake "fakescription"
END LIST UPS
`,
})
m = append(m, interaction{
Expected: "LIST CLIENT fake\n",
Response: `BEGIN LIST CLIENT fake
CLIENT fake 192.168.1.1
END LIST CLIENT fake
`,
})
m = append(m, interaction{
Expected: "LIST CMD fake\n",
Response: `BEGIN LIST CMD fake
END LIST CMD fake
`,
})
m = append(m, interaction{
Expected: "GET UPSDESC fake\n",
Response: "UPSDESC fake \"stub-ups-description\"\n",
})
m = append(m, interaction{
Expected: "GET NUMLOGINS fake\n",
Response: "NUMLOGINS fake 1\n",
})
m = append(m, interaction{
Expected: "LIST VAR fake\n",
Response: `BEGIN LIST VAR fake
VAR fake device.serial "ABC123"
VAR fake device.model "Model 12345"
VAR fake input.voltage "242.0"
VAR fake ups.load "23.0"
VAR fake battery.charge "100.0"
VAR fake battery.runtime "600.00"
VAR fake output.voltage "230.0"
VAR fake battery.voltage "13.4"
VAR fake input.voltage.nominal "230.0"
VAR fake battery.voltage.nominal "24.0"
VAR fake ups.realpower "41.0"
VAR fake ups.realpower.nominal "700"
VAR fake ups.firmware "CUSTOM_FIRMWARE"
VAR fake battery.mfr.date "2016-07-26"
VAR fake ups.status "OL"
END LIST VAR fake
`,
})
m = appendVariable(m, "device.serial", "STRING:64")
m = appendVariable(m, "device.model", "STRING:64")
m = appendVariable(m, "input.voltage", "NUMBER")
m = appendVariable(m, "ups.load", "NUMBER")
m = appendVariable(m, "battery.charge", "NUMBER")
m = appendVariable(m, "battery.runtime", "NUMBER")
m = appendVariable(m, "output.voltage", "NUMBER")
m = appendVariable(m, "battery.voltage", "NUMBER")
m = appendVariable(m, "input.voltage.nominal", "NUMBER")
m = appendVariable(m, "battery.voltage.nominal", "NUMBER")
m = appendVariable(m, "ups.realpower", "NUMBER")
m = appendVariable(m, "ups.realpower.nominal", "NUMBER")
m = appendVariable(m, "ups.firmware", "STRING:64")
m = appendVariable(m, "battery.mfr.date", "STRING:64")
m = appendVariable(m, "ups.status", "STRING:64")
return m
}
func appendVariable(m []interaction, name string, typ string) []interaction {
m = append(m, interaction{
Expected: "GET DESC fake " + name + "\n",
Response: "DESC fake" + name + " \"No description here\"\n",
})
m = append(m, interaction{
Expected: "GET TYPE fake " + name + "\n",
Response: "TYPE fake " + name + " " + typ + "\n",
})
return m
}
func genBadOutput() []interaction {
m := make([]interaction, 0)
return m
}