github.com/m3db/m3@v1.5.0/src/query/functions/binary/and_test.go (about)

     1  // Copyright (c) 2018 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 binary
    22  
    23  import (
    24  	"math"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/query/block"
    29  	"github.com/m3db/m3/src/query/executor/transform"
    30  	"github.com/m3db/m3/src/query/models"
    31  	"github.com/m3db/m3/src/query/parser"
    32  	"github.com/m3db/m3/src/query/test"
    33  	"github.com/m3db/m3/src/query/test/compare"
    34  	"github.com/m3db/m3/src/query/test/executor"
    35  	xtime "github.com/m3db/m3/src/x/time"
    36  
    37  	"github.com/stretchr/testify/assert"
    38  	"github.com/stretchr/testify/require"
    39  )
    40  
    41  func emptyVectorMatcherBuilder(_, _ block.Block) VectorMatching {
    42  	return VectorMatching{Set: true}
    43  }
    44  
    45  func TestAndWithExactValues(t *testing.T) {
    46  	values, bounds := test.GenerateValuesAndBounds(nil, nil)
    47  	block1 := test.NewBlockFromValues(bounds, values)
    48  	block2 := test.NewBlockFromValues(bounds, values)
    49  
    50  	op, err := NewOp(
    51  		AndType,
    52  		NodeParams{
    53  			LNode:                parser.NodeID(rune(0)),
    54  			RNode:                parser.NodeID(rune(1)),
    55  			VectorMatcherBuilder: emptyVectorMatcherBuilder,
    56  		},
    57  	)
    58  	require.NoError(t, err)
    59  
    60  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(2)))
    61  	node := op.(baseOp).Node(c, transform.Options{})
    62  
    63  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(1)), block2)
    64  	require.NoError(t, err)
    65  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block1)
    66  	require.NoError(t, err)
    67  	assert.Equal(t, values, sink.Values)
    68  }
    69  
    70  func TestAndWithSomeValues(t *testing.T) {
    71  	values1, bounds1 := test.GenerateValuesAndBounds(nil, nil)
    72  	block1 := test.NewBlockFromValues(bounds1, values1)
    73  
    74  	v := [][]float64{
    75  		{0, math.NaN(), 2, 3, 4},
    76  		{math.NaN(), 6, 7, 8, 9},
    77  	}
    78  
    79  	values2, bounds2 := test.GenerateValuesAndBounds(v, nil)
    80  	block2 := test.NewBlockFromValues(bounds2, values2)
    81  
    82  	op, err := NewOp(
    83  		AndType,
    84  		NodeParams{
    85  			LNode:                parser.NodeID(rune(0)),
    86  			RNode:                parser.NodeID(rune(1)),
    87  			VectorMatcherBuilder: emptyVectorMatcherBuilder,
    88  		},
    89  	)
    90  	require.NoError(t, err)
    91  
    92  	c, sink := executor.NewControllerWithSink(parser.NodeID(rune(2)))
    93  	node := op.(baseOp).Node(c, transform.Options{})
    94  
    95  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(1)), block2)
    96  	require.NoError(t, err)
    97  	err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block1)
    98  	require.NoError(t, err)
    99  	// Most values same as lhs
   100  	expected := values1
   101  	expected[0][1] = math.NaN()
   102  	expected[1][0] = math.NaN()
   103  	compare.EqualsWithNans(t, expected, sink.Values)
   104  }
   105  
   106  var andTests = []struct {
   107  	name          string
   108  	lhsMeta       []block.SeriesMeta
   109  	lhs           [][]float64
   110  	rhsMeta       []block.SeriesMeta
   111  	rhs           [][]float64
   112  	expectedMetas []block.SeriesMeta
   113  	expected      [][]float64
   114  	err           error
   115  }{
   116  	{
   117  		"valid, equal tags",
   118  		test.NewSeriesMeta("a", 2),
   119  		[][]float64{{1, 2}, {nan, nan}},
   120  		test.NewSeriesMeta("a", 2),
   121  		[][]float64{{3, nan}, {30, nan}},
   122  		test.NewSeriesMetaWithoutName("a", 2),
   123  		[][]float64{{1, nan}, {nan, nan}},
   124  		nil,
   125  	},
   126  	{
   127  		"valid, some overlap right",
   128  		test.NewSeriesMeta("a", 2),
   129  		[][]float64{{nan, 2}, {10, 20}},
   130  		test.NewSeriesMeta("a", 3),
   131  		[][]float64{{3, nan}, {30, 40}, {50, 60}},
   132  		test.NewSeriesMetaWithoutName("a", 2),
   133  		[][]float64{{nan, nan}, {10, 20}},
   134  		nil,
   135  	},
   136  	{
   137  		"valid, some overlap left",
   138  		test.NewSeriesMeta("a", 3),
   139  		[][]float64{{1, 2}, {10, 20}, {100, 200}},
   140  		test.NewSeriesMeta("a", 3)[1:],
   141  		[][]float64{{3, 4}, {nan, 40}},
   142  		test.NewSeriesMetaWithoutName("a", 3)[1:],
   143  		[][]float64{{10, 20}, {nan, 200}},
   144  		nil,
   145  	},
   146  	{
   147  		"valid, some overlap both",
   148  		test.NewSeriesMeta("a", 3),
   149  		[][]float64{{1, 2}, {10, 20}, {100, 200}},
   150  		test.NewSeriesMeta("a", 4)[1:],
   151  		[][]float64{{3, nan}, {nan, 40}, {300, 400}},
   152  		test.NewSeriesMetaWithoutName("a", 3)[1:],
   153  		[][]float64{{10, nan}, {nan, 200}},
   154  		nil,
   155  	},
   156  	{
   157  		"valid, different tags",
   158  		test.NewSeriesMeta("a", 2),
   159  		[][]float64{{1, 2}, {10, 20}},
   160  		test.NewSeriesMeta("b", 2),
   161  		[][]float64{{nan, 4}, {30, 40}},
   162  		[]block.SeriesMeta{},
   163  		[][]float64{},
   164  		nil,
   165  	},
   166  	{
   167  		"valid, different tags, longer rhs",
   168  		test.NewSeriesMeta("a", 2),
   169  		[][]float64{{1, 2}, {10, 20}},
   170  		test.NewSeriesMeta("b", 3),
   171  		[][]float64{{3, 4}, {30, 40}, {300, 400}},
   172  		[]block.SeriesMeta{},
   173  		[][]float64{},
   174  		nil,
   175  	},
   176  	{
   177  		"valid, different tags, longer lhs",
   178  		test.NewSeriesMeta("a", 3),
   179  		[][]float64{{1, 2}, {10, 20}, {100, 200}},
   180  		test.NewSeriesMeta("b", 2),
   181  		[][]float64{{3, 4}, {30, 40}},
   182  		[]block.SeriesMeta{},
   183  		[][]float64{},
   184  		nil,
   185  	},
   186  	{
   187  		"mismatched step counts",
   188  		test.NewSeriesMeta("a", 2),
   189  		[][]float64{{1, 2, 3}, {10, 20, 30}},
   190  		test.NewSeriesMeta("b", 2),
   191  		[][]float64{{3, 4}, {30, 40}},
   192  		[]block.SeriesMeta{},
   193  		[][]float64{},
   194  		errMismatchedStepCounts,
   195  	},
   196  }
   197  
   198  func TestAnd(t *testing.T) {
   199  	now := xtime.Now()
   200  	for _, tt := range andTests {
   201  		t.Run(tt.name, func(t *testing.T) {
   202  			op, err := NewOp(
   203  				AndType,
   204  				NodeParams{
   205  					LNode:                parser.NodeID(rune(0)),
   206  					RNode:                parser.NodeID(rune(1)),
   207  					VectorMatcherBuilder: emptyVectorMatcherBuilder,
   208  				},
   209  			)
   210  			require.NoError(t, err)
   211  
   212  			c, sink := executor.NewControllerWithSink(parser.NodeID(rune(2)))
   213  			node := op.(baseOp).Node(c, transform.Options{})
   214  			bounds := models.Bounds{
   215  				Start:    now,
   216  				Duration: time.Minute * time.Duration(len(tt.lhs[0])),
   217  				StepSize: time.Minute,
   218  			}
   219  
   220  			lhs := test.NewBlockFromValuesWithSeriesMeta(bounds, tt.lhsMeta, tt.lhs)
   221  			err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), lhs)
   222  			require.NoError(t, err)
   223  			bounds = models.Bounds{
   224  				Start:    now,
   225  				Duration: time.Minute * time.Duration(len(tt.rhs[0])),
   226  				StepSize: time.Minute,
   227  			}
   228  
   229  			rhs := test.NewBlockFromValuesWithSeriesMeta(bounds, tt.rhsMeta, tt.rhs)
   230  			err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(1)), rhs)
   231  			if tt.err != nil {
   232  				require.EqualError(t, err, tt.err.Error())
   233  				return
   234  			}
   235  
   236  			require.NoError(t, err)
   237  			compare.EqualsWithNans(t, tt.expected, sink.Values)
   238  			meta := sink.Meta
   239  			assert.Equal(t, 0, meta.Tags.Len())
   240  			assert.True(t, meta.Bounds.Equals(bounds))
   241  			assert.Equal(t, tt.expectedMetas, sink.Metas)
   242  		})
   243  	}
   244  }