123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- // Copyright The OpenTelemetry Authors
- // SPDX-License-Identifier: Apache-2.0
- package awsemfexporter
- import (
- "testing"
- "github.com/stretchr/testify/assert"
- "go.opentelemetry.io/collector/pdata/pmetric"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "go.uber.org/zap/zaptest/observer"
- )
- func TestLabelMatcherInit(t *testing.T) {
- lm := &LabelMatcher{
- LabelNames: []string{"label1", "label2"},
- Regex: ".+",
- }
- err := lm.init()
- assert.Nil(t, err)
- assert.Equal(t, ";", lm.Separator)
- assert.Equal(t, ".+", lm.Regex)
- assert.NotNil(t, lm.compiledRegex)
- lm.Separator = ""
- err = lm.init()
- assert.Nil(t, err)
- assert.Equal(t, ";", lm.Separator)
- lm.Separator = ","
- err = lm.init()
- assert.Nil(t, err)
- assert.Equal(t, ",", lm.Separator)
- lm.Regex = "a*"
- err = lm.init()
- assert.Nil(t, err)
- assert.Equal(t, "a*", lm.Regex)
- assert.NotNil(t, lm.compiledRegex)
- // Test error
- lm.Regex = ""
- err = lm.init()
- assert.NotNil(t, err)
- assert.EqualError(t, err, "regex not specified for label matcher")
- lm.LabelNames = []string{}
- lm.Regex = ".+"
- err = lm.init()
- assert.NotNil(t, err)
- assert.EqualError(t, err, "label matcher must have at least one label name specified")
- }
- func TestGetConcatenatedLabels(t *testing.T) {
- labels := map[string]string{
- "label1": "a",
- "label2": "b",
- "label3": "c",
- }
- testCases := []struct {
- testName string
- labelNames []string
- separator string
- expected string
- }{
- {
- "Single label w/ default separator",
- []string{"label1"},
- "",
- "a",
- },
- {
- "Multiple labels w/ default separator",
- []string{"label1", "label3", "label2"},
- "",
- "a;c;b",
- },
- {
- "Single label w/ custom separator",
- []string{"label1"},
- ",",
- "a",
- },
- {
- "Multiple labels w/ custom separator",
- []string{"label1", "label3", "label2"},
- ",",
- "a,c,b",
- },
- {
- "Multiple labels w/ missing label",
- []string{"label1", "label4", "label2"},
- "",
- "a;;b",
- },
- }
- for _, tc := range testCases {
- lm := &LabelMatcher{
- LabelNames: tc.labelNames,
- Separator: tc.separator,
- Regex: ".+",
- }
- err := lm.init()
- assert.Nil(t, err)
- t.Run(tc.testName, func(t *testing.T) {
- concatenatedLabels := lm.getConcatenatedLabels(labels)
- assert.Equal(t, tc.expected, concatenatedLabels)
- })
- }
- }
- func TestLabelMatcherMatches(t *testing.T) {
- testCases := []struct {
- testName string
- labels map[string]string
- labelMatcher *LabelMatcher
- expected bool
- }{
- {
- "Single label",
- map[string]string{
- "label1": "foo",
- },
- &LabelMatcher{
- LabelNames: []string{"label1"},
- Regex: "^fo+$",
- },
- true,
- },
- {
- "Single label, no match",
- map[string]string{
- "label1": "foo",
- },
- &LabelMatcher{
- LabelNames: []string{"label1"},
- Regex: "^f+$",
- },
- false,
- },
- {
- "Single label w/ missing label name",
- map[string]string{
- "label1": "foo",
- },
- &LabelMatcher{
- LabelNames: []string{"label2"},
- Regex: ".+",
- },
- false,
- },
- {
- "Multiple labels",
- map[string]string{
- "label1": "foo",
- "label2": "bar",
- "label3": "car",
- },
- &LabelMatcher{
- LabelNames: []string{"label1", "label3", "label2"},
- Regex: "fo+;car;b.*$",
- },
- true,
- },
- {
- "Multiple labels w/ custom separator",
- map[string]string{
- "label1": "foo",
- "label2": "bar",
- "label3": "car",
- },
- &LabelMatcher{
- LabelNames: []string{"label1", "label3", "label2"},
- Separator: ",",
- Regex: "fo+,car,b.*$",
- },
- true,
- },
- {
- "Multiple labels, no match",
- map[string]string{
- "label1": "foo",
- "label2": "bar",
- "label3": "car",
- },
- &LabelMatcher{
- LabelNames: []string{"label1", "label3", "label2"},
- Separator: ",",
- Regex: "fo+;car;b.*$",
- },
- false,
- },
- {
- "Multiple labels w/ missing label name",
- map[string]string{
- "label1": "foo",
- "label2": "bar",
- "label3": "car",
- },
- &LabelMatcher{
- LabelNames: []string{"label1", "label4", "label2"},
- Regex: "fo+;;b.*$",
- },
- true,
- },
- }
- for _, tc := range testCases {
- err := tc.labelMatcher.init()
- assert.Nil(t, err)
- t.Run(tc.testName, func(t *testing.T) {
- matches := tc.labelMatcher.Matches(tc.labels)
- assert.Equal(t, tc.expected, matches)
- })
- }
- }
- func TestMetricDeclarationInit(t *testing.T) {
- logger := zap.NewNop()
- t.Run("no dimensions", func(t *testing.T) {
- m := &MetricDeclaration{
- MetricNameSelectors: []string{"a", "b", "aa"},
- }
- err := m.init(logger)
- assert.Nil(t, err)
- assert.Equal(t, 3, len(m.metricRegexList))
- })
- t.Run("with dimensions", func(t *testing.T) {
- m := &MetricDeclaration{
- Dimensions: [][]string{
- {"foo"},
- {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
- },
- MetricNameSelectors: []string{"a.*", "b$", "aa+"},
- }
- err := m.init(logger)
- assert.Nil(t, err)
- assert.Equal(t, 3, len(m.metricRegexList))
- assert.Equal(t, 2, len(m.Dimensions))
- })
- // Test removal of dimension sets with more than 10 elements
- t.Run("dimension set with more than 10 elements", func(t *testing.T) {
- m := &MetricDeclaration{
- Dimensions: [][]string{
- {"foo"},
- {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"},
- },
- MetricNameSelectors: []string{"a.*", "b$", "aa+"},
- }
- obs, logs := observer.New(zap.WarnLevel)
- obsLogger := zap.New(obs)
- err := m.init(obsLogger)
- assert.Nil(t, err)
- assert.Equal(t, 3, len(m.metricRegexList))
- assert.Equal(t, 1, len(m.Dimensions))
- // Check logged warning message
- expectedLogs := []observer.LoggedEntry{{
- Entry: zapcore.Entry{Level: zap.WarnLevel, Message: "Dropped dimension set: > 10 dimensions specified."},
- Context: []zapcore.Field{zap.String("dimensions", "a,b,c,d,e,f,g,h,i,j,k")},
- }}
- assert.Equal(t, 1, logs.Len())
- assert.Equal(t, expectedLogs, logs.AllUntimed())
- })
- // Test removal of duplicate dimensions within a dimension set, and removal of
- // duplicate dimension sets
- t.Run("remove duplicate dimensions and dimension sets", func(t *testing.T) {
- m := &MetricDeclaration{
- Dimensions: [][]string{
- {"a", "c", "b", "c"},
- {"c", "b", "a"},
- },
- MetricNameSelectors: []string{"a.*", "b$", "aa+"},
- }
- obs, logs := observer.New(zap.DebugLevel)
- obsLogger := zap.New(obs)
- err := m.init(obsLogger)
- assert.Nil(t, err)
- assert.Equal(t, 1, len(m.Dimensions))
- assert.Equal(t, []string{"a", "b", "c"}, m.Dimensions[0])
- // Check logged warning message
- expectedLogs := []observer.LoggedEntry{
- {
- Entry: zapcore.Entry{Level: zap.DebugLevel, Message: "Removed duplicates from dimension set."},
- Context: []zapcore.Field{zap.String("dimensions", "a,c,b,c")},
- },
- {
- Entry: zapcore.Entry{Level: zap.DebugLevel, Message: "Dropped dimension set: duplicated dimension set."},
- Context: []zapcore.Field{zap.String("dimensions", "c,b,a")},
- },
- }
- assert.Equal(t, 2, logs.Len())
- assert.Equal(t, expectedLogs, logs.AllUntimed())
- })
- // Test invalid metric declaration
- t.Run("invalid metric declaration", func(t *testing.T) {
- m := &MetricDeclaration{}
- err := m.init(logger)
- assert.NotNil(t, err)
- assert.EqualError(t, err, "invalid metric declaration: no metric name selectors defined")
- })
- // Test initialization of label matchers
- t.Run("initialization of label matchers", func(t *testing.T) {
- m := &MetricDeclaration{
- MetricNameSelectors: []string{"foo"},
- LabelMatchers: []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label2"},
- Regex: ".+",
- },
- {
- LabelNames: []string{"label1", "label3"},
- Separator: ",",
- Regex: "a*",
- },
- },
- }
- err := m.init(logger)
- assert.Nil(t, err)
- assert.Equal(t, 2, len(m.LabelMatchers))
- assert.Equal(t, ";", m.LabelMatchers[0].Separator)
- assert.Equal(t, ".+", m.LabelMatchers[0].Regex)
- assert.NotNil(t, m.LabelMatchers[0].compiledRegex)
- assert.Equal(t, ",", m.LabelMatchers[1].Separator)
- assert.Equal(t, "a*", m.LabelMatchers[1].Regex)
- assert.NotNil(t, m.LabelMatchers[1].compiledRegex)
- })
- // Test error from label matcher initialization
- t.Run("label matcher init error", func(t *testing.T) {
- m := &MetricDeclaration{
- MetricNameSelectors: []string{"foo"},
- LabelMatchers: []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label2"},
- Regex: ".+",
- },
- {
- LabelNames: []string{},
- Regex: ".+",
- },
- },
- }
- err := m.init(logger)
- assert.NotNil(t, err)
- assert.EqualError(t, err, "label matcher must have at least one label name specified")
- m = &MetricDeclaration{
- MetricNameSelectors: []string{"foo"},
- LabelMatchers: []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label2"},
- },
- },
- }
- err = m.init(logger)
- assert.NotNil(t, err)
- assert.EqualError(t, err, "regex not specified for label matcher")
- })
- }
- func TestMetricDeclarationMatchesName(t *testing.T) {
- m := &MetricDeclaration{
- MetricNameSelectors: []string{"^a+$", "^b.*$", "^ac+a$"},
- }
- logger := zap.NewNop()
- err := m.init(logger)
- assert.Nil(t, err)
- assert.True(t, m.MatchesName("a"))
- assert.True(t, m.MatchesName("aa"))
- assert.True(t, m.MatchesName("aaaa"))
- assert.False(t, m.MatchesName("aaab"))
- assert.True(t, m.MatchesName("b"))
- assert.True(t, m.MatchesName("ba"))
- assert.False(t, m.MatchesName("c"))
- assert.True(t, m.MatchesName("aca"))
- assert.True(t, m.MatchesName("accca"))
- }
- func TestMetricDeclarationMatchesLabels(t *testing.T) {
- labels := map[string]string{
- "label1": "foo",
- "label2": "bar",
- "label3": "car",
- }
- testCases := []struct {
- testName string
- labelMatchers []*LabelMatcher
- expected bool
- }{
- {
- "Single label",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1"},
- Regex: "^fo+$",
- },
- },
- true,
- },
- {
- "Multiple matchers w/ single label",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1"},
- Regex: "food",
- },
- {
- LabelNames: []string{"label3"},
- Regex: "^c.*$",
- },
- },
- true,
- },
- {
- "Multiple matchers w/ single label, no match",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1"},
- Regex: "food",
- },
- {
- LabelNames: []string{"label3"},
- Regex: "cat",
- },
- },
- false,
- },
- {
- "Multiple labels",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label3", "label2"},
- Regex: "fo+;car;b.*$",
- },
- },
- true,
- },
- {
- "Multiple labels w/ custom separator",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label3", "label2"},
- Separator: ",",
- Regex: "fo+,car,b.*$",
- },
- },
- true,
- },
- {
- "Multiple matchers w/ multiple labels",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label3", "label2"},
- Separator: ",",
- Regex: "fo+,car,b.*$",
- },
- {
- LabelNames: []string{"label3"},
- Regex: "fat",
- },
- },
- true,
- },
- {
- "Multiple matchers w/ multiple labels, no match",
- []*LabelMatcher{
- {
- LabelNames: []string{"label1", "label3", "label2"},
- Separator: ",",
- Regex: "fo+,cat,b.*$",
- },
- {
- LabelNames: []string{"label3"},
- Regex: "fat",
- },
- },
- false,
- },
- }
- logger := zap.NewNop()
- metric := pmetric.NewMetric()
- metric.SetName("a")
- for _, tc := range testCases {
- m := MetricDeclaration{
- MetricNameSelectors: []string{"^a+$"},
- LabelMatchers: tc.labelMatchers,
- }
- t.Run(tc.testName, func(t *testing.T) {
- err := m.init(logger)
- assert.Nil(t, err)
- matches := m.MatchesLabels(labels)
- assert.Equal(t, tc.expected, matches)
- })
- }
- }
- func TestExtractDimensions(t *testing.T) {
- testCases := []struct {
- testName string
- dimensions [][]string
- labels map[string]string
- extractedDimensions [][]string
- }{
- {
- "matches single dimension set exactly",
- [][]string{{"a", "b"}},
- map[string]string{
- "a": "foo",
- "b": "bar",
- },
- [][]string{{"a", "b"}},
- },
- {
- "matches subset of single dimension set",
- [][]string{{"a"}},
- map[string]string{
- "a": "foo",
- "b": "bar",
- },
- [][]string{{"a"}},
- },
- {
- "does not match single dimension set",
- [][]string{{"a", "b"}},
- map[string]string{
- "b": "bar",
- },
- nil,
- },
- {
- "matches multiple dimension sets",
- [][]string{{"a", "b"}, {"a"}},
- map[string]string{
- "a": "foo",
- "b": "bar",
- },
- [][]string{{"a", "b"}, {"a"}},
- },
- {
- "matches one of multiple dimension sets",
- [][]string{{"a", "b"}, {"a"}},
- map[string]string{
- "a": "foo",
- },
- [][]string{{"a"}},
- },
- {
- "no dimensions",
- [][]string{},
- map[string]string{
- "a": "foo",
- },
- nil,
- },
- {
- "empty dimension set",
- [][]string{{}},
- map[string]string{
- "a": "foo",
- },
- [][]string{{}},
- },
- }
- logger := zap.NewNop()
- for _, tc := range testCases {
- m := MetricDeclaration{
- Dimensions: tc.dimensions,
- MetricNameSelectors: []string{"foo"},
- }
- t.Run(tc.testName, func(t *testing.T) {
- err := m.init(logger)
- assert.Nil(t, err)
- dimensions := m.ExtractDimensions(tc.labels)
- assert.Equal(t, tc.extractedDimensions, dimensions)
- })
- }
- }
|