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  }