github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/iterator_test.go (about) 1 package query_test 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "reflect" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/davecgh/go-spew/spew" 13 "github.com/influxdata/influxdb/v2/influxql/query" 14 "github.com/influxdata/influxdb/v2/pkg/deep" 15 "github.com/influxdata/influxql" 16 ) 17 18 // Ensure that a set of iterators can be merged together, sorted by window and name/tag. 19 func TestMergeIterator_Float(t *testing.T) { 20 inputs := []*FloatIterator{ 21 {Points: []query.FloatPoint{ 22 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 23 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 24 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 25 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 26 {Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}, 27 }}, 28 {Points: []query.FloatPoint{ 29 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 30 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 31 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 32 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 33 }}, 34 {Points: []query.FloatPoint{}}, 35 {Points: []query.FloatPoint{}}, 36 } 37 38 itr := query.NewMergeIterator(FloatIterators(inputs), query.IteratorOptions{ 39 Interval: query.Interval{ 40 Duration: 10 * time.Nanosecond, 41 }, 42 Dimensions: []string{"host"}, 43 Ascending: true, 44 }) 45 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 46 t.Fatalf("unexpected error: %s", err) 47 } else if !deep.Equal(a, [][]query.Point{ 48 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}}, 49 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}}, 50 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 51 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}}, 52 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}}, 53 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 54 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 55 {&query.FloatPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 56 {&query.FloatPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}}, 57 }) { 58 t.Errorf("unexpected points: %s", spew.Sdump(a)) 59 } 60 61 for i, input := range inputs { 62 if !input.Closed { 63 t.Errorf("iterator %d not closed", i) 64 } 65 } 66 } 67 68 // Ensure that a set of iterators can be merged together, sorted by window and name/tag. 69 func TestMergeIterator_Integer(t *testing.T) { 70 inputs := []*IntegerIterator{ 71 {Points: []query.IntegerPoint{ 72 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 73 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 74 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 75 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 76 {Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}, 77 }}, 78 {Points: []query.IntegerPoint{ 79 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 80 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 81 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 82 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 83 }}, 84 {Points: []query.IntegerPoint{}}, 85 } 86 itr := query.NewMergeIterator(IntegerIterators(inputs), query.IteratorOptions{ 87 Interval: query.Interval{ 88 Duration: 10 * time.Nanosecond, 89 }, 90 Dimensions: []string{"host"}, 91 Ascending: true, 92 }) 93 94 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 95 t.Fatalf("unexpected error: %s", err) 96 } else if !deep.Equal(a, [][]query.Point{ 97 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}}, 98 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}}, 99 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 100 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}}, 101 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}}, 102 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 103 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 104 {&query.IntegerPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 105 {&query.IntegerPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}}, 106 }) { 107 t.Errorf("unexpected points: %s", spew.Sdump(a)) 108 } 109 110 for i, input := range inputs { 111 if !input.Closed { 112 t.Errorf("iterator %d not closed", i) 113 } 114 } 115 } 116 117 // Ensure that a set of iterators can be merged together, sorted by window and name/tag. 118 func TestMergeIterator_Unsigned(t *testing.T) { 119 inputs := []*UnsignedIterator{ 120 {Points: []query.UnsignedPoint{ 121 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 122 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 123 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 124 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 125 {Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}, 126 }}, 127 {Points: []query.UnsignedPoint{ 128 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 129 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 130 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 131 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 132 }}, 133 {Points: []query.UnsignedPoint{}}, 134 } 135 itr := query.NewMergeIterator(UnsignedIterators(inputs), query.IteratorOptions{ 136 Interval: query.Interval{ 137 Duration: 10 * time.Nanosecond, 138 }, 139 Dimensions: []string{"host"}, 140 Ascending: true, 141 }) 142 143 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 144 t.Fatalf("unexpected error: %s", err) 145 } else if !deep.Equal(a, [][]query.Point{ 146 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}}, 147 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}}, 148 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 149 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}}, 150 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}}, 151 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 152 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 153 {&query.UnsignedPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 154 {&query.UnsignedPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}}, 155 }) { 156 t.Errorf("unexpected points: %s", spew.Sdump(a)) 157 } 158 159 for i, input := range inputs { 160 if !input.Closed { 161 t.Errorf("iterator %d not closed", i) 162 } 163 } 164 } 165 166 // Ensure that a set of iterators can be merged together, sorted by window and name/tag. 167 func TestMergeIterator_String(t *testing.T) { 168 inputs := []*StringIterator{ 169 {Points: []query.StringPoint{ 170 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: "a"}, 171 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: "c"}, 172 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: "d"}, 173 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: "b"}, 174 {Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: "h"}, 175 }}, 176 {Points: []query.StringPoint{ 177 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: "g"}, 178 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: "e"}, 179 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: "f"}, 180 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: "i"}, 181 }}, 182 {Points: []query.StringPoint{}}, 183 } 184 itr := query.NewMergeIterator(StringIterators(inputs), query.IteratorOptions{ 185 Interval: query.Interval{ 186 Duration: 10 * time.Nanosecond, 187 }, 188 Dimensions: []string{"host"}, 189 Ascending: true, 190 }) 191 192 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 193 t.Fatalf("unexpected error: %s", err) 194 } else if !deep.Equal(a, [][]query.Point{ 195 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: "a"}}, 196 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: "c"}}, 197 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: "g"}}, 198 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: "d"}}, 199 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: "b"}}, 200 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: "e"}}, 201 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: "f"}}, 202 {&query.StringPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: "i"}}, 203 {&query.StringPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: "h"}}, 204 }) { 205 t.Errorf("unexpected points: %s", spew.Sdump(a)) 206 } 207 208 for i, input := range inputs { 209 if !input.Closed { 210 t.Errorf("iterator %d not closed", i) 211 } 212 } 213 } 214 215 // Ensure that a set of iterators can be merged together, sorted by window and name/tag. 216 func TestMergeIterator_Boolean(t *testing.T) { 217 inputs := []*BooleanIterator{ 218 {Points: []query.BooleanPoint{ 219 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: true}, 220 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: true}, 221 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: false}, 222 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: false}, 223 {Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: true}, 224 }}, 225 {Points: []query.BooleanPoint{ 226 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: true}, 227 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: true}, 228 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: false}, 229 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: false}, 230 }}, 231 {Points: []query.BooleanPoint{}}, 232 } 233 itr := query.NewMergeIterator(BooleanIterators(inputs), query.IteratorOptions{ 234 Interval: query.Interval{ 235 Duration: 10 * time.Nanosecond, 236 }, 237 Dimensions: []string{"host"}, 238 Ascending: true, 239 }) 240 241 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 242 t.Fatalf("unexpected error: %s", err) 243 } else if !deep.Equal(a, [][]query.Point{ 244 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: true}}, 245 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: true}}, 246 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: true}}, 247 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: false}}, 248 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: false}}, 249 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: true}}, 250 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: false}}, 251 {&query.BooleanPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: false}}, 252 {&query.BooleanPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: true}}, 253 }) { 254 t.Errorf("unexpected points: %s", spew.Sdump(a)) 255 } 256 257 for i, input := range inputs { 258 if !input.Closed { 259 t.Errorf("iterator %d not closed", i) 260 } 261 } 262 } 263 264 func TestMergeIterator_Nil(t *testing.T) { 265 itr := query.NewMergeIterator([]query.Iterator{nil}, query.IteratorOptions{}) 266 if itr != nil { 267 t.Fatalf("unexpected iterator: %#v", itr) 268 } 269 } 270 271 // Verifies that coercing will drop values that aren't the primary type. 272 // It's the responsibility of the engine to return the correct type. If they don't, 273 // we drop iterators that don't match. 274 func TestMergeIterator_Coerce_Float(t *testing.T) { 275 inputs := []query.Iterator{ 276 &FloatIterator{Points: []query.FloatPoint{ 277 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 278 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 279 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 280 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 281 }}, 282 &IntegerIterator{Points: []query.IntegerPoint{ 283 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 284 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 285 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 286 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 287 {Name: "mem", Tags: ParseTags("host=B"), Time: 11, Value: 8}, 288 }}, 289 } 290 291 itr := query.NewMergeIterator(inputs, query.IteratorOptions{ 292 Interval: query.Interval{ 293 Duration: 10 * time.Nanosecond, 294 }, 295 Dimensions: []string{"host"}, 296 Ascending: true, 297 }) 298 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 299 t.Fatalf("unexpected error: %s", err) 300 } else if !deep.Equal(a, [][]query.Point{ 301 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 302 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 303 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 304 {&query.FloatPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 305 }) { 306 t.Errorf("unexpected points: %s", spew.Sdump(a)) 307 } 308 309 for i, input := range inputs { 310 switch input := input.(type) { 311 case *FloatIterator: 312 if !input.Closed { 313 t.Errorf("iterator %d not closed", i) 314 } 315 case *IntegerIterator: 316 if !input.Closed { 317 t.Errorf("iterator %d not closed", i) 318 } 319 case *UnsignedIterator: 320 if !input.Closed { 321 t.Errorf("iterator %d not closed", i) 322 } 323 } 324 } 325 } 326 327 // Ensure that a set of iterators can be merged together, sorted by name/tag. 328 func TestSortedMergeIterator_Float(t *testing.T) { 329 inputs := []*FloatIterator{ 330 {Points: []query.FloatPoint{ 331 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 332 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 333 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 334 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 335 {Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}, 336 }}, 337 {Points: []query.FloatPoint{ 338 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 339 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 340 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 341 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 342 }}, 343 {Points: []query.FloatPoint{}}, 344 } 345 itr := query.NewSortedMergeIterator(FloatIterators(inputs), query.IteratorOptions{ 346 Interval: query.Interval{ 347 Duration: 10 * time.Nanosecond, 348 }, 349 Dimensions: []string{"host"}, 350 Ascending: true, 351 }) 352 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 353 t.Fatalf("unexpected error: %s", err) 354 } else if !deep.Equal(a, [][]query.Point{ 355 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}}, 356 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}}, 357 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 358 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}}, 359 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}}, 360 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 361 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 362 {&query.FloatPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 363 {&query.FloatPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}}, 364 }) { 365 t.Errorf("unexpected points: %s", spew.Sdump(a)) 366 } 367 368 for i, input := range inputs { 369 if !input.Closed { 370 t.Errorf("iterator %d not closed", i) 371 } 372 } 373 } 374 375 // Ensure that a set of iterators can be merged together, sorted by name/tag. 376 func TestSortedMergeIterator_Integer(t *testing.T) { 377 inputs := []*IntegerIterator{ 378 {Points: []query.IntegerPoint{ 379 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 380 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 381 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 382 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 383 {Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}, 384 }}, 385 {Points: []query.IntegerPoint{ 386 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 387 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 388 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 389 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 390 }}, 391 {Points: []query.IntegerPoint{}}, 392 } 393 itr := query.NewSortedMergeIterator(IntegerIterators(inputs), query.IteratorOptions{ 394 Interval: query.Interval{ 395 Duration: 10 * time.Nanosecond, 396 }, 397 Dimensions: []string{"host"}, 398 Ascending: true, 399 }) 400 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 401 t.Fatalf("unexpected error: %s", err) 402 } else if !deep.Equal(a, [][]query.Point{ 403 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}}, 404 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}}, 405 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 406 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}}, 407 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}}, 408 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 409 {&query.IntegerPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 410 {&query.IntegerPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 411 {&query.IntegerPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}}, 412 }) { 413 t.Errorf("unexpected points: %s", spew.Sdump(a)) 414 } 415 416 for i, input := range inputs { 417 if !input.Closed { 418 t.Errorf("iterator %d not closed", i) 419 } 420 } 421 } 422 423 // Ensure that a set of iterators can be merged together, sorted by name/tag. 424 func TestSortedMergeIterator_Unsigned(t *testing.T) { 425 inputs := []*UnsignedIterator{ 426 {Points: []query.UnsignedPoint{ 427 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 428 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 429 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 430 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 431 {Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}, 432 }}, 433 {Points: []query.UnsignedPoint{ 434 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 435 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 436 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 437 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 438 }}, 439 {Points: []query.UnsignedPoint{}}, 440 } 441 itr := query.NewSortedMergeIterator(UnsignedIterators(inputs), query.IteratorOptions{ 442 Interval: query.Interval{ 443 Duration: 10 * time.Nanosecond, 444 }, 445 Dimensions: []string{"host"}, 446 Ascending: true, 447 }) 448 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 449 t.Fatalf("unexpected error: %s", err) 450 } else if !deep.Equal(a, [][]query.Point{ 451 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}}, 452 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}}, 453 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 454 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}}, 455 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}}, 456 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 457 {&query.UnsignedPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 458 {&query.UnsignedPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 459 {&query.UnsignedPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}}, 460 }) { 461 t.Errorf("unexpected points: %s", spew.Sdump(a)) 462 } 463 464 for i, input := range inputs { 465 if !input.Closed { 466 t.Errorf("iterator %d not closed", i) 467 } 468 } 469 } 470 471 // Ensure that a set of iterators can be merged together, sorted by name/tag. 472 func TestSortedMergeIterator_String(t *testing.T) { 473 inputs := []*StringIterator{ 474 {Points: []query.StringPoint{ 475 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: "a"}, 476 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: "c"}, 477 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: "d"}, 478 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: "b"}, 479 {Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: "h"}, 480 }}, 481 {Points: []query.StringPoint{ 482 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: "g"}, 483 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: "e"}, 484 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: "f"}, 485 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: "i"}, 486 }}, 487 {Points: []query.StringPoint{}}, 488 } 489 itr := query.NewSortedMergeIterator(StringIterators(inputs), query.IteratorOptions{ 490 Interval: query.Interval{ 491 Duration: 10 * time.Nanosecond, 492 }, 493 Dimensions: []string{"host"}, 494 Ascending: true, 495 }) 496 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 497 t.Fatalf("unexpected error: %s", err) 498 } else if !deep.Equal(a, [][]query.Point{ 499 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: "a"}}, 500 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: "c"}}, 501 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: "g"}}, 502 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: "d"}}, 503 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: "b"}}, 504 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: "e"}}, 505 {&query.StringPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: "f"}}, 506 {&query.StringPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: "i"}}, 507 {&query.StringPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: "h"}}, 508 }) { 509 t.Errorf("unexpected points: %s", spew.Sdump(a)) 510 } 511 512 for i, input := range inputs { 513 if !input.Closed { 514 t.Errorf("iterator %d not closed", i) 515 } 516 } 517 } 518 519 // Ensure that a set of iterators can be merged together, sorted by name/tag. 520 func TestSortedMergeIterator_Boolean(t *testing.T) { 521 inputs := []*BooleanIterator{ 522 {Points: []query.BooleanPoint{ 523 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: true}, 524 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: true}, 525 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: false}, 526 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: false}, 527 {Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: true}, 528 }}, 529 {Points: []query.BooleanPoint{ 530 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: true}, 531 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: true}, 532 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: false}, 533 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: true}, 534 }}, 535 {Points: []query.BooleanPoint{}}, 536 } 537 itr := query.NewSortedMergeIterator(BooleanIterators(inputs), query.IteratorOptions{ 538 Interval: query.Interval{ 539 Duration: 10 * time.Nanosecond, 540 }, 541 Dimensions: []string{"host"}, 542 Ascending: true, 543 }) 544 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 545 t.Fatalf("unexpected error: %s", err) 546 } else if !deep.Equal(a, [][]query.Point{ 547 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: true}}, 548 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: true}}, 549 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: true}}, 550 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: false}}, 551 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: false}}, 552 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: true}}, 553 {&query.BooleanPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: false}}, 554 {&query.BooleanPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: true}}, 555 {&query.BooleanPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: true}}, 556 }) { 557 t.Errorf("unexpected points: %s", spew.Sdump(a)) 558 } 559 560 for i, input := range inputs { 561 if !input.Closed { 562 t.Errorf("iterator %d not closed", i) 563 } 564 } 565 } 566 567 func TestSortedMergeIterator_Nil(t *testing.T) { 568 itr := query.NewSortedMergeIterator([]query.Iterator{nil}, query.IteratorOptions{}) 569 if itr != nil { 570 t.Fatalf("unexpected iterator: %#v", itr) 571 } 572 } 573 574 func TestSortedMergeIterator_Coerce_Float(t *testing.T) { 575 inputs := []query.Iterator{ 576 &FloatIterator{Points: []query.FloatPoint{ 577 {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, 578 {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, 579 {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, 580 {Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}, 581 }}, 582 &IntegerIterator{Points: []query.IntegerPoint{ 583 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, 584 {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, 585 {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, 586 {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, 587 {Name: "mem", Tags: ParseTags("host=B"), Time: 4, Value: 8}, 588 }}, 589 } 590 591 itr := query.NewSortedMergeIterator(inputs, query.IteratorOptions{ 592 Interval: query.Interval{ 593 Duration: 10 * time.Nanosecond, 594 }, 595 Dimensions: []string{"host"}, 596 Ascending: true, 597 }) 598 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 599 t.Fatalf("unexpected error: %s", err) 600 } else if !deep.Equal(a, [][]query.Point{ 601 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}}, 602 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}}, 603 {&query.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}}, 604 {&query.FloatPoint{Name: "mem", Tags: ParseTags("host=A"), Time: 25, Value: 9}}, 605 }) { 606 t.Errorf("unexpected points: %s", spew.Sdump(a)) 607 } 608 609 for i, input := range inputs { 610 switch input := input.(type) { 611 case *FloatIterator: 612 if !input.Closed { 613 t.Errorf("iterator %d not closed", i) 614 } 615 case *IntegerIterator: 616 if !input.Closed { 617 t.Errorf("iterator %d not closed", i) 618 } 619 case *UnsignedIterator: 620 if !input.Closed { 621 t.Errorf("iterator %d not closed", i) 622 } 623 } 624 } 625 } 626 627 // Ensure limit iterators work with limit and offset. 628 func TestLimitIterator_Float(t *testing.T) { 629 input := &FloatIterator{Points: []query.FloatPoint{ 630 {Name: "cpu", Time: 0, Value: 1}, 631 {Name: "cpu", Time: 5, Value: 3}, 632 {Name: "cpu", Time: 10, Value: 5}, 633 {Name: "mem", Time: 5, Value: 3}, 634 {Name: "mem", Time: 7, Value: 8}, 635 }} 636 637 itr := query.NewLimitIterator(input, query.IteratorOptions{ 638 Limit: 1, 639 Offset: 1, 640 }) 641 642 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 643 t.Fatalf("unexpected error: %s", err) 644 } else if !deep.Equal(a, [][]query.Point{ 645 {&query.FloatPoint{Name: "cpu", Time: 5, Value: 3}}, 646 {&query.FloatPoint{Name: "mem", Time: 7, Value: 8}}, 647 }) { 648 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 649 } 650 651 if !input.Closed { 652 t.Error("iterator not closed") 653 } 654 } 655 656 // Ensure limit iterators work with limit and offset. 657 func TestLimitIterator_Integer(t *testing.T) { 658 input := &IntegerIterator{Points: []query.IntegerPoint{ 659 {Name: "cpu", Time: 0, Value: 1}, 660 {Name: "cpu", Time: 5, Value: 3}, 661 {Name: "cpu", Time: 10, Value: 5}, 662 {Name: "mem", Time: 5, Value: 3}, 663 {Name: "mem", Time: 7, Value: 8}, 664 }} 665 666 itr := query.NewLimitIterator(input, query.IteratorOptions{ 667 Limit: 1, 668 Offset: 1, 669 }) 670 671 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 672 t.Fatalf("unexpected error: %s", err) 673 } else if !deep.Equal(a, [][]query.Point{ 674 {&query.IntegerPoint{Name: "cpu", Time: 5, Value: 3}}, 675 {&query.IntegerPoint{Name: "mem", Time: 7, Value: 8}}, 676 }) { 677 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 678 } 679 680 if !input.Closed { 681 t.Error("iterator not closed") 682 } 683 } 684 685 // Ensure limit iterators work with limit and offset. 686 func TestLimitIterator_Unsigned(t *testing.T) { 687 input := &UnsignedIterator{Points: []query.UnsignedPoint{ 688 {Name: "cpu", Time: 0, Value: 1}, 689 {Name: "cpu", Time: 5, Value: 3}, 690 {Name: "cpu", Time: 10, Value: 5}, 691 {Name: "mem", Time: 5, Value: 3}, 692 {Name: "mem", Time: 7, Value: 8}, 693 }} 694 695 itr := query.NewLimitIterator(input, query.IteratorOptions{ 696 Limit: 1, 697 Offset: 1, 698 }) 699 700 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 701 t.Fatalf("unexpected error: %s", err) 702 } else if !deep.Equal(a, [][]query.Point{ 703 {&query.UnsignedPoint{Name: "cpu", Time: 5, Value: 3}}, 704 {&query.UnsignedPoint{Name: "mem", Time: 7, Value: 8}}, 705 }) { 706 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 707 } 708 709 if !input.Closed { 710 t.Error("iterator not closed") 711 } 712 } 713 714 // Ensure limit iterators work with limit and offset. 715 func TestLimitIterator_String(t *testing.T) { 716 input := &StringIterator{Points: []query.StringPoint{ 717 {Name: "cpu", Time: 0, Value: "a"}, 718 {Name: "cpu", Time: 5, Value: "b"}, 719 {Name: "cpu", Time: 10, Value: "c"}, 720 {Name: "mem", Time: 5, Value: "d"}, 721 {Name: "mem", Time: 7, Value: "e"}, 722 }} 723 724 itr := query.NewLimitIterator(input, query.IteratorOptions{ 725 Limit: 1, 726 Offset: 1, 727 }) 728 729 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 730 t.Fatalf("unexpected error: %s", err) 731 } else if !deep.Equal(a, [][]query.Point{ 732 {&query.StringPoint{Name: "cpu", Time: 5, Value: "b"}}, 733 {&query.StringPoint{Name: "mem", Time: 7, Value: "e"}}, 734 }) { 735 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 736 } 737 738 if !input.Closed { 739 t.Error("iterator not closed") 740 } 741 } 742 743 // Ensure limit iterators work with limit and offset. 744 func TestLimitIterator_Boolean(t *testing.T) { 745 input := &BooleanIterator{Points: []query.BooleanPoint{ 746 {Name: "cpu", Time: 0, Value: true}, 747 {Name: "cpu", Time: 5, Value: false}, 748 {Name: "cpu", Time: 10, Value: true}, 749 {Name: "mem", Time: 5, Value: false}, 750 {Name: "mem", Time: 7, Value: true}, 751 }} 752 753 itr := query.NewLimitIterator(input, query.IteratorOptions{ 754 Limit: 1, 755 Offset: 1, 756 }) 757 758 if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil { 759 t.Fatalf("unexpected error: %s", err) 760 } else if !deep.Equal(a, [][]query.Point{ 761 {&query.BooleanPoint{Name: "cpu", Time: 5, Value: false}}, 762 {&query.BooleanPoint{Name: "mem", Time: 7, Value: true}}, 763 }) { 764 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 765 } 766 767 if !input.Closed { 768 t.Error("iterator not closed") 769 } 770 } 771 772 // Ensure limit iterator returns a subset of points. 773 func TestLimitIterator(t *testing.T) { 774 itr := query.NewLimitIterator( 775 &FloatIterator{Points: []query.FloatPoint{ 776 {Time: 0, Value: 0}, 777 {Time: 1, Value: 1}, 778 {Time: 2, Value: 2}, 779 {Time: 3, Value: 3}, 780 }}, 781 query.IteratorOptions{ 782 Limit: 2, 783 Offset: 1, 784 StartTime: influxql.MinTime, 785 EndTime: influxql.MaxTime, 786 }, 787 ) 788 789 if a, err := (Iterators{itr}).ReadAll(); err != nil { 790 t.Fatalf("unexpected error: %s", err) 791 } else if !deep.Equal(a, [][]query.Point{ 792 {&query.FloatPoint{Time: 1, Value: 1}}, 793 {&query.FloatPoint{Time: 2, Value: 2}}, 794 }) { 795 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 796 } 797 } 798 799 func TestFillIterator_ImplicitStartTime(t *testing.T) { 800 opt := query.IteratorOptions{ 801 StartTime: influxql.MinTime, 802 EndTime: mustParseTime("2000-01-01T01:00:00Z").UnixNano() - 1, 803 Interval: query.Interval{ 804 Duration: 20 * time.Minute, 805 }, 806 Ascending: true, 807 } 808 start := mustParseTime("2000-01-01T00:00:00Z").UnixNano() 809 itr := query.NewFillIterator( 810 &FloatIterator{Points: []query.FloatPoint{ 811 {Time: start, Value: 0}, 812 }}, 813 nil, 814 opt, 815 ) 816 817 if a, err := (Iterators{itr}).ReadAll(); err != nil { 818 t.Fatalf("unexpected error: %s", err) 819 } else if !deep.Equal(a, [][]query.Point{ 820 {&query.FloatPoint{Time: start, Value: 0}}, 821 {&query.FloatPoint{Time: start + int64(20*time.Minute), Nil: true}}, 822 {&query.FloatPoint{Time: start + int64(40*time.Minute), Nil: true}}, 823 }) { 824 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 825 } 826 } 827 828 // A count() GROUP BY query with an offset that caused an interval 829 // to cross a daylight savings change inserted an extra output row 830 // off by one hour in a grouped count() expression. 831 // https://github.com/influxdata/influxdb/issues/20238 832 833 func TestGroupByIterator_DST(t *testing.T) { 834 inputIter := &IntegerIterator{ 835 Points: []query.IntegerPoint{ 836 {Name: "a", Tags: ParseTags("t=A"), Time: 1584345600000000000, Value: 1}, 837 {Name: "a", Tags: ParseTags("t=A"), Time: 1584432000000000000, Value: 2}, 838 {Name: "a", Tags: ParseTags("t=A"), Time: 1584518400000000000, Value: 3}, 839 {Name: "a", Tags: ParseTags("t=A"), Time: 1585555200000000000, Value: 4}, 840 }, 841 } 842 const location = "Europe/Rome" 843 loc, err := time.LoadLocation(location) 844 if err != nil { 845 t.Fatalf("Cannot find timezone for %s: %s", location, err) 846 } 847 opt := query.IteratorOptions{ 848 StartTime: mustParseTime("2020-03-15T00:00:00Z").UnixNano(), 849 EndTime: mustParseTime("2020-04-01T00:00:00Z").UnixNano(), 850 Ascending: true, 851 Ordered: true, 852 StripName: false, 853 Fill: influxql.NullFill, 854 FillValue: nil, 855 Dedupe: false, 856 Interval: query.Interval{ 857 Duration: 7 * 24 * time.Hour, 858 Offset: 4 * 24 * time.Hour, 859 }, 860 Expr: MustParseExpr("count(Value)"), 861 Location: loc, 862 } 863 864 groupByIter, err := query.NewCallIterator(inputIter, opt) 865 if err != nil { 866 t.Fatalf("Cannot create Count and Group By iterator: %s", err) 867 } else { 868 groupByIter = query.NewFillIterator(groupByIter, MustParseExpr("count(Value)"), opt) 869 } 870 871 if a, err := (Iterators{groupByIter}).ReadAll(); err != nil { 872 t.Fatalf("unexpected error: %s", err) 873 } else if !deep.Equal(a, [][]query.Point{ 874 {&query.IntegerPoint{Name: "a", Aggregated: 0, Time: mustParseTime("2020-03-09T00:00:00+01:00").UnixNano(), Value: 0}}, 875 {&query.IntegerPoint{Name: "a", Aggregated: 3, Time: mustParseTime("2020-03-16T00:00:00+01:00").UnixNano(), Value: 3}}, 876 {&query.IntegerPoint{Name: "a", Aggregated: 0, Time: mustParseTime("2020-03-23T00:00:00+01:00").UnixNano(), Value: 0}}, 877 {&query.IntegerPoint{Name: "a", Aggregated: 1, Time: mustParseTime("2020-03-30T00:00:00+02:00").UnixNano(), Value: 1}}, 878 }) { 879 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 880 } 881 } 882 883 func TestFillIterator_DST(t *testing.T) { 884 for _, tt := range []struct { 885 name string 886 start, end time.Time 887 points []time.Duration 888 opt query.IteratorOptions 889 }{ 890 { 891 name: "Start_GroupByDay_Ascending", 892 start: mustParseTime("2000-04-01T00:00:00-08:00"), 893 end: mustParseTime("2000-04-05T00:00:00-07:00"), 894 points: []time.Duration{ 895 24 * time.Hour, 896 47 * time.Hour, 897 71 * time.Hour, 898 }, 899 opt: query.IteratorOptions{ 900 Interval: query.Interval{ 901 Duration: 24 * time.Hour, 902 }, 903 Location: LosAngeles, 904 Ascending: true, 905 }, 906 }, 907 { 908 name: "Start_GroupByDay_Descending", 909 start: mustParseTime("2000-04-01T00:00:00-08:00"), 910 end: mustParseTime("2000-04-05T00:00:00-07:00"), 911 points: []time.Duration{ 912 71 * time.Hour, 913 47 * time.Hour, 914 24 * time.Hour, 915 }, 916 opt: query.IteratorOptions{ 917 Interval: query.Interval{ 918 Duration: 24 * time.Hour, 919 }, 920 Location: LosAngeles, 921 Ascending: false, 922 }, 923 }, 924 { 925 name: "Start_GroupByHour_Ascending", 926 start: mustParseTime("2000-04-02T00:00:00-08:00"), 927 end: mustParseTime("2000-04-02T05:00:00-07:00"), 928 points: []time.Duration{ 929 1 * time.Hour, 930 2 * time.Hour, 931 3 * time.Hour, 932 }, 933 opt: query.IteratorOptions{ 934 Interval: query.Interval{ 935 Duration: 1 * time.Hour, 936 }, 937 Location: LosAngeles, 938 Ascending: true, 939 }, 940 }, 941 { 942 name: "Start_GroupByHour_Descending", 943 start: mustParseTime("2000-04-02T00:00:00-08:00"), 944 end: mustParseTime("2000-04-02T05:00:00-07:00"), 945 points: []time.Duration{ 946 3 * time.Hour, 947 2 * time.Hour, 948 1 * time.Hour, 949 }, 950 opt: query.IteratorOptions{ 951 Interval: query.Interval{ 952 Duration: 1 * time.Hour, 953 }, 954 Location: LosAngeles, 955 Ascending: false, 956 }, 957 }, 958 { 959 name: "Start_GroupBy2Hour_Ascending", 960 start: mustParseTime("2000-04-02T00:00:00-08:00"), 961 end: mustParseTime("2000-04-02T07:00:00-07:00"), 962 points: []time.Duration{ 963 2 * time.Hour, 964 3 * time.Hour, 965 5 * time.Hour, 966 }, 967 opt: query.IteratorOptions{ 968 Interval: query.Interval{ 969 Duration: 2 * time.Hour, 970 }, 971 Location: LosAngeles, 972 Ascending: true, 973 }, 974 }, 975 { 976 name: "Start_GroupBy2Hour_Descending", 977 start: mustParseTime("2000-04-02T00:00:00-08:00"), 978 end: mustParseTime("2000-04-02T07:00:00-07:00"), 979 points: []time.Duration{ 980 5 * time.Hour, 981 3 * time.Hour, 982 2 * time.Hour, 983 }, 984 opt: query.IteratorOptions{ 985 Interval: query.Interval{ 986 Duration: 2 * time.Hour, 987 }, 988 Location: LosAngeles, 989 Ascending: false, 990 }, 991 }, 992 { 993 name: "End_GroupByDay_Ascending", 994 start: mustParseTime("2000-10-28T00:00:00-07:00"), 995 end: mustParseTime("2000-11-01T00:00:00-08:00"), 996 points: []time.Duration{ 997 24 * time.Hour, 998 49 * time.Hour, 999 73 * time.Hour, 1000 }, 1001 opt: query.IteratorOptions{ 1002 Interval: query.Interval{ 1003 Duration: 24 * time.Hour, 1004 }, 1005 Location: LosAngeles, 1006 Ascending: true, 1007 }, 1008 }, 1009 { 1010 name: "End_GroupByDay_Descending", 1011 start: mustParseTime("2000-10-28T00:00:00-07:00"), 1012 end: mustParseTime("2000-11-01T00:00:00-08:00"), 1013 points: []time.Duration{ 1014 73 * time.Hour, 1015 49 * time.Hour, 1016 24 * time.Hour, 1017 }, 1018 opt: query.IteratorOptions{ 1019 Interval: query.Interval{ 1020 Duration: 24 * time.Hour, 1021 }, 1022 Location: LosAngeles, 1023 Ascending: false, 1024 }, 1025 }, 1026 { 1027 name: "End_GroupByHour_Ascending", 1028 start: mustParseTime("2000-10-29T00:00:00-07:00"), 1029 end: mustParseTime("2000-10-29T03:00:00-08:00"), 1030 points: []time.Duration{ 1031 1 * time.Hour, 1032 2 * time.Hour, 1033 3 * time.Hour, 1034 }, 1035 opt: query.IteratorOptions{ 1036 Interval: query.Interval{ 1037 Duration: 1 * time.Hour, 1038 }, 1039 Location: LosAngeles, 1040 Ascending: true, 1041 }, 1042 }, 1043 { 1044 name: "End_GroupByHour_Descending", 1045 start: mustParseTime("2000-10-29T00:00:00-07:00"), 1046 end: mustParseTime("2000-10-29T03:00:00-08:00"), 1047 points: []time.Duration{ 1048 3 * time.Hour, 1049 2 * time.Hour, 1050 1 * time.Hour, 1051 }, 1052 opt: query.IteratorOptions{ 1053 Interval: query.Interval{ 1054 Duration: 1 * time.Hour, 1055 }, 1056 Location: LosAngeles, 1057 Ascending: false, 1058 }, 1059 }, 1060 } { 1061 t.Run(tt.name, func(t *testing.T) { 1062 opt := tt.opt 1063 opt.StartTime = tt.start.UnixNano() 1064 opt.EndTime = tt.end.UnixNano() - 1 1065 1066 points := make([][]query.Point, 0, len(tt.points)+1) 1067 if opt.Ascending { 1068 points = append(points, []query.Point{ 1069 &query.FloatPoint{ 1070 Time: tt.start.UnixNano(), 1071 }, 1072 }) 1073 } 1074 for _, d := range tt.points { 1075 points = append(points, []query.Point{ 1076 &query.FloatPoint{ 1077 Time: tt.start.Add(d).UnixNano(), 1078 Nil: true, 1079 }, 1080 }) 1081 } 1082 if !opt.Ascending { 1083 points = append(points, []query.Point{ 1084 &query.FloatPoint{ 1085 Time: tt.start.UnixNano(), 1086 }, 1087 }) 1088 } 1089 itr := query.NewFillIterator( 1090 &FloatIterator{Points: []query.FloatPoint{{Time: tt.start.UnixNano(), Value: 0}}}, 1091 nil, 1092 opt, 1093 ) 1094 1095 if a, err := (Iterators{itr}).ReadAll(); err != nil { 1096 t.Fatalf("unexpected error: %s", err) 1097 } else if !deep.Equal(a, points) { 1098 t.Fatalf("unexpected points: %s", spew.Sdump(a)) 1099 } 1100 }) 1101 } 1102 } 1103 1104 // Iterators is a test wrapper for iterators. 1105 type Iterators []query.Iterator 1106 1107 // Next returns the next value from each iterator. 1108 // Returns nil if any iterator returns a nil. 1109 func (itrs Iterators) Next() ([]query.Point, error) { 1110 a := make([]query.Point, len(itrs)) 1111 for i, itr := range itrs { 1112 switch itr := itr.(type) { 1113 case query.FloatIterator: 1114 fp, err := itr.Next() 1115 if fp == nil || err != nil { 1116 return nil, err 1117 } 1118 a[i] = fp 1119 case query.IntegerIterator: 1120 ip, err := itr.Next() 1121 if ip == nil || err != nil { 1122 return nil, err 1123 } 1124 a[i] = ip 1125 case query.UnsignedIterator: 1126 up, err := itr.Next() 1127 if up == nil || err != nil { 1128 return nil, err 1129 } 1130 a[i] = up 1131 case query.StringIterator: 1132 sp, err := itr.Next() 1133 if sp == nil || err != nil { 1134 return nil, err 1135 } 1136 a[i] = sp 1137 case query.BooleanIterator: 1138 bp, err := itr.Next() 1139 if bp == nil || err != nil { 1140 return nil, err 1141 } 1142 a[i] = bp 1143 default: 1144 panic(fmt.Sprintf("iterator type not supported: %T", itr)) 1145 } 1146 } 1147 return a, nil 1148 } 1149 1150 // ReadAll reads all points from all iterators. 1151 func (itrs Iterators) ReadAll() ([][]query.Point, error) { 1152 var a [][]query.Point 1153 1154 // Read from every iterator until a nil is encountered. 1155 for { 1156 points, err := itrs.Next() 1157 if err != nil { 1158 return nil, err 1159 } else if points == nil { 1160 break 1161 } 1162 a = append(a, query.Points(points).Clone()) 1163 } 1164 1165 // Close all iterators. 1166 query.Iterators(itrs).Close() 1167 1168 return a, nil 1169 } 1170 1171 func TestIteratorOptions_Window_Interval(t *testing.T) { 1172 opt := query.IteratorOptions{ 1173 Interval: query.Interval{ 1174 Duration: 10, 1175 }, 1176 } 1177 1178 start, end := opt.Window(4) 1179 if start != 0 { 1180 t.Errorf("expected start to be 0, got %d", start) 1181 } 1182 if end != 10 { 1183 t.Errorf("expected end to be 10, got %d", end) 1184 } 1185 } 1186 1187 func TestIteratorOptions_Window_Offset(t *testing.T) { 1188 opt := query.IteratorOptions{ 1189 Interval: query.Interval{ 1190 Duration: 10, 1191 Offset: 8, 1192 }, 1193 } 1194 1195 start, end := opt.Window(14) 1196 if start != 8 { 1197 t.Errorf("expected start to be 8, got %d", start) 1198 } 1199 if end != 18 { 1200 t.Errorf("expected end to be 18, got %d", end) 1201 } 1202 } 1203 1204 func TestIteratorOptions_Window_Default(t *testing.T) { 1205 opt := query.IteratorOptions{ 1206 StartTime: 0, 1207 EndTime: 60, 1208 } 1209 1210 start, end := opt.Window(34) 1211 if start != 0 { 1212 t.Errorf("expected start to be 0, got %d", start) 1213 } 1214 if end != 61 { 1215 t.Errorf("expected end to be 61, got %d", end) 1216 } 1217 } 1218 1219 func TestIteratorOptions_Window_Location(t *testing.T) { 1220 for _, tt := range []struct { 1221 now time.Time 1222 start, end time.Time 1223 interval time.Duration 1224 }{ 1225 { 1226 now: mustParseTime("2000-04-02T12:14:15-07:00"), 1227 start: mustParseTime("2000-04-02T00:00:00-08:00"), 1228 end: mustParseTime("2000-04-03T00:00:00-07:00"), 1229 interval: 24 * time.Hour, 1230 }, 1231 { 1232 now: mustParseTime("2000-04-02T01:17:12-08:00"), 1233 start: mustParseTime("2000-04-02T00:00:00-08:00"), 1234 end: mustParseTime("2000-04-03T00:00:00-07:00"), 1235 interval: 24 * time.Hour, 1236 }, 1237 { 1238 now: mustParseTime("2000-04-02T01:14:15-08:00"), 1239 start: mustParseTime("2000-04-02T00:00:00-08:00"), 1240 end: mustParseTime("2000-04-02T03:00:00-07:00"), 1241 interval: 2 * time.Hour, 1242 }, 1243 { 1244 now: mustParseTime("2000-04-02T03:17:12-07:00"), 1245 start: mustParseTime("2000-04-02T03:00:00-07:00"), 1246 end: mustParseTime("2000-04-02T04:00:00-07:00"), 1247 interval: 2 * time.Hour, 1248 }, 1249 { 1250 now: mustParseTime("2000-04-02T01:14:15-08:00"), 1251 start: mustParseTime("2000-04-02T01:00:00-08:00"), 1252 end: mustParseTime("2000-04-02T03:00:00-07:00"), 1253 interval: 1 * time.Hour, 1254 }, 1255 { 1256 now: mustParseTime("2000-04-02T03:17:12-07:00"), 1257 start: mustParseTime("2000-04-02T03:00:00-07:00"), 1258 end: mustParseTime("2000-04-02T04:00:00-07:00"), 1259 interval: 1 * time.Hour, 1260 }, 1261 { 1262 now: mustParseTime("2000-10-29T12:14:15-08:00"), 1263 start: mustParseTime("2000-10-29T00:00:00-07:00"), 1264 end: mustParseTime("2000-10-30T00:00:00-08:00"), 1265 interval: 24 * time.Hour, 1266 }, 1267 { 1268 now: mustParseTime("2000-10-29T01:17:12-07:00"), 1269 start: mustParseTime("2000-10-29T00:00:00-07:00"), 1270 end: mustParseTime("2000-10-30T00:00:00-08:00"), 1271 interval: 24 * time.Hour, 1272 }, 1273 { 1274 now: mustParseTime("2000-10-29T01:14:15-07:00"), 1275 start: mustParseTime("2000-10-29T00:00:00-07:00"), 1276 end: mustParseTime("2000-10-29T02:00:00-08:00"), 1277 interval: 2 * time.Hour, 1278 }, 1279 { 1280 now: mustParseTime("2000-10-29T03:17:12-08:00"), 1281 start: mustParseTime("2000-10-29T02:00:00-08:00"), 1282 end: mustParseTime("2000-10-29T04:00:00-08:00"), 1283 interval: 2 * time.Hour, 1284 }, 1285 { 1286 now: mustParseTime("2000-10-29T01:14:15-07:00"), 1287 start: mustParseTime("2000-10-29T01:00:00-07:00"), 1288 end: mustParseTime("2000-10-29T01:00:00-08:00"), 1289 interval: 1 * time.Hour, 1290 }, 1291 { 1292 now: mustParseTime("2000-10-29T02:17:12-07:00"), 1293 start: mustParseTime("2000-10-29T02:00:00-07:00"), 1294 end: mustParseTime("2000-10-29T03:00:00-07:00"), 1295 interval: 1 * time.Hour, 1296 }, 1297 } { 1298 t.Run(fmt.Sprintf("%s/%s", tt.now, tt.interval), func(t *testing.T) { 1299 opt := query.IteratorOptions{ 1300 Location: LosAngeles, 1301 Interval: query.Interval{ 1302 Duration: tt.interval, 1303 }, 1304 } 1305 start, end := opt.Window(tt.now.UnixNano()) 1306 if have, want := time.Unix(0, start).In(LosAngeles), tt.start; !have.Equal(want) { 1307 t.Errorf("unexpected start time: %s != %s", have, want) 1308 } 1309 if have, want := time.Unix(0, end).In(LosAngeles), tt.end; !have.Equal(want) { 1310 t.Errorf("unexpected end time: %s != %s", have, want) 1311 } 1312 }) 1313 } 1314 } 1315 1316 func TestIteratorOptions_Window_MinTime(t *testing.T) { 1317 opt := query.IteratorOptions{ 1318 StartTime: influxql.MinTime, 1319 EndTime: influxql.MaxTime, 1320 Interval: query.Interval{ 1321 Duration: time.Hour, 1322 }, 1323 } 1324 expected := time.Unix(0, influxql.MinTime).Add(time.Hour).Truncate(time.Hour) 1325 1326 start, end := opt.Window(influxql.MinTime) 1327 if start != influxql.MinTime { 1328 t.Errorf("expected start to be %d, got %d", influxql.MinTime, start) 1329 } 1330 if have, want := end, expected.UnixNano(); have != want { 1331 t.Errorf("expected end to be %d, got %d", want, have) 1332 } 1333 } 1334 1335 func TestIteratorOptions_Window_MaxTime(t *testing.T) { 1336 opt := query.IteratorOptions{ 1337 StartTime: influxql.MinTime, 1338 EndTime: influxql.MaxTime, 1339 Interval: query.Interval{ 1340 Duration: time.Hour, 1341 }, 1342 } 1343 expected := time.Unix(0, influxql.MaxTime).Truncate(time.Hour) 1344 1345 start, end := opt.Window(influxql.MaxTime) 1346 if have, want := start, expected.UnixNano(); have != want { 1347 t.Errorf("expected start to be %d, got %d", want, have) 1348 } 1349 if end != influxql.MaxTime { 1350 t.Errorf("expected end to be %d, got %d", influxql.MaxTime, end) 1351 } 1352 } 1353 1354 func TestIteratorOptions_SeekTime_Ascending(t *testing.T) { 1355 opt := query.IteratorOptions{ 1356 StartTime: 30, 1357 EndTime: 60, 1358 Ascending: true, 1359 } 1360 1361 time := opt.SeekTime() 1362 if time != 30 { 1363 t.Errorf("expected time to be 30, got %d", time) 1364 } 1365 } 1366 1367 func TestIteratorOptions_SeekTime_Descending(t *testing.T) { 1368 opt := query.IteratorOptions{ 1369 StartTime: 30, 1370 EndTime: 60, 1371 Ascending: false, 1372 } 1373 1374 time := opt.SeekTime() 1375 if time != 60 { 1376 t.Errorf("expected time to be 60, got %d", time) 1377 } 1378 } 1379 1380 func TestIteratorOptions_DerivativeInterval_Default(t *testing.T) { 1381 opt := query.IteratorOptions{} 1382 expected := query.Interval{Duration: time.Second} 1383 actual := opt.DerivativeInterval() 1384 if actual != expected { 1385 t.Errorf("expected derivative interval to be %v, got %v", expected, actual) 1386 } 1387 } 1388 1389 func TestIteratorOptions_DerivativeInterval_GroupBy(t *testing.T) { 1390 opt := query.IteratorOptions{ 1391 Interval: query.Interval{ 1392 Duration: 10, 1393 Offset: 2, 1394 }, 1395 } 1396 expected := query.Interval{Duration: 10} 1397 actual := opt.DerivativeInterval() 1398 if actual != expected { 1399 t.Errorf("expected derivative interval to be %v, got %v", expected, actual) 1400 } 1401 } 1402 1403 func TestIteratorOptions_DerivativeInterval_Call(t *testing.T) { 1404 opt := query.IteratorOptions{ 1405 Expr: &influxql.Call{ 1406 Name: "mean", 1407 Args: []influxql.Expr{ 1408 &influxql.VarRef{Val: "value"}, 1409 &influxql.DurationLiteral{Val: 2 * time.Second}, 1410 }, 1411 }, 1412 Interval: query.Interval{ 1413 Duration: 10, 1414 Offset: 2, 1415 }, 1416 } 1417 expected := query.Interval{Duration: 2 * time.Second} 1418 actual := opt.DerivativeInterval() 1419 if actual != expected { 1420 t.Errorf("expected derivative interval to be %v, got %v", expected, actual) 1421 } 1422 } 1423 1424 func TestIteratorOptions_ElapsedInterval_Default(t *testing.T) { 1425 opt := query.IteratorOptions{} 1426 expected := query.Interval{Duration: time.Nanosecond} 1427 actual := opt.ElapsedInterval() 1428 if actual != expected { 1429 t.Errorf("expected elapsed interval to be %v, got %v", expected, actual) 1430 } 1431 } 1432 1433 func TestIteratorOptions_ElapsedInterval_GroupBy(t *testing.T) { 1434 opt := query.IteratorOptions{ 1435 Interval: query.Interval{ 1436 Duration: 10, 1437 Offset: 2, 1438 }, 1439 } 1440 expected := query.Interval{Duration: time.Nanosecond} 1441 actual := opt.ElapsedInterval() 1442 if actual != expected { 1443 t.Errorf("expected elapsed interval to be %v, got %v", expected, actual) 1444 } 1445 } 1446 1447 func TestIteratorOptions_ElapsedInterval_Call(t *testing.T) { 1448 opt := query.IteratorOptions{ 1449 Expr: &influxql.Call{ 1450 Name: "mean", 1451 Args: []influxql.Expr{ 1452 &influxql.VarRef{Val: "value"}, 1453 &influxql.DurationLiteral{Val: 2 * time.Second}, 1454 }, 1455 }, 1456 Interval: query.Interval{ 1457 Duration: 10, 1458 Offset: 2, 1459 }, 1460 } 1461 expected := query.Interval{Duration: 2 * time.Second} 1462 actual := opt.ElapsedInterval() 1463 if actual != expected { 1464 t.Errorf("expected elapsed interval to be %v, got %v", expected, actual) 1465 } 1466 } 1467 1468 func TestIteratorOptions_IntegralInterval_Default(t *testing.T) { 1469 opt := query.IteratorOptions{} 1470 expected := query.Interval{Duration: time.Second} 1471 actual := opt.IntegralInterval() 1472 if actual != expected { 1473 t.Errorf("expected default integral interval to be %v, got %v", expected, actual) 1474 } 1475 } 1476 1477 // Ensure iterator options can be marshaled to and from a binary format. 1478 func TestIteratorOptions_MarshalBinary(t *testing.T) { 1479 opt := &query.IteratorOptions{ 1480 Expr: MustParseExpr("count(value)"), 1481 Aux: []influxql.VarRef{{Val: "a"}, {Val: "b"}, {Val: "c"}}, 1482 Interval: query.Interval{ 1483 Duration: 1 * time.Hour, 1484 Offset: 20 * time.Minute, 1485 }, 1486 Dimensions: []string{"region", "host"}, 1487 GroupBy: map[string]struct{}{ 1488 "region": {}, 1489 "host": {}, 1490 "cluster": {}, 1491 }, 1492 Fill: influxql.NumberFill, 1493 FillValue: float64(100), 1494 Condition: MustParseExpr(`foo = 'bar'`), 1495 StartTime: 1000, 1496 EndTime: 2000, 1497 Ascending: true, 1498 Limit: 100, 1499 Offset: 200, 1500 SLimit: 300, 1501 SOffset: 400, 1502 StripName: true, 1503 Dedupe: true, 1504 } 1505 1506 // Marshal to binary. 1507 buf, err := opt.MarshalBinary() 1508 if err != nil { 1509 t.Fatal(err) 1510 } 1511 1512 // Unmarshal back to an object. 1513 var other query.IteratorOptions 1514 if err := other.UnmarshalBinary(buf); err != nil { 1515 t.Fatal(err) 1516 } else if !reflect.DeepEqual(&other, opt) { 1517 t.Fatalf("unexpected options: %s", spew.Sdump(other)) 1518 } 1519 } 1520 1521 // Ensure iterator can be encoded and decoded over a byte stream. 1522 func TestIterator_EncodeDecode(t *testing.T) { 1523 var buf bytes.Buffer 1524 1525 // Create an iterator with several points & stats. 1526 itr := &FloatIterator{ 1527 Points: []query.FloatPoint{ 1528 {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 0}, 1529 {Name: "mem", Tags: ParseTags("host=B"), Time: 1, Value: 10}, 1530 }, 1531 stats: query.IteratorStats{ 1532 SeriesN: 2, 1533 PointN: 0, 1534 }, 1535 } 1536 1537 // Encode to the buffer. 1538 enc := query.NewIteratorEncoder(&buf) 1539 enc.StatsInterval = 100 * time.Millisecond 1540 if err := enc.EncodeIterator(itr); err != nil { 1541 t.Fatal(err) 1542 } 1543 1544 // Decode from the buffer. 1545 dec := query.NewReaderIterator(context.Background(), &buf, influxql.Float, itr.Stats()) 1546 1547 // Initial stats should exist immediately. 1548 fdec := dec.(query.FloatIterator) 1549 if stats := fdec.Stats(); !reflect.DeepEqual(stats, query.IteratorStats{SeriesN: 2, PointN: 0}) { 1550 t.Fatalf("unexpected stats(initial): %#v", stats) 1551 } 1552 1553 // Read both points. 1554 if p, err := fdec.Next(); err != nil { 1555 t.Fatalf("unexpected error(0): %#v", err) 1556 } else if !reflect.DeepEqual(p, &query.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 0}) { 1557 t.Fatalf("unexpected point(0); %#v", p) 1558 } 1559 if p, err := fdec.Next(); err != nil { 1560 t.Fatalf("unexpected error(1): %#v", err) 1561 } else if !reflect.DeepEqual(p, &query.FloatPoint{Name: "mem", Tags: ParseTags("host=B"), Time: 1, Value: 10}) { 1562 t.Fatalf("unexpected point(1); %#v", p) 1563 } 1564 if p, err := fdec.Next(); err != nil { 1565 t.Fatalf("unexpected error(eof): %#v", err) 1566 } else if p != nil { 1567 t.Fatalf("unexpected point(eof); %#v", p) 1568 } 1569 } 1570 1571 // Test implementation of query.IntegerIterator 1572 type IntegerConstIterator struct { 1573 numPoints int 1574 Closed bool 1575 stats query.IteratorStats 1576 point query.IntegerPoint 1577 } 1578 1579 func BenchmarkIterator_Aggregator(b *testing.B) { 1580 input := &IntegerConstIterator{ 1581 numPoints: b.N, 1582 Closed: false, 1583 stats: query.IteratorStats{}, 1584 point: query.IntegerPoint{ 1585 Name: "constPoint", 1586 Value: 1, 1587 }, 1588 } 1589 opt := query.IteratorOptions{ 1590 Interval: query.Interval{ 1591 Duration: 100 * time.Minute, 1592 }, 1593 Expr: &influxql.Call{ 1594 Name: "count", 1595 }, 1596 } 1597 1598 counter, err := query.NewCallIterator(input, opt) 1599 if err != nil { 1600 b.Fatalf("Bad counter: %v", err) 1601 } 1602 1603 b.ResetTimer() 1604 point, err := counter.(query.IntegerIterator).Next() 1605 if err != nil { 1606 b.Fatalf("Unexpected error %v", err) 1607 } 1608 if point == nil { 1609 b.Fatal("Expected point not to be nil") 1610 } 1611 if point.Value != int64(b.N) { 1612 b.Fatalf("Expected %v != %v points", b.N, point.Value) 1613 } 1614 } 1615 1616 func (itr *IntegerConstIterator) Stats() query.IteratorStats { return itr.stats } 1617 func (itr *IntegerConstIterator) Close() error { itr.Closed = true; return nil } 1618 1619 // Next returns the next value and shifts it off the beginning of the points slice. 1620 func (itr *IntegerConstIterator) Next() (*query.IntegerPoint, error) { 1621 if itr.numPoints == 0 || itr.Closed { 1622 return nil, nil 1623 } 1624 itr.numPoints-- 1625 itr.point.Time++ 1626 return &itr.point, nil 1627 } 1628 1629 // Test implementation of influxql.FloatIterator 1630 type FloatIterator struct { 1631 Context context.Context 1632 Points []query.FloatPoint 1633 Closed bool 1634 Delay time.Duration 1635 stats query.IteratorStats 1636 point query.FloatPoint 1637 } 1638 1639 func (itr *FloatIterator) Stats() query.IteratorStats { return itr.stats } 1640 func (itr *FloatIterator) Close() error { itr.Closed = true; return nil } 1641 1642 // Next returns the next value and shifts it off the beginning of the points slice. 1643 func (itr *FloatIterator) Next() (*query.FloatPoint, error) { 1644 if len(itr.Points) == 0 || itr.Closed { 1645 return nil, nil 1646 } 1647 1648 // If we have asked for a delay, then delay the returning of the point 1649 // until either an (optional) context is done or the time has passed. 1650 if itr.Delay > 0 { 1651 var done <-chan struct{} 1652 if itr.Context != nil { 1653 done = itr.Context.Done() 1654 } 1655 1656 timer := time.NewTimer(itr.Delay) 1657 select { 1658 case <-timer.C: 1659 case <-done: 1660 timer.Stop() 1661 return nil, itr.Context.Err() 1662 } 1663 } 1664 v := &itr.Points[0] 1665 itr.Points = itr.Points[1:] 1666 1667 // Copy the returned point into a static point that we return. 1668 // This actual storage engine returns a point from the same memory location 1669 // so we need to test that the query engine does not misuse this memory. 1670 itr.point.Name = v.Name 1671 itr.point.Tags = v.Tags 1672 itr.point.Time = v.Time 1673 itr.point.Value = v.Value 1674 itr.point.Nil = v.Nil 1675 if len(itr.point.Aux) != len(v.Aux) { 1676 itr.point.Aux = make([]interface{}, len(v.Aux)) 1677 } 1678 copy(itr.point.Aux, v.Aux) 1679 return &itr.point, nil 1680 } 1681 1682 func FloatIterators(inputs []*FloatIterator) []query.Iterator { 1683 itrs := make([]query.Iterator, len(inputs)) 1684 for i := range itrs { 1685 itrs[i] = query.Iterator(inputs[i]) 1686 } 1687 return itrs 1688 } 1689 1690 // Test implementation of query.IntegerIterator 1691 type IntegerIterator struct { 1692 Points []query.IntegerPoint 1693 Closed bool 1694 stats query.IteratorStats 1695 point query.IntegerPoint 1696 } 1697 1698 func (itr *IntegerIterator) Stats() query.IteratorStats { return itr.stats } 1699 func (itr *IntegerIterator) Close() error { itr.Closed = true; return nil } 1700 1701 // Next returns the next value and shifts it off the beginning of the points slice. 1702 func (itr *IntegerIterator) Next() (*query.IntegerPoint, error) { 1703 if len(itr.Points) == 0 || itr.Closed { 1704 return nil, nil 1705 } 1706 1707 v := &itr.Points[0] 1708 itr.Points = itr.Points[1:] 1709 1710 // Copy the returned point into a static point that we return. 1711 // This actual storage engine returns a point from the same memory location 1712 // so we need to test that the query engine does not misuse this memory. 1713 itr.point.Name = v.Name 1714 itr.point.Tags = v.Tags 1715 itr.point.Time = v.Time 1716 itr.point.Value = v.Value 1717 itr.point.Nil = v.Nil 1718 if len(itr.point.Aux) != len(v.Aux) { 1719 itr.point.Aux = make([]interface{}, len(v.Aux)) 1720 } 1721 copy(itr.point.Aux, v.Aux) 1722 return &itr.point, nil 1723 } 1724 1725 func IntegerIterators(inputs []*IntegerIterator) []query.Iterator { 1726 itrs := make([]query.Iterator, len(inputs)) 1727 for i := range itrs { 1728 itrs[i] = query.Iterator(inputs[i]) 1729 } 1730 return itrs 1731 } 1732 1733 // Test implementation of query.UnsignedIterator 1734 type UnsignedIterator struct { 1735 Points []query.UnsignedPoint 1736 Closed bool 1737 stats query.IteratorStats 1738 point query.UnsignedPoint 1739 } 1740 1741 func (itr *UnsignedIterator) Stats() query.IteratorStats { return itr.stats } 1742 func (itr *UnsignedIterator) Close() error { itr.Closed = true; return nil } 1743 1744 // Next returns the next value and shifts it off the beginning of the points slice. 1745 func (itr *UnsignedIterator) Next() (*query.UnsignedPoint, error) { 1746 if len(itr.Points) == 0 || itr.Closed { 1747 return nil, nil 1748 } 1749 1750 v := &itr.Points[0] 1751 itr.Points = itr.Points[1:] 1752 1753 // Copy the returned point into a static point that we return. 1754 // This actual storage engine returns a point from the same memory location 1755 // so we need to test that the query engine does not misuse this memory. 1756 itr.point.Name = v.Name 1757 itr.point.Tags = v.Tags 1758 itr.point.Time = v.Time 1759 itr.point.Value = v.Value 1760 itr.point.Nil = v.Nil 1761 if len(itr.point.Aux) != len(v.Aux) { 1762 itr.point.Aux = make([]interface{}, len(v.Aux)) 1763 } 1764 copy(itr.point.Aux, v.Aux) 1765 return &itr.point, nil 1766 } 1767 1768 func UnsignedIterators(inputs []*UnsignedIterator) []query.Iterator { 1769 itrs := make([]query.Iterator, len(inputs)) 1770 for i := range itrs { 1771 itrs[i] = query.Iterator(inputs[i]) 1772 } 1773 return itrs 1774 } 1775 1776 // Test implementation of query.StringIterator 1777 type StringIterator struct { 1778 Points []query.StringPoint 1779 Closed bool 1780 stats query.IteratorStats 1781 point query.StringPoint 1782 } 1783 1784 func (itr *StringIterator) Stats() query.IteratorStats { return itr.stats } 1785 func (itr *StringIterator) Close() error { itr.Closed = true; return nil } 1786 1787 // Next returns the next value and shifts it off the beginning of the points slice. 1788 func (itr *StringIterator) Next() (*query.StringPoint, error) { 1789 if len(itr.Points) == 0 || itr.Closed { 1790 return nil, nil 1791 } 1792 1793 v := &itr.Points[0] 1794 itr.Points = itr.Points[1:] 1795 1796 // Copy the returned point into a static point that we return. 1797 // This actual storage engine returns a point from the same memory location 1798 // so we need to test that the query engine does not misuse this memory. 1799 itr.point.Name = v.Name 1800 itr.point.Tags = v.Tags 1801 itr.point.Time = v.Time 1802 itr.point.Value = v.Value 1803 itr.point.Nil = v.Nil 1804 if len(itr.point.Aux) != len(v.Aux) { 1805 itr.point.Aux = make([]interface{}, len(v.Aux)) 1806 } 1807 copy(itr.point.Aux, v.Aux) 1808 return &itr.point, nil 1809 } 1810 1811 func StringIterators(inputs []*StringIterator) []query.Iterator { 1812 itrs := make([]query.Iterator, len(inputs)) 1813 for i := range itrs { 1814 itrs[i] = query.Iterator(inputs[i]) 1815 } 1816 return itrs 1817 } 1818 1819 // Test implementation of query.BooleanIterator 1820 type BooleanIterator struct { 1821 Points []query.BooleanPoint 1822 Closed bool 1823 stats query.IteratorStats 1824 point query.BooleanPoint 1825 } 1826 1827 func (itr *BooleanIterator) Stats() query.IteratorStats { return itr.stats } 1828 func (itr *BooleanIterator) Close() error { itr.Closed = true; return nil } 1829 1830 // Next returns the next value and shifts it off the beginning of the points slice. 1831 func (itr *BooleanIterator) Next() (*query.BooleanPoint, error) { 1832 if len(itr.Points) == 0 || itr.Closed { 1833 return nil, nil 1834 } 1835 1836 v := &itr.Points[0] 1837 itr.Points = itr.Points[1:] 1838 1839 // Copy the returned point into a static point that we return. 1840 // This actual storage engine returns a point from the same memory location 1841 // so we need to test that the query engine does not misuse this memory. 1842 itr.point.Name = v.Name 1843 itr.point.Tags = v.Tags 1844 itr.point.Time = v.Time 1845 itr.point.Value = v.Value 1846 itr.point.Nil = v.Nil 1847 if len(itr.point.Aux) != len(v.Aux) { 1848 itr.point.Aux = make([]interface{}, len(v.Aux)) 1849 } 1850 copy(itr.point.Aux, v.Aux) 1851 return &itr.point, nil 1852 } 1853 1854 func BooleanIterators(inputs []*BooleanIterator) []query.Iterator { 1855 itrs := make([]query.Iterator, len(inputs)) 1856 for i := range itrs { 1857 itrs[i] = query.Iterator(inputs[i]) 1858 } 1859 return itrs 1860 } 1861 1862 // MustParseSelectStatement parses a select statement. Panic on error. 1863 func MustParseSelectStatement(s string) *influxql.SelectStatement { 1864 stmt, err := influxql.NewParser(strings.NewReader(s)).ParseStatement() 1865 if err != nil { 1866 panic(err) 1867 } 1868 return stmt.(*influxql.SelectStatement) 1869 } 1870 1871 // MustParseExpr parses an expression. Panic on error. 1872 func MustParseExpr(s string) influxql.Expr { 1873 expr, err := influxql.NewParser(strings.NewReader(s)).ParseExpr() 1874 if err != nil { 1875 panic(err) 1876 } 1877 return expr 1878 } 1879 1880 // mustParseTime parses an IS0-8601 string. Panic on error. 1881 func mustParseTime(s string) time.Time { 1882 t, err := time.Parse(time.RFC3339, s) 1883 if err != nil { 1884 panic(err.Error()) 1885 } 1886 return t 1887 } 1888 1889 func mustLoadLocation(s string) *time.Location { 1890 l, err := time.LoadLocation(s) 1891 if err != nil { 1892 panic(err) 1893 } 1894 return l 1895 } 1896 1897 var LosAngeles = mustLoadLocation("America/Los_Angeles")