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")