1
0
Fork 0
telegraf/plugins/inputs/nfsclient/nfsclient_test.go

342 lines
9.7 KiB
Go
Raw Permalink Normal View History

package nfsclient
import (
"bufio"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf/testutil"
)
func getMountStatsPath() string {
path := "./testdata/mountstats"
if os.Getenv("MOUNT_PROC") != "" {
path = os.Getenv("MOUNT_PROC")
}
return path
}
func TestNFSClientParsev3(t *testing.T) {
var acc testutil.Accumulator
nfsclient := NFSClient{Fullstat: true}
nfsclient.nfs3Ops = map[string]bool{"READLINK": true, "GETATTR": false}
nfsclient.nfs4Ops = map[string]bool{"READLINK": true, "GETATTR": false}
data := strings.Fields(" READLINK: 500 501 502 503 504 505 506 507")
err := nfsclient.parseStat("1.2.3.4:/storage/NFS", "/A", "3", data, &acc)
require.NoError(t, err)
fieldsOps := map[string]interface{}{
"ops": uint64(500),
"trans": uint64(501),
"timeouts": uint64(502),
"bytes_sent": uint64(503),
"bytes_recv": uint64(504),
"queue_time": uint64(505),
"response_time": uint64(506),
"total_time": uint64(507),
}
acc.AssertContainsFields(t, "nfs_ops", fieldsOps)
}
func TestNFSClientParsev4(t *testing.T) {
var acc testutil.Accumulator
nfsclient := NFSClient{Fullstat: true}
nfsclient.nfs3Ops = map[string]bool{"DESTROY_SESSION": true, "GETATTR": false}
nfsclient.nfs4Ops = map[string]bool{"DESTROY_SESSION": true, "GETATTR": false}
data := strings.Fields(" DESTROY_SESSION: 500 501 502 503 504 505 506 507")
err := nfsclient.parseStat("2.2.2.2:/nfsdata/", "/B", "4", data, &acc)
require.NoError(t, err)
fieldsOps := map[string]interface{}{
"ops": uint64(500),
"trans": uint64(501),
"timeouts": uint64(502),
"bytes_sent": uint64(503),
"bytes_recv": uint64(504),
"queue_time": uint64(505),
"response_time": uint64(506),
"total_time": uint64(507),
}
acc.AssertContainsFields(t, "nfs_ops", fieldsOps)
}
func TestNFSClientParseLargeValue(t *testing.T) {
var acc testutil.Accumulator
nfsclient := NFSClient{Fullstat: true}
nfsclient.nfs3Ops = map[string]bool{"SETCLIENTID": true, "GETATTR": false}
nfsclient.nfs4Ops = map[string]bool{"SETCLIENTID": true, "GETATTR": false}
data := strings.Fields(" SETCLIENTID: 218 216 0 53568 12960 18446744073709531008 134 197")
err := nfsclient.parseStat("2.2.2.2:/nfsdata/", "/B", "4", data, &acc)
require.NoError(t, err)
fieldsOps := map[string]interface{}{
"ops": uint64(218),
"trans": uint64(216),
"timeouts": uint64(0),
"bytes_sent": uint64(53568),
"bytes_recv": uint64(12960),
"queue_time": uint64(18446744073709531008),
"response_time": uint64(134),
"total_time": uint64(197),
}
acc.AssertContainsFields(t, "nfs_ops", fieldsOps)
}
func TestNFSClientProcessStat(t *testing.T) {
var acc testutil.Accumulator
nfsclient := NFSClient{}
nfsclient.Fullstat = false
file, err := os.Open(getMountStatsPath())
require.NoError(t, err)
defer file.Close()
scanner := bufio.NewScanner(file)
err = nfsclient.processText(scanner, &acc)
require.NoError(t, err)
fieldsReadstat := map[string]interface{}{
"ops": uint64(600),
"retrans": uint64(1),
"bytes": uint64(1207),
"rtt": uint64(606),
"exe": uint64(607),
"rtt_per_op": float64(1.01),
}
readTags := map[string]string{
"serverexport": "1.2.3.4:/storage/NFS",
"mountpoint": "/A",
"operation": "READ",
}
acc.AssertContainsTaggedFields(t, "nfsstat", fieldsReadstat, readTags)
fieldsWritestat := map[string]interface{}{
"ops": uint64(700),
"retrans": uint64(1),
"bytes": uint64(1407),
"rtt": uint64(706),
"exe": uint64(707),
"rtt_per_op": float64(1.0085714285714287),
}
writeTags := map[string]string{
"serverexport": "1.2.3.4:/storage/NFS",
"mountpoint": "/A",
"operation": "WRITE",
}
acc.AssertContainsTaggedFields(t, "nfsstat", fieldsWritestat, writeTags)
}
func TestNFSClientProcessFull(t *testing.T) {
var acc testutil.Accumulator
nfsclient := NFSClient{}
nfsclient.Fullstat = true
file, err := os.Open(getMountStatsPath())
require.NoError(t, err)
defer file.Close()
scanner := bufio.NewScanner(file)
err = nfsclient.processText(scanner, &acc)
require.NoError(t, err)
fieldsEvents := map[string]interface{}{
"inoderevalidates": uint64(301736),
"dentryrevalidates": uint64(22838),
"datainvalidates": uint64(410979),
"attrinvalidates": uint64(26188427),
"vfsopen": uint64(27525),
"vfslookup": uint64(9140),
"vfsaccess": uint64(114420),
"vfsupdatepage": uint64(30785253),
"vfsreadpage": uint64(5308856),
"vfsreadpages": uint64(5364858),
"vfswritepage": uint64(30784819),
"vfswritepages": uint64(79832668),
"vfsgetdents": uint64(170),
"vfssetattr": uint64(64),
"vfsflush": uint64(18194),
"vfsfsync": uint64(29294718),
"vfslock": uint64(0),
"vfsrelease": uint64(18279),
"congestionwait": uint64(0),
"setattrtrunc": uint64(2),
"extendwrite": uint64(785551),
"sillyrenames": uint64(0),
"shortreads": uint64(0),
"shortwrites": uint64(0),
"delay": uint64(0),
"pnfsreads": uint64(0),
"pnfswrites": uint64(0),
}
fieldsBytes := map[string]interface{}{
"normalreadbytes": uint64(204440464584),
"normalwritebytes": uint64(110857586443),
"directreadbytes": uint64(783170354688),
"directwritebytes": uint64(296174954496),
"serverreadbytes": uint64(1134399088816),
"serverwritebytes": uint64(407107155723),
"readpages": uint64(85749323),
"writepages": uint64(30784819),
}
fieldsXprtTCP := map[string]interface{}{
"bind_count": uint64(1),
"connect_count": uint64(1),
"connect_time": uint64(0),
"idle_time": uint64(0),
"rpcsends": uint64(96172963),
"rpcreceives": uint64(96172963),
"badxids": uint64(0),
"inflightsends": uint64(620878754),
"backlogutil": uint64(0),
}
acc.AssertContainsFields(t, "nfs_events", fieldsEvents)
acc.AssertContainsFields(t, "nfs_bytes", fieldsBytes)
acc.AssertContainsFields(t, "nfs_xprt_tcp", fieldsXprtTCP)
}
func TestNFSClientFileDoesNotExist(t *testing.T) {
var acc testutil.Accumulator
nfsclient := NFSClient{Fullstat: true}
nfsclient.mountstatsPath = "/does_not_exist"
require.Error(t, nfsclient.Gather(&acc))
}
func TestNFSClientProcessTextWithIncludeExclude(t *testing.T) {
// Test cases for different include/exclude scenarios
testCases := []struct {
name string
includeMounts []string
excludeMounts []string
expectedMounts []string
unexpectedMounts []string
}{
{
name: "No filters",
includeMounts: nil,
excludeMounts: nil,
expectedMounts: []string{"/A", "/B"}, // All mounts should be included
},
{
name: "Exclude one mount",
includeMounts: nil,
excludeMounts: []string{"^/A$"},
expectedMounts: []string{"/B"},
unexpectedMounts: []string{"/A"},
},
{
name: "Include one mount",
includeMounts: []string{"^/A$"},
excludeMounts: nil,
expectedMounts: []string{"/A"},
unexpectedMounts: []string{"/B"},
},
{
name: "Include and exclude with regex",
includeMounts: []string{"^/"},
excludeMounts: []string{"^/A$"},
expectedMounts: []string{"/B"},
unexpectedMounts: []string{"/A"},
},
{
name: "Exclude with prefix pattern",
includeMounts: nil,
excludeMounts: []string{"^/A"},
expectedMounts: []string{"/B"},
unexpectedMounts: []string{"/A"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Create NFS client with test configuration
nfsclient := NFSClient{
IncludeMounts: tc.includeMounts,
ExcludeMounts: tc.excludeMounts,
Fullstat: true,
Log: testutil.Logger{},
}
require.NoError(t, nfsclient.Init())
// Open the test data
file, err := os.Open(getMountStatsPath())
require.NoError(t, err)
defer file.Close()
scanner := bufio.NewScanner(file)
// Process the data
var acc testutil.Accumulator
require.NoError(t, nfsclient.processText(scanner, &acc))
// Verify expected mounts are present
for _, mount := range tc.expectedMounts {
found := false
for _, metric := range acc.Metrics {
if mountpoint, exists := metric.Tags["mountpoint"]; exists && mountpoint == mount {
found = true
break
}
}
require.True(t, found, "Expected mount %s not found", mount)
}
// Verify unexpected mounts are absent
for _, mount := range tc.unexpectedMounts {
found := false
for _, metric := range acc.Metrics {
if mountpoint, exists := metric.Tags["mountpoint"]; exists && mountpoint == mount {
found = true
break
}
}
require.False(t, found, "Unexpected mount %s found", mount)
}
})
}
}
func TestNFSClientInvalidIncludeRegex(t *testing.T) {
// Test that invalid include regex patterns are properly reported as errors during Init
nfsclient := &NFSClient{
IncludeMounts: []string{"[invalid"},
ExcludeMounts: nil,
Fullstat: true,
Log: testutil.Logger{},
}
// Init should fail with an error due to invalid regex
err := nfsclient.Init()
require.Error(t, err)
require.Contains(t, err.Error(), "failed to compile include mount pattern")
}
func TestNFSClientInvalidExcludeRegex(t *testing.T) {
// Test that invalid exclude regex patterns are properly reported as errors during Init
nfsclient := &NFSClient{
IncludeMounts: nil,
ExcludeMounts: []string{"[also-invalid"},
Fullstat: true,
Log: testutil.Logger{},
}
// Init should fail with an error due to invalid regex
err := nfsclient.Init()
require.Error(t, err)
require.Contains(t, err.Error(), "failed to compile exclude mount pattern")
}