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  }