github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/block/container_test.go (about) 1 // Copyright (c) 2019 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 block 22 23 import ( 24 "fmt" 25 "testing" 26 "time" 27 28 "github.com/m3db/m3/src/query/models" 29 "github.com/m3db/m3/src/query/ts" 30 xtest "github.com/m3db/m3/src/x/test" 31 xtime "github.com/m3db/m3/src/x/time" 32 33 "github.com/golang/mock/gomock" 34 "github.com/stretchr/testify/assert" 35 "github.com/stretchr/testify/require" 36 ) 37 38 func TestInvalidContainerBlock(t *testing.T) { 39 ctrl := xtest.NewController(t) 40 now := xtime.Now() 41 defer ctrl.Finish() 42 43 _, err := NewContainerBlock() 44 assert.Error(t, err) 45 46 b := NewMockBlock(ctrl) 47 b.EXPECT().Meta().Return(buildMeta(now)).AnyTimes() 48 49 b2 := NewMockBlock(ctrl) 50 b2.EXPECT().Meta().Return(buildMeta(now.Add(100))).AnyTimes() 51 52 _, err = NewContainerBlock(b, b2) 53 require.Error(t, err) 54 55 container, err := NewContainerBlock(b) 56 require.NoError(t, err) 57 58 err = container.AddBlock(b) 59 require.NoError(t, err) 60 61 err = container.AddBlock(b2) 62 require.Error(t, err) 63 } 64 65 var ( 66 opts = models.NewTagOptions() 67 step = time.Second 68 numSteps = 10 69 now = xtime.Now() 70 containerBounds = models.Bounds{ 71 Start: now, 72 StepSize: step, 73 Duration: step * time.Duration(numSteps), 74 } 75 ) 76 77 func TestContainerBlockMergesResultMeta(t *testing.T) { 78 ctrl := xtest.NewController(t) 79 defer ctrl.Finish() 80 81 b := NewMockBlock(ctrl) 82 meta := Metadata{ 83 Tags: models.NewTags(0, models.NewTagOptions()), 84 Bounds: containerBounds, 85 ResultMetadata: ResultMetadata{ 86 Exhaustive: false, 87 LocalOnly: true, 88 }, 89 } 90 91 b.EXPECT().Meta().Return(meta).AnyTimes() 92 93 bTwo := NewMockBlock(ctrl) 94 metaTwo := Metadata{ 95 Tags: models.NewTags(0, models.NewTagOptions()), 96 Bounds: containerBounds, 97 ResultMetadata: ResultMetadata{ 98 Exhaustive: true, 99 LocalOnly: true, 100 Warnings: []Warning{{"foo", "bar"}}, 101 }, 102 } 103 104 bTwo.EXPECT().Meta().Return(metaTwo).AnyTimes() 105 106 container, err := NewContainerBlock(b, bTwo) 107 assert.NoError(t, err) 108 109 resultMeta := container.Meta().ResultMetadata 110 assert.False(t, resultMeta.Exhaustive) 111 assert.True(t, resultMeta.LocalOnly) 112 assert.Equal(t, 1, len(resultMeta.Warnings)) 113 } 114 115 func buildStepBlock(ctrl *gomock.Controller, v float64, first bool) Block { 116 b := NewMockBlock(ctrl) 117 meta := Metadata{ 118 Tags: models.NewTags(0, models.NewTagOptions()), 119 Bounds: containerBounds, 120 } 121 122 b.EXPECT().Meta().Return(meta) 123 it := NewMockStepIter(ctrl) 124 it.EXPECT().Close() 125 it.EXPECT().Err().Return(nil).AnyTimes() 126 it.EXPECT().Next().Return(true).Times(numSteps) 127 it.EXPECT().Next().Return(false) 128 for i := 0; i < numSteps; i++ { 129 s := NewMockStep(ctrl) 130 if first { 131 s.EXPECT().Time().Return(now.Add(time.Duration(i) * step)) 132 } 133 134 s.EXPECT().Values().Return([]float64{v}) 135 it.EXPECT().Current().Return(s) 136 } 137 138 it.EXPECT().SeriesMeta(). 139 Return([]SeriesMeta{{Name: []byte(fmt.Sprint(v))}}).Times(2) 140 if first { 141 it.EXPECT().StepCount().Return(numSteps) 142 } 143 144 b.EXPECT().StepIter().Return(it, nil) 145 return b 146 } 147 148 func TestContainerStepIter(t *testing.T) { 149 ctrl := xtest.NewController(t) 150 defer ctrl.Finish() 151 152 block := buildStepBlock(ctrl, 1, true) 153 blockTwo := buildStepBlock(ctrl, 2, false) 154 155 container, err := NewContainerBlock(block, blockTwo) 156 require.NoError(t, err) 157 158 assert.True(t, containerBounds.Equals(container.Meta().Bounds)) 159 assert.True(t, opts.Equals(container.Meta().Tags.Opts)) 160 161 it, err := container.StepIter() 162 require.NoError(t, err) 163 164 count := 0 165 ex := []float64{1, 2} 166 for it.Next() { 167 st := it.Current() 168 assert.Equal(t, ex, st.Values()) 169 assert.Equal(t, now.Add(step*time.Duration(count)), st.Time()) 170 count++ 171 } 172 173 assert.Equal(t, count, numSteps) 174 175 metas := it.SeriesMeta() 176 assert.Equal(t, 2, len(metas)) 177 assert.Equal(t, []byte("1"), metas[0].Name) 178 assert.Equal(t, []byte("2"), metas[1].Name) 179 assert.Equal(t, numSteps, it.StepCount()) 180 181 assert.NoError(t, it.Err()) 182 assert.NotPanics(t, func() { it.Close() }) 183 } 184 185 func buildUnconsolidatedSeriesBlock(ctrl *gomock.Controller, 186 v float64, first bool) Block { 187 b := NewMockBlock(ctrl) 188 189 meta := Metadata{ 190 Tags: models.NewTags(0, models.NewTagOptions()), 191 Bounds: containerBounds, 192 } 193 194 b.EXPECT().Meta().Return(meta).AnyTimes() 195 it := NewMockSeriesIter(ctrl) 196 it.EXPECT().Close() 197 it.EXPECT().Err().Return(nil).AnyTimes() 198 it.EXPECT().Next().Return(true) 199 it.EXPECT().Next().Return(false) 200 vals := make(ts.Datapoints, 0, numSteps) 201 for i := 0; i < numSteps; i++ { 202 tt := now.Add(time.Duration(i) * step) 203 vals = append(vals, 204 ts.Datapoint{Timestamp: tt, Value: v}, 205 ts.Datapoint{Timestamp: tt, Value: v}, 206 ) 207 } 208 209 it.EXPECT().Current().Return(UnconsolidatedSeries{ 210 datapoints: vals, 211 Meta: SeriesMeta{Name: []byte(fmt.Sprint(v))}, 212 }) 213 214 it.EXPECT().SeriesMeta(). 215 Return([]SeriesMeta{{Name: []byte(fmt.Sprint(v))}}).Times(2) 216 b.EXPECT().SeriesIter().Return(it, nil) 217 return b 218 } 219 220 func buildExpected(v float64) ts.Datapoints { 221 expected := make(ts.Datapoints, 0, numSteps) 222 for i := 0; i < numSteps; i++ { 223 expected = append(expected, ts.Datapoint{ 224 Timestamp: now.Add(time.Duration(i) * step), 225 Value: float64(v), 226 }, ts.Datapoint{ 227 Timestamp: now.Add(time.Duration(i) * step), 228 Value: float64(v), 229 }) 230 } 231 232 return expected 233 } 234 235 func TestUnconsolidatedContainerSeriesIter(t *testing.T) { 236 ctrl := gomock.NewController(t) 237 defer ctrl.Finish() 238 239 block := buildUnconsolidatedSeriesBlock(ctrl, 1, true) 240 blockTwo := buildUnconsolidatedSeriesBlock(ctrl, 2, false) 241 242 c, err := NewContainerBlock(block, blockTwo) 243 require.NoError(t, err) 244 245 assert.True(t, containerBounds.Equals(c.Meta().Bounds)) 246 assert.True(t, opts.Equals(c.Meta().Tags.Opts)) 247 248 it, err := c.SeriesIter() 249 require.NoError(t, err) 250 251 expected := []ts.Datapoints{buildExpected(1), buildExpected(2)} 252 ex := 0 253 for it.Next() { 254 current := it.Current() 255 assert.Equal(t, expected[ex], current.Datapoints()) 256 ex++ 257 258 assert.Equal(t, []byte(fmt.Sprint(ex)), current.Meta.Name) 259 } 260 261 metas := it.SeriesMeta() 262 assert.Equal(t, 2, len(metas)) 263 assert.Equal(t, []byte("1"), metas[0].Name) 264 assert.Equal(t, []byte("2"), metas[1].Name) 265 266 assert.NoError(t, it.Err()) 267 assert.NotPanics(t, func() { it.Close() }) 268 } 269 270 func buildMultiSeriesBlock( 271 ctrl *gomock.Controller, 272 count int, 273 concurrency int, 274 v float64, 275 ) Block { 276 b := NewMockBlock(ctrl) 277 278 meta := Metadata{ 279 Tags: models.NewTags(0, models.NewTagOptions()), 280 Bounds: containerBounds, 281 } 282 283 b.EXPECT().Meta().Return(meta).AnyTimes() 284 batches := make([]SeriesIterBatch, 0, concurrency) 285 for i := 0; i < count; i++ { 286 it := NewMockSeriesIter(ctrl) 287 it.EXPECT().Close() 288 it.EXPECT().Err().Return(nil).AnyTimes() 289 it.EXPECT().Next().Return(true) 290 it.EXPECT().Next().Return(false) 291 vals := make(ts.Datapoints, 0, numSteps) 292 for i := 0; i < numSteps; i++ { 293 tt := now.Add(time.Duration(i) * step) 294 vals = append(vals, 295 ts.Datapoint{Timestamp: tt, Value: v}, 296 ts.Datapoint{Timestamp: tt, Value: v}, 297 ) 298 } 299 300 it.EXPECT().Current().Return(UnconsolidatedSeries{ 301 datapoints: vals, 302 Meta: SeriesMeta{Name: []byte(fmt.Sprintf("%d_%d", i, int(v)))}, 303 }) 304 305 batches = append(batches, SeriesIterBatch{Iter: it, Size: 1}) 306 } 307 308 b.EXPECT().MultiSeriesIter(concurrency).Return(batches, nil) 309 return b 310 } 311 312 func TestUnconsolidatedContainerMultiSeriesIter(t *testing.T) { 313 ctrl := xtest.NewController(t) 314 defer ctrl.Finish() 315 316 concurrency := 5 317 c, err := NewContainerBlock( 318 buildMultiSeriesBlock(ctrl, 0, concurrency, 1), 319 buildMultiSeriesBlock(ctrl, 4, concurrency, 2), 320 buildMultiSeriesBlock(ctrl, 5, concurrency, 3), 321 buildMultiSeriesBlock(ctrl, 1, concurrency, 4), 322 ) 323 324 require.NoError(t, err) 325 assert.True(t, containerBounds.Equals(c.Meta().Bounds)) 326 assert.True(t, opts.Equals(c.Meta().Tags.Opts)) 327 328 batch, err := c.MultiSeriesIter(concurrency) 329 require.NoError(t, err) 330 require.Equal(t, concurrency, len(batch)) 331 332 expected := [][]ts.Datapoints{ 333 {buildExpected(2), buildExpected(3), buildExpected(4)}, 334 {buildExpected(2), buildExpected(3)}, 335 {buildExpected(2), buildExpected(3)}, 336 {buildExpected(2), buildExpected(3)}, 337 {buildExpected(3)}, 338 } 339 340 expectedNames := []string{ 341 "0_2", "0_3", "0_4", 342 "1_2", "1_3", 343 "2_2", "2_3", 344 "3_2", "3_3", 345 "4_3", 346 } 347 348 n := 0 349 for i, b := range batch { 350 ex := expected[i] 351 assert.Equal(t, len(ex), b.Size) 352 353 i := 0 354 for b.Iter.Next() { 355 current := b.Iter.Current() 356 assert.Equal(t, ex[i], current.Datapoints()) 357 i++ 358 359 assert.Equal(t, expectedNames[n], string(current.Meta.Name)) 360 n++ 361 } 362 } 363 364 for _, b := range batch { 365 assert.NoError(t, b.Iter.Err()) 366 assert.NotPanics(t, func() { b.Iter.Close() }) 367 } 368 }