1
0
Fork 0
telegraf/plugins/inputs/smartctl/smartctl_test.go

199 lines
5.4 KiB
Go
Raw Normal View History

package smartctl
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"slices"
"strconv"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/influxdata/telegraf/plugins/parsers/influx"
"github.com/influxdata/telegraf/testutil"
)
func TestCasesScan(t *testing.T) {
// Get all directories in testdata
folders, err := os.ReadDir("testcases_scan")
require.NoError(t, err)
// Register the plugin
inputs.Add("smartctl", func() telegraf.Input {
return &Smartctl{}
})
for _, f := range folders {
if !f.IsDir() {
continue
}
testcasePath := filepath.Join("testcases_scan", f.Name())
configFilename := filepath.Join(testcasePath, "telegraf.toml")
scanFilename := filepath.Join(testcasePath, "response.json")
expectedFilename := filepath.Join(testcasePath, "expected.out")
t.Run(f.Name(), func(t *testing.T) {
parser := &influx.Parser{}
require.NoError(t, parser.Init())
// Read the expected output if any
var expected int
if _, err := os.Stat(expectedFilename); err == nil {
var err error
expectedBytes, err := os.ReadFile(expectedFilename)
require.NoError(t, err)
expected, err = strconv.Atoi(strings.TrimSpace(string(expectedBytes)))
require.NoError(t, err)
}
// Update exec to return fake data.
execCommand = fakeScanExecCommand
defer func() { execCommand = exec.Command }()
// Configure the plugin
cfg := config.NewConfig()
require.NoError(t, cfg.LoadConfig(configFilename))
require.Len(t, cfg.Inputs, 1)
plugin := cfg.Inputs[0].Input.(*Smartctl)
require.NoError(t, plugin.Init())
scanArgs = append(scanArgs, scanFilename)
devices, err := plugin.scan()
require.NoError(t, err)
require.Len(t, devices, expected)
})
}
}
func fakeScanExecCommand(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestScanHelperProcess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
func TestScanHelperProcess(*testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
args := os.Args
scanBytes, err := os.ReadFile(args[len(args)-1])
if err != nil {
fmt.Fprint(os.Stdout, "unknown filename")
//nolint:revive // os.Exit called intentionally
os.Exit(42)
}
fmt.Fprint(os.Stdout, string(scanBytes))
//nolint:revive // os.Exit called intentionally
os.Exit(0)
}
func TestCasesDevices(t *testing.T) {
// Get all directories in testdata
folders, err := os.ReadDir("testcases_device")
require.NoError(t, err)
// Register the plugin
inputs.Add("smartctl", func() telegraf.Input {
return &Smartctl{}
})
for _, f := range folders {
if !f.IsDir() {
continue
}
testcasePath := filepath.Join("testcases_device", f.Name())
deviceFilename := filepath.Join(testcasePath, "device")
deviceTypeFilename := filepath.Join(testcasePath, "deviceType")
expectedFilename := filepath.Join(testcasePath, "expected.out")
t.Run(f.Name(), func(t *testing.T) {
parser := &influx.Parser{}
require.NoError(t, parser.Init())
// Read the expected output if any
var expected []telegraf.Metric
if _, err := os.Stat(expectedFilename); err == nil {
var err error
expected, err = testutil.ParseMetricsFromFile(expectedFilename, parser)
require.NoError(t, err)
}
// Read the devices to scan
deviceBytes, err := os.ReadFile(deviceFilename)
require.NoError(t, err)
deviceTypeBytes, err := os.ReadFile(deviceTypeFilename)
require.NoError(t, err)
// Update exec to return fake data.
execCommand = fakeDeviceExecCommand
defer func() { execCommand = exec.Command }()
// Configure the plugin
plugin := Smartctl{}
require.NoError(t, plugin.Init())
var acc testutil.Accumulator
require.NoError(t,
plugin.scanDevice(
&acc,
strings.TrimSpace(string(deviceBytes)),
strings.TrimSpace(string(deviceTypeBytes)),
),
)
// Check the metric nevertheless as we might get some metrics despite errors.
actual := acc.GetTelegrafMetrics()
testutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime())
acc.Lock()
defer acc.Unlock()
require.Empty(t, acc.Errors)
})
}
}
func fakeDeviceExecCommand(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestDeviceHelperProcess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
func TestDeviceHelperProcess(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
args := os.Args
var filename string
if slices.Contains(args, "/dev/nvme0") {
filename = "testcases_device/nvme/response.json"
} else if slices.Contains(args, "/dev/sda") {
filename = "testcases_device/usb/response.json"
} else if slices.Contains(args, "/dev/bus/6") {
filename = "testcases_device/megaraid/response.json"
} else if slices.Contains(args, "/dev/sdb") {
filename = "testcases_device/scsi/response.json"
} else if slices.Contains(args, "/dev/sdaa") {
filename = "testcases_device/scsi_extended/response.json"
} else {
fmt.Fprint(os.Stdout, "unknown filename")
os.Exit(42) //nolint:revive // os.Exit called intentionally
}
scanBytes, err := os.ReadFile(filename)
require.NoError(t, err)
fmt.Fprint(os.Stdout, string(scanBytes))
os.Exit(0) //nolint:revive // os.Exit called intentionally
}