1
0
Fork 0
telegraf/plugins/parsers/collectd/parser_test.go

411 lines
8.9 KiB
Go
Raw Permalink Normal View History

package collectd
import (
"context"
"testing"
"time"
"collectd.org/api"
"collectd.org/network"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/testutil"
)
type AuthMap struct {
Passwd map[string]string
}
func (p *AuthMap) Password(user string) (string, error) {
return p.Passwd[user], nil
}
type metricData struct {
name string
tags map[string]string
fields map[string]interface{}
}
type testCase struct {
vl []api.ValueList
expected []metricData
}
var singleMetric = testCase{
[]api.ValueList{
{
Identifier: api.Identifier{
Host: "xyzzy",
Plugin: "cpu",
PluginInstance: "1",
Type: "cpu",
TypeInstance: "user",
},
Values: []api.Value{
api.Counter(42),
},
DSNames: []string(nil),
},
},
[]metricData{
{
"cpu_value",
map[string]string{
"type_instance": "user",
"host": "xyzzy",
"instance": "1",
"type": "cpu",
},
map[string]interface{}{
"value": float64(42),
},
},
},
}
var multiMetric = testCase{
[]api.ValueList{
{
Identifier: api.Identifier{
Host: "xyzzy",
Plugin: "cpu",
PluginInstance: "0",
Type: "cpu",
TypeInstance: "user",
},
Values: []api.Value{
api.Derive(42),
api.Gauge(42),
},
DSNames: []string{"t1", "t2"},
},
},
[]metricData{
{
"cpu_0",
map[string]string{
"type_instance": "user",
"host": "xyzzy",
"instance": "0",
"type": "cpu",
},
map[string]interface{}{
"value": float64(42),
},
},
{
"cpu_1",
map[string]string{
"type_instance": "user",
"host": "xyzzy",
"instance": "0",
"type": "cpu",
},
map[string]interface{}{
"value": float64(42),
},
},
},
}
func TestNewCollectdParser(t *testing.T) {
parser := Parser{
ParseMultiValue: "join",
}
require.NoError(t, parser.Init())
require.Equal(t, network.None, parser.popts.SecurityLevel)
require.NotNil(t, parser.popts.PasswordLookup)
require.Nil(t, parser.popts.TypesDB)
}
func TestParse(t *testing.T) {
cases := []testCase{singleMetric, multiMetric}
for _, tc := range cases {
buf, err := writeValueList(t.Context(), tc.vl)
require.NoError(t, err)
bytes, err := buf.Bytes()
require.NoError(t, err)
parser := &Parser{}
require.NoError(t, parser.Init())
metrics, err := parser.Parse(bytes)
require.NoError(t, err)
assertEqualMetrics(t, tc.expected, metrics)
}
}
func TestParseMultiValueSplit(t *testing.T) {
buf, err := writeValueList(t.Context(), multiMetric.vl)
require.NoError(t, err)
bytes, err := buf.Bytes()
require.NoError(t, err)
parser := &Parser{ParseMultiValue: "split"}
require.NoError(t, parser.Init())
metrics, err := parser.Parse(bytes)
require.NoError(t, err)
require.Len(t, metrics, 2)
}
func TestParseMultiValueJoin(t *testing.T) {
buf, err := writeValueList(t.Context(), multiMetric.vl)
require.NoError(t, err)
bytes, err := buf.Bytes()
require.NoError(t, err)
parser := &Parser{ParseMultiValue: "join"}
require.NoError(t, parser.Init())
metrics, err := parser.Parse(bytes)
require.NoError(t, err)
require.Len(t, metrics, 1)
}
func TestParse_DefaultTags(t *testing.T) {
buf, err := writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
bytes, err := buf.Bytes()
require.NoError(t, err)
parser := &Parser{}
require.NoError(t, parser.Init())
parser.SetDefaultTags(map[string]string{
"foo": "bar",
})
require.NoError(t, err)
metrics, err := parser.Parse(bytes)
require.NoError(t, err)
require.Equal(t, "bar", metrics[0].Tags()["foo"])
}
func TestParse_SignSecurityLevel(t *testing.T) {
parser := &Parser{
SecurityLevel: "sign",
AuthFile: "testdata/authfile",
}
require.NoError(t, parser.Init())
// Signed data
buf, err := writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
buf.Sign("user0", "bar")
bytes, err := buf.Bytes()
require.NoError(t, err)
metrics, err := parser.Parse(bytes)
require.NoError(t, err)
assertEqualMetrics(t, singleMetric.expected, metrics)
// Encrypted data
buf, err = writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
buf.Encrypt("user0", "bar")
bytes, err = buf.Bytes()
require.NoError(t, err)
metrics, err = parser.Parse(bytes)
require.NoError(t, err)
assertEqualMetrics(t, singleMetric.expected, metrics)
// Plain text data skipped
buf, err = writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
bytes, err = buf.Bytes()
require.NoError(t, err)
metrics, err = parser.Parse(bytes)
require.NoError(t, err)
require.Empty(t, metrics)
// Wrong password error
buf, err = writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
buf.Sign("x", "y")
bytes, err = buf.Bytes()
require.NoError(t, err)
_, err = parser.Parse(bytes)
require.Error(t, err)
}
func TestParse_EncryptSecurityLevel(t *testing.T) {
parser := &Parser{
SecurityLevel: "encrypt",
AuthFile: "testdata/authfile",
}
require.NoError(t, parser.Init())
// Signed data skipped
buf, err := writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
buf.Sign("user0", "bar")
bytes, err := buf.Bytes()
require.NoError(t, err)
metrics, err := parser.Parse(bytes)
require.NoError(t, err)
require.Empty(t, metrics)
// Encrypted data
buf, err = writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
buf.Encrypt("user0", "bar")
bytes, err = buf.Bytes()
require.NoError(t, err)
metrics, err = parser.Parse(bytes)
require.NoError(t, err)
assertEqualMetrics(t, singleMetric.expected, metrics)
// Plain text data skipped
buf, err = writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
bytes, err = buf.Bytes()
require.NoError(t, err)
metrics, err = parser.Parse(bytes)
require.NoError(t, err)
require.Empty(t, metrics)
// Wrong password error
buf, err = writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
buf.Sign("x", "y")
bytes, err = buf.Bytes()
require.NoError(t, err)
_, err = parser.Parse(bytes)
require.Error(t, err)
}
func TestParseLine(t *testing.T) {
buf, err := writeValueList(t.Context(), singleMetric.vl)
require.NoError(t, err)
bytes, err := buf.Bytes()
require.NoError(t, err)
parser := Parser{
ParseMultiValue: "split",
}
require.NoError(t, parser.Init())
m, err := parser.ParseLine(string(bytes))
require.NoError(t, err)
assertEqualMetrics(t, singleMetric.expected, []telegraf.Metric{m})
}
func writeValueList(testContext context.Context, valueLists []api.ValueList) (*network.Buffer, error) {
buffer := network.NewBuffer(0)
for i := range valueLists {
err := buffer.Write(testContext, &valueLists[i])
if err != nil {
return nil, err
}
}
return buffer, nil
}
func assertEqualMetrics(t *testing.T, expected []metricData, received []telegraf.Metric) {
require.Len(t, received, len(expected))
for i, m := range received {
require.Equal(t, expected[i].name, m.Name())
require.Equal(t, expected[i].tags, m.Tags())
require.Equal(t, expected[i].fields, m.Fields())
}
}
var benchmarkData = []api.ValueList{
{
Identifier: api.Identifier{
Host: "xyzzy",
Plugin: "cpu",
PluginInstance: "1",
Type: "cpu",
TypeInstance: "user",
},
Values: []api.Value{
api.Counter(4),
},
DSNames: []string(nil),
},
{
Identifier: api.Identifier{
Host: "xyzzy",
Plugin: "cpu",
PluginInstance: "2",
Type: "cpu",
TypeInstance: "user",
},
Values: []api.Value{
api.Counter(5),
},
DSNames: []string(nil),
},
}
func TestBenchmarkData(t *testing.T) {
expected := []telegraf.Metric{
metric.New(
"cpu_value",
map[string]string{
"host": "xyzzy",
"instance": "1",
"type": "cpu",
"type_instance": "user",
},
map[string]interface{}{
"value": 4.0,
},
time.Unix(0, 0),
),
metric.New(
"cpu_value",
map[string]string{
"host": "xyzzy",
"instance": "2",
"type": "cpu",
"type_instance": "user",
},
map[string]interface{}{
"value": 5.0,
},
time.Unix(0, 0),
),
}
buf, err := writeValueList(t.Context(), benchmarkData)
require.NoError(t, err)
bytes, err := buf.Bytes()
require.NoError(t, err)
parser := &Parser{}
require.NoError(t, parser.Init())
actual, err := parser.Parse(bytes)
require.NoError(t, err)
testutil.RequireMetricsEqual(t, expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())
}
func BenchmarkParsing(b *testing.B) {
buf, err := writeValueList(b.Context(), benchmarkData)
require.NoError(b, err)
bytes, err := buf.Bytes()
require.NoError(b, err)
parser := &Parser{}
require.NoError(b, parser.Init())
b.ResetTimer()
for n := 0; n < b.N; n++ {
//nolint:errcheck // Benchmarking so skip the error check to avoid the unnecessary operations
parser.Parse(bytes)
}
}