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