// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package snmpreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/snmpreceiver" import ( "context" "errors" "fmt" "path/filepath" "testing" "github.com/stretchr/testify/mock" // client is an autogenerated mock type for the client type "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/scrapererror" "go.uber.org/zap" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pmetrictest" ) type MockClient struct { mock.Mock } // Close provides a mock function with given fields: func (_m *MockClient) Close() error { ret := _m.Called() var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // Connect provides a mock function with given fields: func (_m *MockClient) Connect() error { ret := _m.Called() var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // GetIndexedData provides a mock function with given fields: oids, scraperErrors func (_m *MockClient) GetIndexedData(oids []string, scraperErrors *scrapererror.ScrapeErrors) []SNMPData { ret := _m.Called(oids, scraperErrors) var r0 []SNMPData if rf, ok := ret.Get(0).(func([]string, *scrapererror.ScrapeErrors) []SNMPData); ok { r0 = rf(oids, scraperErrors) } else if ret.Get(0) != nil { r0 = ret.Get(0).([]SNMPData) } return r0 } // GetScalarData provides a mock function with given fields: oids, scraperErrors func (_m *MockClient) GetScalarData(oids []string, scraperErrors *scrapererror.ScrapeErrors) []SNMPData { ret := _m.Called(oids, scraperErrors) var r0 []SNMPData if rf, ok := ret.Get(0).(func([]string, *scrapererror.ScrapeErrors) []SNMPData); ok { r0 = rf(oids, scraperErrors) } else if ret.Get(0) != nil { r0 = ret.Get(0).([]SNMPData) } return r0 } func TestStart(t *testing.T) { testCases := []struct { desc string testFunc func(*testing.T) }{ { desc: "Bad Config", testFunc: func(t *testing.T) { scraper := &snmpScraper{ cfg: &Config{}, settings: receivertest.NewNopCreateSettings(), } err := scraper.start(context.Background(), componenttest.NewNopHost()) require.Error(t, err) }, }, { desc: "Valid Config", testFunc: func(t *testing.T) { scraper := &snmpScraper{ cfg: createDefaultConfig().(*Config), settings: receivertest.NewNopCreateSettings(), } err := scraper.start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) }, }, } for _, tc := range testCases { t.Run(tc.desc, tc.testFunc) } } func TestScrape(t *testing.T) { testCases := []struct { desc string testFunc func(*testing.T) }{ { // Config is responsible for making sure this would never happen desc: "No Metric Configs returns no metrics with no error", testFunc: func(t *testing.T) { mockClient := new(MockClient) mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) scraper := &snmpScraper{ cfg: &Config{}, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Scalar scrape errors and no indexed metric configs adds error", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientErr := errors.New("problem getting scrape data") mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Run( func(args mock.Arguments) { scraperErrors := args.Get(1).(*scrapererror.ScrapeErrors) scraperErrors.AddPartial(1, clientErr) }, ).Return([]SNMPData{}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { ScalarOIDs: []ScalarOID{ { OID: "1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, clientErr.Error()) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Scalar scrape returns string data does not create metric", testFunc: func(t *testing.T) { mockClient := new(MockClient) oid := "1" clientSNMPData := SNMPData{ oid: oid, value: "test", valueType: stringVal, } innerError := fmt.Errorf(errMsgBadValueType, oid) expectedScrapeErr := fmt.Errorf(errMsgScalarOIDProcessing, oid, innerError) mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{clientSNMPData}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { ScalarOIDs: []ScalarOID{ { OID: "1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, expectedScrapeErr.Error()) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Simple scalar scrape creates int gauge metric (1)", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientSNMPData := SNMPData{ oid: ".1", value: int64(1), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{clientSNMPData}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "1_scalar_metrics_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Simple scalar scrape with non '.' prefixed OID still creates metric (1)", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientSNMPData := SNMPData{ oid: ".1", value: int64(1), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{clientSNMPData}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: "1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "1_scalar_metrics_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Simple scalar scrape creates float cumulative monotonic sum metric (2)", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientSNMPData := SNMPData{ oid: ".1", value: float64(1.0), valueType: floatVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{clientSNMPData}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Sum: &SumMetric{ Aggregation: "cumulative", Monotonic: true, ValueType: "double", }, ScalarOIDs: []ScalarOID{ { OID: ".1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "2_scalar_metrics_sum_cumulative_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Simple scalar scrape creates int delta non-monotonic sum metric (3)", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientSNMPData := SNMPData{ oid: ".1", value: int64(1), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{clientSNMPData}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Sum: &SumMetric{ Aggregation: "delta", Monotonic: false, ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "3_scalar_metrics_sum_delta_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Scalar scrape creates multiple metrics (4)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData1 := SNMPData{ oid: ".1", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ oid: ".2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".1", }, }, }, "metric2": { Description: "test description2", Unit: "{things}", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".2", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "4_scalar_multiple_metrics_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Scalar scrape creates metric with attributes (5)", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientSNMPData := SNMPData{ oid: ".1", value: int64(1), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{clientSNMPData}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { Enum: []string{"val1", "val2"}, }, "attr2": { Value: "attr2NewName", Enum: []string{"val1", "val2"}, }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", Value: "val1", }, { Name: "attr2", Value: "val2", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "5_scalar_metric_w_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Scalar scrape creates metric with multiple data points (6)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData1 := SNMPData{ oid: ".1", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ oid: ".2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { Enum: []string{"val1", "val2"}, }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", Value: "val1", }, }, }, { OID: ".2", Attributes: []Attribute{ { Name: "attr1", Value: "val2", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "6_scalar_metric_w_multi_datapoint_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed scrape errors and no scalar metric configs adds error", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientErr := errors.New("problem getting data") mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Run( func(args mock.Arguments) { scraperErrors := args.Get(1).(*scrapererror.ScrapeErrors) scraperErrors.AddPartial(1, clientErr) }, ).Return([]SNMPData{}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { ColumnOIDs: []ColumnOID{ { OID: "1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, clientErr.Error()) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Indexed metric scrape returns string data does not create metric", testFunc: func(t *testing.T) { mockClient := new(MockClient) columnOID := ".1" oid1 := ".1.1" oid2 := ".1.2" snmpData1 := SNMPData{ columnOID: columnOID, oid: oid1, value: "test1", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: columnOID, oid: oid2, value: "test2", valueType: stringVal, } innerError1 := fmt.Errorf(errMsgBadValueType, oid1) expectedScrapeErr1 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid1, columnOID, innerError1) innerError2 := fmt.Errorf(errMsgBadValueType, oid2) expectedScrapeErr2 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid2, columnOID, innerError2) expectedScrapeErrMsg := expectedScrapeErr1.Error() + "; " + expectedScrapeErr2.Error() mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Metrics: map[string]*MetricConfig{ "metric1": { ColumnOIDs: []ColumnOID{ { OID: ".1", }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, expectedScrapeErrMsg) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Simple indexed metric scrape creates int gauge metric on new no attribute resource (7)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData1 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "7_indexed_metrics_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Simple indexed metric scrape with non '.' prefixed OID still creates metric (7)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData1 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: "1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "7_indexed_metrics_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Simple indexed metric scrape creates float cumulative monotonic sum metric (8)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData1 := SNMPData{ columnOID: ".1", oid: ".1.1", value: float64(1.0), valueType: floatVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.2", value: float64(2.0), valueType: floatVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Sum: &SumMetric{ Aggregation: "cumulative", Monotonic: true, ValueType: "double", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "8_indexed_metrics_sum_cumulative_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Simple indexed metric scrape creates int delta non-monotonic sum metric (9)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData1 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Sum: &SumMetric{ Aggregation: "delta", Monotonic: false, ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "9_indexed_metrics_sum_delta_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed metric scrape creates metric on existing resource if scalar metrics were scraped (10)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ oid: ".0", value: int64(0), valueType: integerVal, } snmpData1 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0}) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData1, snmpData2}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, }, Metrics: map[string]*MetricConfig{ "metric0": { Description: "test description0", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".0", }, }, }, "metric1": { Description: "test description1", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "10_indexed_scalar_metrics_same_resource_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed metric scrape creates multiple metrics on same no attribute resource (11)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: int64(0), valueType: integerVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: int64(1), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(2), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(3), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0, snmpData1, snmpData2, snmpData3}) scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, }, Metrics: map[string]*MetricConfig{ "metric0": { Description: "test description0", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".0", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, "metric1": { Description: "test description1", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "11_indexed_multiple_metrics_same_resource_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed metric scrape creates with all attribute config creates metric with all attributes (12)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: "thing1", valueType: stringVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: "thing2", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "attrPrefix", }, "attr2": { Value: "attr2NewName", Enum: []string{"val1", "val2"}, }, "attr3": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, { Name: "attr2", Value: "val2", }, { Name: "attr3", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "12_indexed_metrics_w_all_attrs_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed attribute scrape error does not create metric datapoints", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientErr := errors.New("problem getting data") columnOID := ".1" oid1 := ".1.1" oid2 := ".1.2" snmpData0 := SNMPData{ columnOID: columnOID, oid: oid1, value: int64(1), valueType: integerVal, } snmpData1 := SNMPData{ columnOID: columnOID, oid: oid2, value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Run( func(args mock.Arguments) { scraperErrors := args.Get(1).(*scrapererror.ScrapeErrors) scraperErrors.AddPartial(1, clientErr) }, ).Return([]SNMPData{}).Once() metricName := "metric1" innerInnerErr := errors.New(errMsgAttributeEmptyValue) innerErr := fmt.Errorf(errMsgOIDAttributeEmptyValue, metricName, innerInnerErr) expectedErr1 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid1, columnOID, innerErr) expectedErr2 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid2, columnOID, innerErr) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, fmt.Sprintf("%s; %s; %s", clientErr, expectedErr1, expectedErr2)) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Indexed attribute scrape returning bad value type does not create metric data points", testFunc: func(t *testing.T) { mockClient := new(MockClient) columnOID1 := ".0" columnOID2 := ".1" oid1 := ".0.1" oid2 := ".0.2" oid3 := ".1.1" oid4 := ".1.2" metricName := "metric1" snmpData0 := SNMPData{ columnOID: columnOID1, oid: oid1, value: true, valueType: notSupportedVal, } snmpData1 := SNMPData{ columnOID: columnOID1, oid: oid2, value: false, valueType: notSupportedVal, } snmpData2 := SNMPData{ columnOID: columnOID2, oid: oid3, value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: columnOID2, oid: oid4, value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) innerErr1 := fmt.Errorf(errMsgIndexedAttributesBadValueType, oid1, columnOID1) expectedErr1 := fmt.Errorf(errMsgIndexedAttributeOIDProcessing, oid1, columnOID1, innerErr1) innerErr2 := fmt.Errorf(errMsgIndexedAttributesBadValueType, oid2, columnOID1) expectedErr2 := fmt.Errorf(errMsgIndexedAttributeOIDProcessing, oid2, columnOID1, innerErr2) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() innerInnerErr := errors.New(errMsgAttributeEmptyValue) innerErr := fmt.Errorf(errMsgOIDAttributeEmptyValue, metricName, innerInnerErr) expectedErr3 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid3, columnOID2, innerErr) expectedErr4 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid4, columnOID2, innerErr) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, fmt.Sprintf("%s; %s; %s; %s", expectedErr1, expectedErr2, expectedErr3, expectedErr4)) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Indexed scrape for metric and attributes creates a metric with indexed attributes (13)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: "thing1", valueType: stringVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: "thing2", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "13_indexed_metrics_w_column_oid_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed metric scrape with non '.' prefixed OID for attribute still creates metric (13)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: "thing1", valueType: stringVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: "thing2", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { OID: "0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: "1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "13_indexed_metrics_w_column_oid_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "SNMP float value for indexed attribute still creates metric (14)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: 1.11111111, valueType: floatVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: 2.22222222, valueType: floatVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "14_indexed_column_oid_float_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "SNMP integer value for indexed attribute still creates metric (15)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: int64(1), valueType: integerVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: int64(2), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "15_indexed_column_oid_int_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Resource attribute with prefix creates new resources with created metrics (16)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData1 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } snmpData2 := SNMPData{ columnOID: ".2", oid: ".2.1", value: float64(1.0), valueType: floatVal, } snmpData3 := SNMPData{ columnOID: ".2", oid: ".2.2", value: float64(2.0), valueType: floatVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0, snmpData1, snmpData2, snmpData3}) scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { IndexedValuePrefix: "thing", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", ResourceAttributes: []string{"rattr1"}, }, }, }, "metric2": { Description: "test description2", Unit: "{units}", Gauge: &GaugeMetric{ ValueType: "double", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "16_indexed_prefix_res_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed resource attribute scrape error will not create metrics or resources", testFunc: func(t *testing.T) { mockClient := new(MockClient) clientErr := errors.New("problem getting data") columnOID := ".1" oid1 := ".1.1" oid2 := ".1.2" metricName := "metric1" snmpData0 := SNMPData{ columnOID: columnOID, oid: oid1, value: int64(1), valueType: integerVal, } snmpData1 := SNMPData{ columnOID: columnOID, oid: oid2, value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Run( func(args mock.Arguments) { scraperErrors := args.Get(1).(*scrapererror.ScrapeErrors) scraperErrors.AddPartial(1, clientErr) }, ).Return([]SNMPData{}).Once() innerInnerErr := errors.New(errMsgResourceAttributeEmptyValue) innerErr := fmt.Errorf(errMsgOIDResourceAttributeEmptyValue, metricName, innerInnerErr) expectedErr1 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid1, columnOID, innerErr) expectedErr2 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid2, columnOID, innerErr) mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, fmt.Sprintf("%s; %s; %s", clientErr, expectedErr1, expectedErr2)) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Indexed resource attribute scrape returning bad value type will not create metrics or resources", testFunc: func(t *testing.T) { mockClient := new(MockClient) columnOID1 := ".0" columnOID2 := ".1" oid1 := ".0.1" oid2 := ".0.2" oid3 := ".1.1" oid4 := ".1.2" metricName := "metric1" snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: true, valueType: notSupportedVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: false, valueType: notSupportedVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) innerErr1 := fmt.Errorf(errMsgIndexedAttributesBadValueType, oid1, columnOID1) expectedErr1 := fmt.Errorf(errMsgIndexedAttributeOIDProcessing, oid1, columnOID1, innerErr1) innerErr2 := fmt.Errorf(errMsgIndexedAttributesBadValueType, oid2, columnOID1) expectedErr2 := fmt.Errorf(errMsgIndexedAttributeOIDProcessing, oid2, columnOID1, innerErr2) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() innerInnerErr := errors.New(errMsgResourceAttributeEmptyValue) innerErr := fmt.Errorf(errMsgOIDResourceAttributeEmptyValue, metricName, innerInnerErr) expectedErr3 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid3, columnOID2, innerErr) expectedErr4 := fmt.Errorf(errMsgIndexedMetricOIDProcessing, oid4, columnOID2, innerErr) mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } metrics, err := scraper.scrape(context.Background()) require.EqualError(t, err, fmt.Sprintf("%s; %s; %s; %s", expectedErr1, expectedErr2, expectedErr3, expectedErr4)) require.Equal(t, metrics.MetricCount(), 0) }, }, { desc: "Resource attribute with column OID creates new resource with multiple metrics (17)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: "thing1", valueType: stringVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: "thing2", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } snmpData4 := SNMPData{ columnOID: ".2", oid: ".2.1", value: float64(1.0), valueType: floatVal, } snmpData5 := SNMPData{ columnOID: ".2", oid: ".2.2", value: float64(2.0), valueType: floatVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData2, snmpData3, snmpData4, snmpData5}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { OID: ".0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", ResourceAttributes: []string{"rattr1"}, }, }, }, "metric2": { Description: "test description2", Unit: "{units}", Gauge: &GaugeMetric{ ValueType: "double", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "17_indexed_oid_res_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Resource attribute with column OID without . prefix still creates metrics (17)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: "thing1", valueType: stringVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: "thing2", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } snmpData4 := SNMPData{ columnOID: ".2", oid: ".2.1", value: float64(1.0), valueType: floatVal, } snmpData5 := SNMPData{ columnOID: ".2", oid: ".2.2", value: float64(2.0), valueType: floatVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", mock.Anything, mock.Anything).Return([]SNMPData{snmpData2, snmpData3, snmpData4, snmpData5}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { OID: "0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: "1", ResourceAttributes: []string{"rattr1"}, }, }, }, "metric2": { Description: "test description2", Unit: "{units}", Gauge: &GaugeMetric{ ValueType: "double", }, ColumnOIDs: []ColumnOID{ { OID: "2", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "17_indexed_oid_res_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Indexed config with both column OID and prefix resource attributes creates metric (18)", testFunc: func(t *testing.T) { mockClient := new(MockClient) snmpData0 := SNMPData{ columnOID: ".0", oid: ".0.1", value: "thing1", valueType: stringVal, } snmpData1 := SNMPData{ columnOID: ".0", oid: ".0.2", value: "thing2", valueType: stringVal, } snmpData2 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } snmpData3 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetIndexedData", []string{".0"}, mock.Anything).Return([]SNMPData{snmpData0, snmpData1}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{snmpData2, snmpData3}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { OID: ".0", }, "rattr2": { IndexedValuePrefix: "object", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".1", ResourceAttributes: []string{"rattr1", "rattr2"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "18_indexed_oid_and_prefix_res_attr_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (string) resource attribute attached to ColumnOID metric alongside a ColumnOID (string) resource attribute creates metric (19)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".0", value: "scalar", valueType: stringVal, } coidRA11 := SNMPData{ columnOID: ".1", oid: ".1.1", value: "string1", valueType: stringVal, } coidRA12 := SNMPData{ columnOID: ".1", oid: ".1.2", value: "string2", valueType: stringVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{coidRA11, coidRA12}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".0", }, "rattr2": { OID: ".1", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1", "rattr2"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "19_scalar_ra_string_and_coid_ra_string_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (int) resource attribute attached to ColumnOID metric alongside a ColumnOID (int) resource attribute creates metric (20)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".0", value: int64(5), valueType: integerVal, } coidRA11 := SNMPData{ columnOID: ".1", oid: ".1.1", value: int64(1), valueType: integerVal, } coidRA12 := SNMPData{ columnOID: ".1", oid: ".1.2", value: int64(2), valueType: integerVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{coidRA11, coidRA12}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".0", }, "rattr2": { OID: ".1", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1", "rattr2"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "20_scalar_ra_int_and_coid_ra_int_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (float) resource attribute attached to ColumnOID metric alongside a ColumnOID (float) resource attribute creates metric (21)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".0", value: float64(5.0), valueType: floatVal, } coidRA11 := SNMPData{ columnOID: ".1", oid: ".1.1", value: float64(1.0), valueType: floatVal, } coidRA12 := SNMPData{ columnOID: ".1", oid: ".1.2", value: float64(2.0), valueType: floatVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{coidRA11, coidRA12}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".0", }, "rattr2": { OID: ".1", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1", "rattr2"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "21_scalar_ra_float_and_coid_ra_float_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (string) resource attribute attached to ColumnOID metric alongside an IndexedValuePrefix resource attribute creates metric (22)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".0", value: "scalar", valueType: stringVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".0", }, "rattr2": { IndexedValuePrefix: "p", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1", "rattr2"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "22_scalar_ra_string_and_prefix_ra_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Multiple ScalarOID (string) resource attributes attached to ColumnOID metric alongside multiple Column OID (string) resource attributes creates metrics (23)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA1 := SNMPData{ oid: ".5.0", value: "scalar", valueType: stringVal, } scalarRA2 := SNMPData{ oid: ".6.0", value: "also scalar", valueType: stringVal, } coidRA11 := SNMPData{ columnOID: ".1", oid: ".1.1", value: "string1", valueType: stringVal, } coidRA12 := SNMPData{ columnOID: ".1", oid: ".1.2", value: "string2", valueType: stringVal, } coidRA21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: "also a string1", valueType: stringVal, } coidRA22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: "also a string2", valueType: stringVal, } coid31 := SNMPData{ columnOID: ".3", oid: ".3.1", value: int64(3), valueType: integerVal, } coid32 := SNMPData{ columnOID: ".3", oid: ".3.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".5.0", ".6.0"}, mock.Anything).Return([]SNMPData{scalarRA1, scalarRA2}).Once() mockClient.On("GetIndexedData", []string{".1", ".2"}, mock.Anything).Return([]SNMPData{coidRA11, coidRA12, coidRA21, coidRA22}).Once() mockClient.On("GetIndexedData", []string{".3"}, mock.Anything).Return([]SNMPData{coid31, coid32}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".5.0", }, "rattr2": { ScalarOID: ".6.0", }, "rattr3": { OID: ".1", }, "rattr4": { OID: ".2", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".3", ResourceAttributes: []string{"rattr1", "rattr2", "rattr3", "rattr4"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "23_multiple_scalar_oid_string_with_multiple_coid_ra_string_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (string) resource attribute attached to ColumnOID metric alongside a ColumnOID (string) attribute creates metric (24)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".0", value: "scalar", valueType: stringVal, } coidAttr11 := SNMPData{ columnOID: ".1", oid: ".1.1", value: "string1", valueType: stringVal, } coidAttr12 := SNMPData{ columnOID: ".1", oid: ".1.2", value: "string2", valueType: stringVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{coidAttr11, coidAttr12}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".0", }, }, Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".1", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1"}, Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "24_scalar_ra_string_and_coid_attr_string_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (string) resource attribute attached to ColumnOID metric alongside an Indexed Value Prefix attribute creates metric (25)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".0", value: "scalar", valueType: stringVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".0", }, }, Attributes: map[string]*AttributeConfig{ "attr1": { IndexedValuePrefix: "prefix", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1"}, Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "25_scalar_ra_string_and_ivp_attr_on_coid_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "ScalarOID (string) resource attribute attached to ScalarOID metric creates metric (26)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".5.0", value: "scalar", valueType: stringVal, } scalarOID := SNMPData{ oid: ".6.0", value: int64(6), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".5.0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetScalarData", []string{".6.0"}, mock.Anything).Return([]SNMPData{scalarOID}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".5.0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".6.0", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "26_scalar_ra_string_on_scalar_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Multiple ScalarOID (string) resource attributes attached to ScalarOID metric creates single resource for metric (27)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA1 := SNMPData{ oid: ".5.0", value: "scalar", valueType: stringVal, } scalarRA2 := SNMPData{ oid: ".7.0", value: "also scalar", valueType: stringVal, } scalarOID := SNMPData{ oid: ".6.0", value: int64(6), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".5.0", ".7.0"}, mock.Anything).Return([]SNMPData{scalarRA1, scalarRA2}).Once() mockClient.On("GetScalarData", []string{".6.0"}, mock.Anything).Return([]SNMPData{scalarOID}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".5.0", }, "rattr2": { ScalarOID: ".7.0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".6.0", ResourceAttributes: []string{"rattr1", "rattr2"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "27_multiple_scalar_ra_string_on_scalar_metric_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Two scalar oid metrics with the same resource attribute get added to a single resource (28)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA := SNMPData{ oid: ".5.0", value: "scalar", valueType: stringVal, } scalarOID1 := SNMPData{ oid: ".6.0", value: int64(6), valueType: integerVal, } scalarOID2 := SNMPData{ oid: ".7.0", value: int64(7), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".5.0"}, mock.Anything).Return([]SNMPData{scalarRA}).Once() mockClient.On("GetScalarData", []string{".6.0", ".7.0"}, mock.Anything).Return([]SNMPData{scalarOID1, scalarOID2}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".5.0", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".6.0", ResourceAttributes: []string{"rattr1"}, }, }, }, "metric2": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ScalarOIDs: []ScalarOID{ { OID: ".7.0", ResourceAttributes: []string{"rattr1"}, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "28_two_scalar_oid_metrics_with_same_resource_attribute_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, { desc: "Metric does not use all available scalar RAs and still behaves properly (near copy of (24)) (29)", testFunc: func(t *testing.T) { mockClient := new(MockClient) scalarRA1 := SNMPData{ oid: ".5.0", value: "scalar", valueType: stringVal, } scalarRA2 := SNMPData{ oid: ".6.0", value: "also scalar", valueType: stringVal, } coidAttr11 := SNMPData{ columnOID: ".1", oid: ".1.1", value: "string1", valueType: stringVal, } coidAttr12 := SNMPData{ columnOID: ".1", oid: ".1.2", value: "string2", valueType: stringVal, } coid21 := SNMPData{ columnOID: ".2", oid: ".2.1", value: int64(3), valueType: integerVal, } coid22 := SNMPData{ columnOID: ".2", oid: ".2.2", value: int64(4), valueType: integerVal, } mockClient.On("Connect").Return(nil) mockClient.On("Close").Return(nil) mockClient.On("GetScalarData", []string{".5.0", ".6.0"}, mock.Anything).Return([]SNMPData{scalarRA1, scalarRA2}).Once() mockClient.On("GetIndexedData", []string{".1"}, mock.Anything).Return([]SNMPData{coidAttr11, coidAttr12}).Once() mockClient.On("GetIndexedData", []string{".2"}, mock.Anything).Return([]SNMPData{coid21, coid22}).Once() scraper := &snmpScraper{ cfg: &Config{ ResourceAttributes: map[string]*ResourceAttributeConfig{ "rattr1": { ScalarOID: ".5.0", }, "rattr2": { ScalarOID: ".6.0", }, }, Attributes: map[string]*AttributeConfig{ "attr1": { OID: ".1", }, }, Metrics: map[string]*MetricConfig{ "metric1": { Description: "test description", Unit: "By", Gauge: &GaugeMetric{ ValueType: "int", }, ColumnOIDs: []ColumnOID{ { OID: ".2", ResourceAttributes: []string{"rattr1"}, Attributes: []Attribute{ { Name: "attr1", }, }, }, }, }, }, }, settings: receivertest.NewNopCreateSettings(), client: mockClient, logger: zap.NewNop(), } expectedMetricGen := func(t *testing.T) pmetric.Metrics { goldenPath := filepath.Join("testdata", "expected_metrics", "29_metric_does_not_use_all_available_scalar_RAs_golden.yaml") expectedMetrics, err := golden.ReadMetrics(goldenPath) require.NoError(t, err) return expectedMetrics } expectedMetrics := expectedMetricGen(t) metrics, err := scraper.scrape(context.Background()) require.NoError(t, err) err = pmetrictest.CompareMetrics(expectedMetrics, metrics, pmetrictest.IgnoreTimestamp()) require.NoError(t, err) }, }, } for _, tc := range testCases { t.Run(tc.desc, tc.testFunc) } }