github.com/m3db/m3@v1.5.0/src/query/block/lazy_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 "errors" 25 "testing" 26 "time" 27 28 "github.com/m3db/m3/src/query/models" 29 "github.com/m3db/m3/src/query/ts" 30 xtime "github.com/m3db/m3/src/x/time" 31 32 "github.com/golang/mock/gomock" 33 "github.com/stretchr/testify/assert" 34 "github.com/stretchr/testify/require" 35 ) 36 37 func buildMeta(start xtime.UnixNano) Metadata { 38 return buildMetaExhaustive(start, false) 39 } 40 41 func buildMetaExhaustive(start xtime.UnixNano, exhaustive bool) Metadata { 42 return Metadata{ 43 Bounds: models.Bounds{ 44 Start: start, 45 Duration: time.Minute, 46 StepSize: time.Hour, 47 }, 48 Tags: models.NewTags(0, models.NewTagOptions()), 49 ResultMetadata: ResultMetadata{Exhaustive: exhaustive}, 50 } 51 } 52 53 func buildTestSeriesMeta(name string) []SeriesMeta { 54 tags := models.NewTags(1, models.NewTagOptions()). 55 AddTag(models.Tag{Name: []byte("a"), Value: []byte("b")}) 56 return []SeriesMeta{ 57 SeriesMeta{ 58 Name: []byte(name), 59 Tags: tags, 60 }, 61 } 62 63 } 64 65 func testLazyOpts(timeOffset time.Duration, valOffset float64) LazyOptions { 66 tt := func(t xtime.UnixNano) xtime.UnixNano { return t.Add(timeOffset) } 67 vt := func(val float64) float64 { return val * valOffset } 68 mt := func(meta Metadata) Metadata { 69 meta.Bounds.Start = meta.Bounds.Start.Add(timeOffset) 70 return meta 71 } 72 73 smt := func(sm []SeriesMeta) []SeriesMeta { 74 for i, m := range sm { 75 sm[i].Name = append(m.Name, []byte("_mutated")...) 76 } 77 78 return sm 79 } 80 81 return NewLazyOptions(). 82 SetTimeTransform(tt). 83 SetValueTransform(vt). 84 SetMetaTransform(mt). 85 SetSeriesMetaTransform(smt) 86 } 87 88 func TestLazyOpts(t *testing.T) { 89 off := time.Minute 90 lazyOpts := testLazyOpts(off, 1.0) 91 92 now := xtime.Now() 93 equalTimes := lazyOpts.TimeTransform()(now).Equal(now.Add(off)) 94 assert.True(t, equalTimes) 95 96 meta := buildMeta(now) 97 updated := lazyOpts.MetaTransform()(meta) 98 expected := buildMeta(now.Add(off)) 99 require.Equal(t, expected, updated) 100 101 seriesMeta := buildTestSeriesMeta("name") 102 expectSM := buildTestSeriesMeta("name_mutated") 103 require.Equal(t, expectSM, lazyOpts.SeriesMetaTransform()(seriesMeta)) 104 105 require.Equal(t, 1.0, lazyOpts.ValueTransform()(1.0)) 106 } 107 108 func TestValidOffset(t *testing.T) { 109 ctrl := gomock.NewController(t) 110 defer ctrl.Finish() 111 b := NewMockBlock(ctrl) 112 offset := time.Minute 113 off := NewLazyBlock(b, testLazyOpts(offset, 1.0)) 114 115 b.EXPECT().Info().Return(NewBlockInfo(BlockM3TSZCompressed)) 116 info := off.Info() 117 assert.Equal(t, BlockLazy, info.Type()) 118 assert.Equal(t, BlockM3TSZCompressed, info.BaseType()) 119 120 // ensure functions are marshalled to the underlying block. 121 b.EXPECT().Close().Return(nil) 122 err := off.Close() 123 assert.NoError(t, err) 124 125 msg := "err" 126 e := errors.New(msg) 127 b.EXPECT().Close().Return(e) 128 err = off.Close() 129 assert.EqualError(t, err, msg) 130 131 b.EXPECT().StepIter().Return(nil, e) 132 _, err = off.StepIter() 133 assert.EqualError(t, err, msg) 134 135 b.EXPECT().Close().Return(nil) 136 err = off.Close() 137 assert.NoError(t, err) 138 } 139 140 func TestStepIter(t *testing.T) { 141 ctrl := gomock.NewController(t) 142 defer ctrl.Finish() 143 b := NewMockBlock(ctrl) 144 offset := time.Minute 145 off := NewLazyBlock(b, testLazyOpts(offset, 1.0)) 146 msg := "err" 147 e := errors.New(msg) 148 now := xtime.Now() 149 150 b.EXPECT().Meta().Return(buildMeta(now)) 151 ex := buildMeta(now.Add(offset)) 152 require.Equal(t, ex, off.Meta()) 153 154 iter := NewMockStepIter(ctrl) 155 b.EXPECT().StepIter().Return(iter, nil) 156 it, err := off.StepIter() 157 require.NoError(t, err) 158 159 seriesMetas := buildTestSeriesMeta("name") 160 expected := buildTestSeriesMeta("name_mutated") 161 162 iter.EXPECT().SeriesMeta().Return(seriesMetas) 163 assert.Equal(t, expected, it.SeriesMeta()) 164 165 // ensure functions are marshalled to the block's underlying step iterator. 166 iter.EXPECT().Close() 167 it.Close() 168 169 iter.EXPECT().Err().Return(e) 170 assert.EqualError(t, it.Err(), msg) 171 172 iter.EXPECT().StepCount().Return(12) 173 assert.Equal(t, 12, it.StepCount()) 174 175 iter.EXPECT().Next().Return(true) 176 assert.True(t, it.Next()) 177 178 vals := []float64{1, 2, 3} 179 step := NewMockStep(ctrl) 180 step.EXPECT().Values().Return(vals) 181 step.EXPECT().Time().Return(now) 182 183 iter.EXPECT().Current().Return(step) 184 actual := it.Current() 185 assert.Equal(t, vals, actual.Values()) 186 assert.Equal(t, now.Add(offset), actual.Time()) 187 } 188 189 func TestSeriesIter(t *testing.T) { 190 ctrl := gomock.NewController(t) 191 b := NewMockBlock(ctrl) 192 defer ctrl.Finish() 193 offset := time.Minute 194 offblock := NewLazyBlock(b, testLazyOpts(offset, 1.0)) 195 now := xtime.Now() 196 msg := "err" 197 e := errors.New(msg) 198 199 // ensure functions are marshalled to the underlying unconsolidated block. 200 iter := NewMockSeriesIter(ctrl) 201 b.EXPECT().SeriesIter().Return(iter, nil) 202 it, err := offblock.SeriesIter() 203 require.NoError(t, err) 204 205 seriesMetas := buildTestSeriesMeta("name") 206 expected := buildTestSeriesMeta("name_mutated") 207 208 iter.EXPECT().SeriesMeta().Return(seriesMetas) 209 assert.Equal(t, expected, it.SeriesMeta()) 210 211 // ensure functions are marshalled to the block's underlying series iterator. 212 iter.EXPECT().Close() 213 it.Close() 214 215 iter.EXPECT().Err().Return(e) 216 assert.EqualError(t, it.Err(), msg) 217 218 iter.EXPECT().SeriesCount().Return(12) 219 assert.Equal(t, 12, it.SeriesCount()) 220 221 iter.EXPECT().Next().Return(true) 222 assert.True(t, it.Next()) 223 224 vals := ts.Datapoints{ 225 ts.Datapoint{ 226 Timestamp: now, 227 Value: 12, 228 }, 229 } 230 231 unconsolidated := UnconsolidatedSeries{ 232 datapoints: vals, 233 } 234 235 iter.EXPECT().Current().Return(unconsolidated) 236 actual := it.Current() 237 xts := ts.Datapoints{ 238 ts.Datapoint{ 239 Timestamp: now.Add(offset), 240 Value: 12, 241 }, 242 } 243 244 assert.Equal(t, xts, actual.Datapoints()) 245 } 246 247 // negative value offset tests 248 249 func TestStepIterWithNegativeValueOffset(t *testing.T) { 250 ctrl := gomock.NewController(t) 251 defer ctrl.Finish() 252 b := NewMockBlock(ctrl) 253 offset := time.Duration(0) 254 off := NewLazyBlock(b, testLazyOpts(offset, -1.0)) 255 msg := "err" 256 e := errors.New(msg) 257 now := xtime.Now() 258 259 iter := NewMockStepIter(ctrl) 260 b.EXPECT().StepIter().Return(iter, nil) 261 it, err := off.StepIter() 262 require.NoError(t, err) 263 264 // ensure functions are marshalled to the block's underlying step iterator. 265 iter.EXPECT().Close() 266 it.Close() 267 268 iter.EXPECT().Err().Return(e) 269 assert.EqualError(t, it.Err(), msg) 270 271 iter.EXPECT().StepCount().Return(12) 272 assert.Equal(t, 12, it.StepCount()) 273 274 seriesMetas := []SeriesMeta{} 275 iter.EXPECT().SeriesMeta().Return(seriesMetas) 276 assert.Equal(t, seriesMetas, it.SeriesMeta()) 277 278 iter.EXPECT().Next().Return(true) 279 assert.True(t, it.Next()) 280 281 vals := []float64{1, 2, 3} 282 step := NewMockStep(ctrl) 283 step.EXPECT().Values().Return(vals) 284 step.EXPECT().Time().Return(now) 285 286 expectedVals := []float64{-1, -2, -3} 287 iter.EXPECT().Current().Return(step) 288 actual := it.Current() 289 assert.Equal(t, expectedVals, actual.Values()) 290 assert.Equal(t, now, actual.Time()) 291 } 292 293 func TestUnconsolidatedSeriesIterWithNegativeValueOffset(t *testing.T) { 294 ctrl := gomock.NewController(t) 295 b := NewMockBlock(ctrl) 296 defer ctrl.Finish() 297 offset := time.Duration(0) 298 offblock := NewLazyBlock(b, testLazyOpts(offset, -1.0)) 299 now := xtime.Now() 300 msg := "err" 301 e := errors.New(msg) 302 303 iter := NewMockSeriesIter(ctrl) 304 b.EXPECT().SeriesIter().Return(iter, nil) 305 it, err := offblock.SeriesIter() 306 require.NoError(t, err) 307 308 concurrency := 5 309 batched := []SeriesIterBatch{ 310 SeriesIterBatch{}, 311 SeriesIterBatch{}, 312 SeriesIterBatch{}, 313 } 314 315 b.EXPECT().MultiSeriesIter(concurrency).Return(batched, nil) 316 bs, err := offblock.MultiSeriesIter(concurrency) 317 require.NoError(t, err) 318 assert.Equal(t, batched, bs) 319 320 // ensure functions are marshalled to the block's underlying series iterator. 321 iter.EXPECT().Close() 322 it.Close() 323 324 iter.EXPECT().Err().Return(e) 325 assert.EqualError(t, it.Err(), msg) 326 327 iter.EXPECT().SeriesCount().Return(12) 328 assert.Equal(t, 12, it.SeriesCount()) 329 330 seriesMetas := []SeriesMeta{} 331 iter.EXPECT().SeriesMeta().Return(seriesMetas) 332 assert.Equal(t, seriesMetas, it.SeriesMeta()) 333 334 iter.EXPECT().Next().Return(true) 335 assert.True(t, it.Next()) 336 337 vals := ts.Datapoints{ 338 ts.Datapoint{ 339 Timestamp: now, 340 Value: 12, 341 }, 342 } 343 344 unconsolidated := UnconsolidatedSeries{ 345 datapoints: vals, 346 } 347 348 iter.EXPECT().Current().Return(unconsolidated) 349 actual := it.Current() 350 expected := ts.Datapoints{ 351 ts.Datapoint{ 352 Timestamp: now, 353 Value: -12, 354 }, 355 } 356 357 assert.Equal(t, expected, actual.Datapoints()) 358 }