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 }