github.com/m3db/m3@v1.5.0/src/query/functions/aggregation/absent_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 aggregation
    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 toArgs(f float64) []interface{} { return []interface{}{f} }
    42  
    43  var (
    44  	start     = xtime.Now()
    45  	testBound = models.Bounds{
    46  		Start:    start,
    47  		Duration: time.Hour,
    48  		StepSize: time.Minute * 15,
    49  	}
    50  )
    51  
    52  var absentTests = []struct {
    53  	name         string
    54  	meta         block.Metadata
    55  	seriesMetas  []block.SeriesMeta
    56  	vals         [][]float64
    57  	expectedMeta block.Metadata
    58  	expectedVals []float64
    59  }{
    60  	{
    61  		"no series",
    62  		test.MustMakeMeta(testBound),
    63  		[]block.SeriesMeta{},
    64  		[][]float64{},
    65  		test.MustMakeMeta(testBound),
    66  		[]float64{1, 1, 1, 1},
    67  	},
    68  	{
    69  		"no series with tags",
    70  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
    71  		[]block.SeriesMeta{},
    72  		[][]float64{},
    73  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
    74  		[]float64{1, 1, 1, 1},
    75  	},
    76  	{
    77  		"series with tags and values",
    78  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
    79  		[]block.SeriesMeta{test.MustMakeSeriesMeta("B", "B")},
    80  		[][]float64{{1, 1, 1, 1}},
    81  		test.MustMakeMeta(testBound, "A", "B", "B", "B", "C", "D"),
    82  		nil,
    83  	},
    84  	{
    85  		"series with tags and some missing",
    86  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
    87  		[]block.SeriesMeta{test.MustMakeSeriesMeta("bar", "baz")},
    88  		[][]float64{{1, 1, 1, math.NaN()}},
    89  		test.MustMakeMeta(testBound, "A", "B", "bar", "baz", "C", "D"),
    90  		[]float64{nan, nan, nan, 1},
    91  	},
    92  	{
    93  		"series with mismatched tags",
    94  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
    95  		[]block.SeriesMeta{
    96  			test.MustMakeSeriesMeta("B", "B"),
    97  			test.MustMakeSeriesMeta("F", "F"),
    98  		},
    99  		[][]float64{
   100  			{1, 1, 1, math.NaN()},
   101  			{math.NaN(), 1, 1, math.NaN()},
   102  		},
   103  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
   104  		[]float64{nan, nan, nan, 1},
   105  	},
   106  	{
   107  		"series with no missing values",
   108  		test.MustMakeMeta(testBound, "A", "B", "C", "D"),
   109  		[]block.SeriesMeta{
   110  			test.MustMakeSeriesMeta("F", "F"),
   111  			test.MustMakeSeriesMeta("F", "F"),
   112  		},
   113  		[][]float64{
   114  			{1, math.NaN(), math.NaN(), 2},
   115  			{math.NaN(), 1, 1, math.NaN()},
   116  		},
   117  		test.MustMakeMeta(testBound, "A", "B", "C", "D", "F", "F"),
   118  		nil,
   119  	},
   120  }
   121  
   122  func TestAbsent(t *testing.T) {
   123  	for _, tt := range absentTests {
   124  		t.Run(tt.name, func(t *testing.T) {
   125  			block := test.NewBlockFromValuesWithMetaAndSeriesMeta(
   126  				tt.meta,
   127  				tt.seriesMetas,
   128  				tt.vals,
   129  			)
   130  
   131  			c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1)))
   132  			absentOp := NewAbsentOp()
   133  			op, ok := absentOp.(transform.Params)
   134  			require.True(t, ok)
   135  
   136  			node := op.Node(c, transform.Options{})
   137  			err := node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block)
   138  			require.NoError(t, err)
   139  
   140  			if tt.expectedVals == nil {
   141  				require.Equal(t, 0, len(sink.Values))
   142  			} else {
   143  				require.Equal(t, 1, len(sink.Values))
   144  				compare.EqualsWithNans(t, tt.expectedVals, sink.Values[0])
   145  				assert.True(t, tt.expectedMeta.Equals(sink.Meta))
   146  			}
   147  		})
   148  	}
   149  }