1
0
Fork 0
telegraf/plugins/outputs/signalfx/signalfx_test.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

652 lines
20 KiB
Go

package signalfx
import (
"context"
"errors"
"reflect"
"testing"
"time"
"github.com/signalfx/golib/v3/datapoint"
"github.com/signalfx/golib/v3/event"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/influxdata/telegraf/plugins/outputs"
"github.com/influxdata/telegraf/testutil"
)
type sink struct {
datapoints []*datapoint.Datapoint
events []*event.Event
}
func (s *sink) AddDatapoints(_ context.Context, points []*datapoint.Datapoint) error {
s.datapoints = append(s.datapoints, points...)
return nil
}
func (s *sink) AddEvents(_ context.Context, events []*event.Event) error {
s.events = append(s.events, events...)
return nil
}
type errorsink struct {
datapoints []*datapoint.Datapoint
events []*event.Event
}
func (*errorsink) AddDatapoints(context.Context, []*datapoint.Datapoint) error {
return errors.New("not sending datapoints")
}
func (*errorsink) AddEvents(context.Context, []*event.Event) error {
return errors.New("not sending events")
}
func TestSignalFx_SignalFx(t *testing.T) {
type measurement struct {
name string
tags map[string]string
fields map[string]interface{}
time time.Time
tp telegraf.ValueType
}
type fields struct {
IncludedEvents []string
}
tests := []struct {
name string
fields fields
measurements []*measurement
want errorsink
}{
{
name: "add datapoints of all types",
fields: fields{},
measurements: []*measurement{
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Counter,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Summary,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Histogram,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Untyped,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"myboolmeasurement": true},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"myboolmeasurement": false},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
},
},
want: errorsink{
datapoints: []*datapoint.Datapoint{
datapoint.New(
"datapoint.mymeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Counter,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.mymeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.mymeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.mymeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.mymeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.mymeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.myboolmeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewIntValue(int64(1)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
datapoint.New(
"datapoint.myboolmeasurement",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewIntValue(int64(0)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
},
events: make([]*event.Event, 0),
},
},
{
name: "add events of all types",
fields: fields{
IncludedEvents: []string{"event.mymeasurement"},
},
measurements: []*measurement{
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Counter,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Summary,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Histogram,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Untyped,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
},
},
want: errorsink{
datapoints: make([]*datapoint.Datapoint, 0),
events: []*event.Event{
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
},
},
},
{
name: "exclude events by default",
fields: fields{},
measurements: []*measurement{
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"value": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
},
want: errorsink{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
},
},
{
name: "add datapoint with field named value",
fields: fields{},
measurements: []*measurement{
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"value": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
},
want: errorsink{
datapoints: []*datapoint.Datapoint{
datapoint.New(
"datapoint",
map[string]string{
"host": "192.168.0.1",
},
datapoint.NewFloatValue(float64(3.14)),
datapoint.Gauge,
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
},
events: make([]*event.Event, 0),
},
},
{
name: "add event",
fields: fields{
IncludedEvents: []string{"event.mymeasurement"},
},
measurements: []*measurement{
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Untyped,
},
},
want: errorsink{
datapoints: make([]*datapoint.Datapoint, 0),
events: []*event.Event{
event.NewWithProperties(
"event.mymeasurement",
event.AGENT,
map[string]string{
"host": "192.168.0.1",
},
map[string]interface{}{
"message": "hello world",
},
time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)),
},
},
},
{
name: "exclude events that are not explicitly included",
fields: fields{},
measurements: []*measurement{
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"value": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
},
want: errorsink{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
},
},
{
name: "malformed metadata event",
fields: fields{},
measurements: []*measurement{
{
name: "event",
tags: map[string]string{"host": "192.168.0.1", "sf_metric": "objects.host-meta-data"},
fields: map[string]interface{}{"value": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
},
want: errorsink{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := outputs.Outputs["signalfx"]().(*SignalFx)
s.IncludedEventNames = tt.fields.IncludedEvents
s.SignalFxRealm = "test"
s.Log = testutil.Logger{}
require.NoError(t, s.Connect())
s.client = &sink{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
}
measurements := make([]telegraf.Metric, 0, len(tt.measurements))
for _, measurement := range tt.measurements {
measurements = append(measurements, metric.New(measurement.name, measurement.tags, measurement.fields, measurement.time, measurement.tp))
}
err := s.Write(measurements)
require.NoError(t, err)
require.Eventually(t, func() bool { return len(s.client.(*sink).datapoints) == len(tt.want.datapoints) }, 5*time.Second, 10*time.Millisecond)
require.Eventually(t, func() bool { return len(s.client.(*sink).events) == len(tt.want.events) }, 5*time.Second, 10*time.Millisecond)
if !reflect.DeepEqual(s.client.(*sink).datapoints, tt.want.datapoints) {
t.Errorf("Collected datapoints do not match desired. Collected: %v Desired: %v", s.client.(*sink).datapoints, tt.want.datapoints)
}
if !reflect.DeepEqual(s.client.(*sink).events, tt.want.events) {
t.Errorf("Collected events do not match desired. Collected: %v Desired: %v", s.client.(*sink).events, tt.want.events)
}
})
}
}
func TestSignalFx_Errors(t *testing.T) {
type measurement struct {
name string
tags map[string]string
fields map[string]interface{}
time time.Time
tp telegraf.ValueType
}
type fields struct {
IncludedEvents []string
}
type want struct {
datapoints []*datapoint.Datapoint
events []*event.Event
}
tests := []struct {
name string
fields fields
measurements []*measurement
want want
}{
{
name: "add datapoints of all types",
fields: fields{},
measurements: []*measurement{
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Counter,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Summary,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Histogram,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Untyped,
},
{
name: "datapoint",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": float64(3.14)},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
},
},
want: want{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
},
},
{
name: "add events of all types",
fields: fields{
IncludedEvents: []string{"event.mymeasurement"},
},
measurements: []*measurement{
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Counter,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Gauge,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Summary,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Histogram,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
tp: telegraf.Untyped,
},
{
name: "event",
tags: map[string]string{"host": "192.168.0.1"},
fields: map[string]interface{}{"mymeasurement": "hello world"},
time: time.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC),
},
},
want: want{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := outputs.Outputs["signalfx"]().(*SignalFx)
// constrain the buffer to cover code that emits when batch size is met
s.IncludedEventNames = tt.fields.IncludedEvents
s.SignalFxRealm = "test"
s.Log = testutil.Logger{}
require.NoError(t, s.Connect())
s.client = &errorsink{
datapoints: make([]*datapoint.Datapoint, 0),
events: make([]*event.Event, 0),
}
for _, measurement := range tt.measurements {
m := metric.New(
measurement.name, measurement.tags, measurement.fields, measurement.time, measurement.tp,
)
err := s.Write([]telegraf.Metric{m})
require.Error(t, err)
}
for len(s.client.(*errorsink).datapoints) != len(tt.want.datapoints) || len(s.client.(*errorsink).events) != len(tt.want.events) {
time.Sleep(1 * time.Second)
}
if !reflect.DeepEqual(s.client.(*errorsink).datapoints, tt.want.datapoints) {
t.Errorf("Collected datapoints do not match desired. Collected: %v Desired: %v", s.client.(*errorsink).datapoints, tt.want.datapoints)
}
if !reflect.DeepEqual(s.client.(*errorsink).events, tt.want.events) {
t.Errorf("Collected events do not match desired. Collected: %v Desired: %v", s.client.(*errorsink).events, tt.want.events)
}
})
}
}
func TestGetMetricName(t *testing.T) {
type args struct {
metric string
field string
dims map[string]string
}
tests := []struct {
name string
args args
want string
wantsfx bool
}{
{
name: "fields that equal value should not be append to metricname",
args: args{
metric: "datapoint",
field: "value",
dims: map[string]string{
"testDimKey": "testDimVal",
},
},
want: "datapoint",
},
{
name: "fields other than 'value' with out sf_metric dim should return measurement.fieldname as metric name",
args: args{
metric: "datapoint",
field: "test",
dims: map[string]string{
"testDimKey": "testDimVal",
},
},
want: "datapoint.test",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getMetricName(tt.args.metric, tt.args.field)
if got != tt.want {
t.Errorf("getMetricName() got = %v, want %v", got, tt.want)
}
})
}
}