github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/functions/linear/datetime_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 linear 22 23 import ( 24 "math" 25 "testing" 26 "time" 27 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 35 "github.com/stretchr/testify/assert" 36 "github.com/stretchr/testify/require" 37 ) 38 39 var withArg = []interface{}{struct{}{}} 40 41 func expectedDateVals(values [][]float64, fn func(t time.Time) float64) [][]float64 { 42 expected := make([][]float64, 0, len(values)) 43 for _, val := range values { 44 v := make([]float64, len(val)) 45 for i, ev := range val { 46 if math.IsNaN(ev) { 47 v[i] = math.NaN() 48 continue 49 } 50 t := time.Unix(int64(ev), 0).UTC() 51 v[i] = fn(t) 52 } 53 54 expected = append(expected, v) 55 } 56 return expected 57 } 58 59 func TestDayOfMonth(t *testing.T) { 60 v := [][]float64{ 61 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 62 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 63 } 64 65 values, bounds := test.GenerateValuesAndBounds(v, nil) 66 block := test.NewBlockFromValues(bounds, values) 67 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 68 timeOp, err := NewDateOp(DayOfMonthType, true) 69 require.NoError(t, err) 70 71 op, ok := timeOp.(transform.Params) 72 require.True(t, ok) 73 74 node := op.Node(c, transform.Options{}) 75 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 76 require.NoError(t, err) 77 expected := expectedDateVals(values, datetimeFuncs[DayOfMonthType]) 78 assert.Len(t, sink.Values, 2) 79 compare.EqualsWithNans(t, expected, sink.Values) 80 } 81 82 func TestDayOfWeek(t *testing.T) { 83 v := [][]float64{ 84 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 85 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 86 } 87 88 values, bounds := test.GenerateValuesAndBounds(v, nil) 89 block := test.NewBlockFromValues(bounds, values) 90 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 91 timeOp, err := NewDateOp(DayOfWeekType, true) 92 require.NoError(t, err) 93 94 op, ok := timeOp.(transform.Params) 95 require.True(t, ok) 96 97 node := op.Node(c, transform.Options{}) 98 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 99 require.NoError(t, err) 100 expected := expectedDateVals(values, datetimeFuncs[DayOfWeekType]) 101 assert.Len(t, sink.Values, 2) 102 compare.EqualsWithNans(t, expected, sink.Values) 103 } 104 105 func TestDaysInMonth(t *testing.T) { 106 v := [][]float64{ 107 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 108 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 109 } 110 111 values, bounds := test.GenerateValuesAndBounds(v, nil) 112 block := test.NewBlockFromValues(bounds, values) 113 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 114 timeOp, err := NewDateOp(DaysInMonthType, true) 115 require.NoError(t, err) 116 117 op, ok := timeOp.(transform.Params) 118 require.True(t, ok) 119 120 node := op.Node(c, transform.Options{}) 121 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 122 require.NoError(t, err) 123 expected := expectedDateVals(values, datetimeFuncs[DaysInMonthType]) 124 assert.Len(t, sink.Values, 2) 125 compare.EqualsWithNans(t, expected, sink.Values) 126 } 127 128 func TestHour(t *testing.T) { 129 v := [][]float64{ 130 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 131 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 132 } 133 134 values, bounds := test.GenerateValuesAndBounds(v, nil) 135 block := test.NewBlockFromValues(bounds, values) 136 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 137 timeOp, err := NewDateOp(HourType, true) 138 require.NoError(t, err) 139 140 op, ok := timeOp.(transform.Params) 141 require.True(t, ok) 142 143 node := op.Node(c, transform.Options{}) 144 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 145 require.NoError(t, err) 146 expected := expectedDateVals(values, datetimeFuncs[HourType]) 147 assert.Len(t, sink.Values, 2) 148 compare.EqualsWithNans(t, expected, sink.Values) 149 } 150 151 func TestMinute(t *testing.T) { 152 v := [][]float64{ 153 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 154 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 155 } 156 157 values, bounds := test.GenerateValuesAndBounds(v, nil) 158 block := test.NewBlockFromValues(bounds, values) 159 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 160 timeOp, err := NewDateOp(MinuteType, true) 161 require.NoError(t, err) 162 163 op, ok := timeOp.(transform.Params) 164 require.True(t, ok) 165 166 node := op.Node(c, transform.Options{}) 167 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 168 require.NoError(t, err) 169 expected := expectedDateVals(values, datetimeFuncs[MinuteType]) 170 assert.Len(t, sink.Values, 2) 171 compare.EqualsWithNans(t, expected, sink.Values) 172 } 173 174 func TestMonth(t *testing.T) { 175 v := [][]float64{ 176 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 177 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 178 } 179 180 values, bounds := test.GenerateValuesAndBounds(v, nil) 181 block := test.NewBlockFromValues(bounds, values) 182 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 183 timeOp, err := NewDateOp(MonthType, true) 184 require.NoError(t, err) 185 186 op, ok := timeOp.(transform.Params) 187 require.True(t, ok) 188 189 node := op.Node(c, transform.Options{}) 190 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 191 require.NoError(t, err) 192 expected := expectedDateVals(values, datetimeFuncs[MonthType]) 193 assert.Len(t, sink.Values, 2) 194 compare.EqualsWithNans(t, expected, sink.Values) 195 } 196 197 func TestYear(t *testing.T) { 198 v := [][]float64{ 199 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 200 {math.NaN(), 1493712846439, 1493712846539, 1493712846639, 1493712846739}, 201 } 202 203 values, bounds := test.GenerateValuesAndBounds(v, nil) 204 block := test.NewBlockFromValues(bounds, values) 205 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 206 timeOp, err := NewDateOp(YearType, true) 207 require.NoError(t, err) 208 209 op, ok := timeOp.(transform.Params) 210 require.True(t, ok) 211 212 node := op.Node(c, transform.Options{}) 213 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 214 require.NoError(t, err) 215 expected := expectedDateVals(values, datetimeFuncs[YearType]) 216 assert.Len(t, sink.Values, 2) 217 compare.EqualsWithNans(t, expected, sink.Values) 218 } 219 220 func TestNonExistentDateFunc(t *testing.T) { 221 _, err := NewDateOp("nonexistent_func", true) 222 require.Error(t, err) 223 } 224 225 func TestWithoutArgs(t *testing.T) { 226 v := [][]float64{ 227 {1493712846039, math.NaN(), 1493712846139, 1493712846239, 1493712846339}, 228 } 229 230 values, bounds := test.GenerateValuesAndBounds(v, nil) 231 block := test.NewBlockFromValues(bounds, values) 232 c, sink := executor.NewControllerWithSink(parser.NodeID(rune(1))) 233 timeOp, err := NewDateOp(YearType, false) 234 require.NoError(t, err) 235 236 op, ok := timeOp.(transform.Params) 237 require.True(t, ok) 238 239 node := op.Node(c, transform.Options{}) 240 err = node.Process(models.NoopQueryContext(), parser.NodeID(rune(0)), block) 241 require.NoError(t, err) 242 assert.Len(t, sink.Values, 1) 243 ex := float64(time.Now().Year()) 244 assert.Equal(t, []float64{ex, ex, ex, ex, ex}, sink.Values[0]) 245 }