github.com/m3db/m3@v1.5.0/src/cmd/services/m3coordinator/downsample/metrics_appender_test.go (about) 1 // Copyright (c) 2020 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package downsample 22 23 import ( 24 "errors" 25 "fmt" 26 "testing" 27 28 "github.com/m3db/m3/src/aggregator/aggregator" 29 "github.com/m3db/m3/src/metrics/matcher" 30 "github.com/m3db/m3/src/metrics/metadata" 31 "github.com/m3db/m3/src/metrics/metric/id" 32 "github.com/m3db/m3/src/metrics/metric/unaggregated" 33 "github.com/m3db/m3/src/metrics/rules" 34 "github.com/m3db/m3/src/x/checked" 35 "github.com/m3db/m3/src/x/pool" 36 "github.com/m3db/m3/src/x/serialize" 37 xtest "github.com/m3db/m3/src/x/test" 38 xtime "github.com/m3db/m3/src/x/time" 39 40 "github.com/golang/mock/gomock" 41 "github.com/stretchr/testify/assert" 42 "github.com/stretchr/testify/require" 43 "github.com/uber-go/tally" 44 ) 45 46 func TestSamplesAppenderPoolResetsTagsAcrossSamples(t *testing.T) { 47 ctrl := xtest.NewController(t) 48 defer ctrl.Finish() 49 50 count := 3 51 52 poolOpts := pool.NewObjectPoolOptions().SetSize(1) 53 54 tagEncoderPool := serialize.NewTagEncoderPool(serialize.NewTagEncoderOptions(), 55 poolOpts) 56 tagEncoderPool.Init() 57 58 size := 1 59 tagDecoderPool := serialize.NewTagDecoderPool( 60 serialize.NewTagDecoderOptions(serialize.TagDecoderOptionsConfig{ 61 CheckBytesWrapperPoolSize: &size, 62 }), poolOpts) 63 tagDecoderPool.Init() 64 65 appenderPool := newMetricsAppenderPool(poolOpts, serialize.NewTagSerializationLimits(), defaultMetricNameTagName) 66 67 for i := 0; i < count; i++ { 68 matcher := matcher.NewMockMatcher(ctrl) 69 matcher.EXPECT().ForwardMatch(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). 70 DoAndReturn(func(encodedID id.ID, _, _ int64, _ rules.MatchOptions) (rules.MatchResult, error) { 71 // NB: ensure tags are cleared correctly between runs. 72 bs := encodedID.Bytes() 73 74 decoder := tagDecoderPool.Get() 75 decoder.Reset(checked.NewBytes(bs, nil)) 76 77 var id string 78 for decoder.Next() { 79 tag := decoder.Current() 80 tagStr := fmt.Sprintf("%s-%s", tag.Name.String(), tag.Value.String()) 81 if len(id) == 0 { 82 id = tagStr 83 } else { 84 id = fmt.Sprintf("%s,%s", id, tagStr) 85 } 86 } 87 88 decoder.Close() 89 return rules.NewMatchResult(1, 1, 90 metadata.StagedMetadatas{}, 91 []rules.IDWithMetadatas{ 92 { 93 ID: []byte(id), 94 Metadatas: metadata.StagedMetadatas{}, 95 }, 96 }, 97 true, 98 ), nil 99 }) 100 101 appender := appenderPool.Get() 102 agg := aggregator.NewMockAggregator(ctrl) 103 appender.reset(metricsAppenderOptions{ 104 tagEncoderPool: tagEncoderPool, 105 matcher: matcher, 106 agg: agg, 107 metrics: metricsAppenderMetrics{ 108 processedCountNonRollup: tally.NoopScope.Counter("test-counter-non-rollup"), 109 processedCountRollup: tally.NoopScope.Counter("test-counter-rollup"), 110 operationsCount: tally.NoopScope.Counter("test-counter-operations"), 111 }, 112 }) 113 name := []byte(fmt.Sprint("foo", i)) 114 value := []byte(fmt.Sprint("bar", i)) 115 appender.AddTag(name, value) 116 a, err := appender.SamplesAppender(SampleAppenderOptions{}) 117 require.NoError(t, err) 118 119 agg.EXPECT().AddUntimed(gomock.Any(), gomock.Any()).DoAndReturn( 120 func(u unaggregated.MetricUnion, _ metadata.StagedMetadatas) error { 121 if u.CounterVal != int64(i) { 122 return errors.New("wrong counter value") 123 } 124 125 // NB: expected ID is generated into human-readable form 126 // from tags in ForwardMatch mock above. Also include the m3 type, which is included when matching. 127 // nolint:scopelint 128 expected := fmt.Sprintf("__m3_prom_type__-unknown,__m3_type__-gauge,foo%d-bar%d", i, i) 129 if expected != u.ID.String() { 130 // NB: if this fails, appender is holding state after Finalize. 131 return fmt.Errorf("expected ID %s, got %s", expected, u.ID.String()) 132 } 133 134 return nil 135 }, 136 ) 137 138 require.NoError(t, a.SamplesAppender.AppendUntimedCounterSample(xtime.Now(), int64(i), nil)) 139 140 assert.False(t, a.IsDropPolicyApplied) 141 appender.Finalize() 142 } 143 } 144 145 func TestSamplesAppenderPoolResetsTagSimple(t *testing.T) { 146 ctrl := xtest.NewController(t) 147 defer ctrl.Finish() 148 149 poolOpts := pool.NewObjectPoolOptions().SetSize(1) 150 size := 1 151 tagDecoderPool := serialize.NewTagDecoderPool( 152 serialize.NewTagDecoderOptions(serialize.TagDecoderOptionsConfig{ 153 CheckBytesWrapperPoolSize: &size, 154 }), poolOpts) 155 tagDecoderPool.Init() 156 157 appenderPool := newMetricsAppenderPool(poolOpts, serialize.NewTagSerializationLimits(), defaultMetricNameTagName) 158 159 appender := appenderPool.Get() 160 appender.AddTag([]byte("foo"), []byte("bar")) 161 assert.Equal(t, 1, len(appender.originalTags.names)) 162 assert.Equal(t, 1, len(appender.originalTags.values)) 163 appender.Finalize() 164 165 // NB: getting a new appender from the pool yields a clean appender. 166 appender = appenderPool.Get() 167 assert.Nil(t, appender.originalTags) 168 appender.Finalize() 169 }