github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/call_iterator_test.go (about)

     1  package query_test
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/influxdata/influxdb/v2/influxql/query"
     9  	"github.com/influxdata/influxql"
    10  )
    11  
    12  // Ensure that a float iterator can be created for a count() call.
    13  func TestCallIterator_Count_Float(t *testing.T) {
    14  	itr, _ := query.NewCallIterator(
    15  		&FloatIterator{Points: []query.FloatPoint{
    16  			{Name: "cpu", Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
    17  			{Name: "cpu", Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
    18  			{Name: "cpu", Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
    19  			{Name: "cpu", Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
    20  
    21  			{Name: "cpu", Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
    22  			{Name: "cpu", Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
    23  			{Name: "mem", Time: 23, Value: 10, Tags: ParseTags("region=us-west,host=hostB")},
    24  		}},
    25  		query.IteratorOptions{
    26  			Expr:       MustParseExpr(`count("value")`),
    27  			Dimensions: []string{"host"},
    28  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
    29  			Ordered:    true,
    30  			Ascending:  true,
    31  		},
    32  	)
    33  
    34  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
    35  		t.Fatalf("unexpected error: %s", err)
    36  	} else if diff := cmp.Diff(a, [][]query.Point{
    37  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 3, Tags: ParseTags("host=hostA"), Aggregated: 3}},
    38  		{&query.IntegerPoint{Name: "cpu", Time: 5, Value: 1, Tags: ParseTags("host=hostA"), Aggregated: 1}},
    39  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
    40  		{&query.IntegerPoint{Name: "cpu", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
    41  		{&query.IntegerPoint{Name: "mem", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
    42  	}); diff != "" {
    43  		t.Fatalf("unexpected points:\n%s", diff)
    44  	}
    45  }
    46  
    47  // Ensure that an integer iterator can be created for a count() call.
    48  func TestCallIterator_Count_Integer(t *testing.T) {
    49  	itr, _ := query.NewCallIterator(
    50  		&IntegerIterator{Points: []query.IntegerPoint{
    51  			{Name: "cpu", Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
    52  			{Name: "cpu", Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
    53  			{Name: "cpu", Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
    54  			{Name: "cpu", Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
    55  
    56  			{Name: "cpu", Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
    57  			{Name: "cpu", Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
    58  			{Name: "mem", Time: 23, Value: 10, Tags: ParseTags("region=us-west,host=hostB")},
    59  		}},
    60  		query.IteratorOptions{
    61  			Expr:       MustParseExpr(`count("value")`),
    62  			Dimensions: []string{"host"},
    63  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
    64  			Ordered:    true,
    65  			Ascending:  true,
    66  		},
    67  	)
    68  
    69  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
    70  		t.Fatalf("unexpected error: %s", err)
    71  	} else if diff := cmp.Diff(a, [][]query.Point{
    72  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 3, Tags: ParseTags("host=hostA"), Aggregated: 3}},
    73  		{&query.IntegerPoint{Name: "cpu", Time: 5, Value: 1, Tags: ParseTags("host=hostA"), Aggregated: 1}},
    74  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
    75  		{&query.IntegerPoint{Name: "cpu", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
    76  		{&query.IntegerPoint{Name: "mem", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
    77  	}); diff != "" {
    78  		t.Fatalf("unexpected points:\n%s", diff)
    79  	}
    80  }
    81  
    82  // Ensure that an unsigned iterator can be created for a count() call.
    83  func TestCallIterator_Count_Unsigned(t *testing.T) {
    84  	itr, _ := query.NewCallIterator(
    85  		&UnsignedIterator{Points: []query.UnsignedPoint{
    86  			{Name: "cpu", Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
    87  			{Name: "cpu", Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
    88  			{Name: "cpu", Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
    89  			{Name: "cpu", Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
    90  
    91  			{Name: "cpu", Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
    92  			{Name: "cpu", Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
    93  			{Name: "mem", Time: 23, Value: 10, Tags: ParseTags("region=us-west,host=hostB")},
    94  		}},
    95  		query.IteratorOptions{
    96  			Expr:       MustParseExpr(`count("value")`),
    97  			Dimensions: []string{"host"},
    98  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
    99  			Ordered:    true,
   100  			Ascending:  true,
   101  		},
   102  	)
   103  
   104  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   105  		t.Fatalf("unexpected error: %s", err)
   106  	} else if diff := cmp.Diff(a, [][]query.Point{
   107  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 3, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   108  		{&query.IntegerPoint{Name: "cpu", Time: 5, Value: 1, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   109  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   110  		{&query.IntegerPoint{Name: "cpu", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   111  		{&query.IntegerPoint{Name: "mem", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   112  	}); diff != "" {
   113  		t.Fatalf("unexpected points:\n%s", diff)
   114  	}
   115  }
   116  
   117  // Ensure that a string iterator can be created for a count() call.
   118  func TestCallIterator_Count_String(t *testing.T) {
   119  	itr, _ := query.NewCallIterator(
   120  		&StringIterator{Points: []query.StringPoint{
   121  			{Name: "cpu", Time: 0, Value: "d", Tags: ParseTags("region=us-east,host=hostA")},
   122  			{Name: "cpu", Time: 2, Value: "b", Tags: ParseTags("region=us-east,host=hostA")},
   123  			{Name: "cpu", Time: 1, Value: "b", Tags: ParseTags("region=us-west,host=hostA")},
   124  			{Name: "cpu", Time: 5, Value: "e", Tags: ParseTags("region=us-east,host=hostA")},
   125  
   126  			{Name: "cpu", Time: 1, Value: "c", Tags: ParseTags("region=us-west,host=hostB")},
   127  			{Name: "cpu", Time: 23, Value: "a", Tags: ParseTags("region=us-west,host=hostB")},
   128  			{Name: "mem", Time: 23, Value: "b", Tags: ParseTags("region=us-west,host=hostB")},
   129  		}},
   130  		query.IteratorOptions{
   131  			Expr:       MustParseExpr(`count("value")`),
   132  			Dimensions: []string{"host"},
   133  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   134  			Ordered:    true,
   135  			Ascending:  true,
   136  		},
   137  	)
   138  
   139  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   140  		t.Fatalf("unexpected error: %s", err)
   141  	} else if diff := cmp.Diff(a, [][]query.Point{
   142  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 3, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   143  		{&query.IntegerPoint{Name: "cpu", Time: 5, Value: 1, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   144  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   145  		{&query.IntegerPoint{Name: "cpu", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   146  		{&query.IntegerPoint{Name: "mem", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   147  	}); diff != "" {
   148  		t.Fatalf("unexpected points:\n%s", diff)
   149  	}
   150  }
   151  
   152  // Ensure that a boolean iterator can be created for a count() call.
   153  func TestCallIterator_Count_Boolean(t *testing.T) {
   154  	itr, _ := query.NewCallIterator(
   155  		&BooleanIterator{Points: []query.BooleanPoint{
   156  			{Name: "cpu", Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
   157  			{Name: "cpu", Time: 2, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   158  			{Name: "cpu", Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostA")},
   159  			{Name: "cpu", Time: 5, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   160  
   161  			{Name: "cpu", Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
   162  			{Name: "cpu", Time: 23, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
   163  			{Name: "mem", Time: 23, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
   164  		}},
   165  		query.IteratorOptions{
   166  			Expr:       MustParseExpr(`count("value")`),
   167  			Dimensions: []string{"host"},
   168  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   169  			Ordered:    true,
   170  			Ascending:  true,
   171  		},
   172  	)
   173  
   174  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   175  		t.Fatalf("unexpected error: %s", err)
   176  	} else if diff := cmp.Diff(a, [][]query.Point{
   177  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 3, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   178  		{&query.IntegerPoint{Name: "cpu", Time: 5, Value: 1, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   179  		{&query.IntegerPoint{Name: "cpu", Time: 0, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   180  		{&query.IntegerPoint{Name: "cpu", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   181  		{&query.IntegerPoint{Name: "mem", Time: 20, Value: 1, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   182  	}); diff != "" {
   183  		t.Fatalf("unexpected points:\n%s", diff)
   184  	}
   185  }
   186  
   187  // Ensure that a float iterator can be created for a min() call.
   188  func TestCallIterator_Min_Float(t *testing.T) {
   189  	itr, _ := query.NewCallIterator(
   190  		&FloatIterator{Points: []query.FloatPoint{
   191  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   192  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   193  			{Time: 4, Value: 12, Tags: ParseTags("region=us-east,host=hostA")},
   194  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   195  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   196  
   197  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   198  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   199  		}},
   200  		query.IteratorOptions{
   201  			Expr:       MustParseExpr(`min("value")`),
   202  			Dimensions: []string{"host"},
   203  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   204  			Ordered:    true,
   205  			Ascending:  true,
   206  		},
   207  	)
   208  
   209  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   210  		t.Fatalf("unexpected error: %s", err)
   211  	} else if diff := cmp.Diff(a, [][]query.Point{
   212  		{&query.FloatPoint{Time: 1, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 4}},
   213  		{&query.FloatPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   214  		{&query.FloatPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   215  		{&query.FloatPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   216  	}); diff != "" {
   217  		t.Fatalf("unexpected points:\n%s", diff)
   218  	}
   219  }
   220  
   221  // Ensure that a integer iterator can be created for a min() call.
   222  func TestCallIterator_Min_Integer(t *testing.T) {
   223  	itr, _ := query.NewCallIterator(
   224  		&IntegerIterator{Points: []query.IntegerPoint{
   225  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   226  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   227  			{Time: 4, Value: 12, Tags: ParseTags("region=us-east,host=hostA")},
   228  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   229  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   230  
   231  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   232  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   233  		}},
   234  		query.IteratorOptions{
   235  			Expr:       MustParseExpr(`min("value")`),
   236  			Dimensions: []string{"host"},
   237  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   238  			Ordered:    true,
   239  			Ascending:  true,
   240  		},
   241  	)
   242  
   243  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   244  		t.Fatalf("unexpected error: %s", err)
   245  	} else if diff := cmp.Diff(a, [][]query.Point{
   246  		{&query.IntegerPoint{Time: 1, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 4}},
   247  		{&query.IntegerPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   248  		{&query.IntegerPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   249  		{&query.IntegerPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   250  	}); diff != "" {
   251  		t.Fatalf("unexpected points:\n%s", diff)
   252  	}
   253  }
   254  
   255  // Ensure that a unsigned iterator can be created for a min() call.
   256  func TestCallIterator_Min_Unsigned(t *testing.T) {
   257  	itr, _ := query.NewCallIterator(
   258  		&UnsignedIterator{Points: []query.UnsignedPoint{
   259  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   260  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   261  			{Time: 4, Value: 12, Tags: ParseTags("region=us-east,host=hostA")},
   262  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   263  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   264  
   265  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   266  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   267  		}},
   268  		query.IteratorOptions{
   269  			Expr:       MustParseExpr(`min("value")`),
   270  			Dimensions: []string{"host"},
   271  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   272  			Ordered:    true,
   273  			Ascending:  true,
   274  		},
   275  	)
   276  
   277  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   278  		t.Fatalf("unexpected error: %s", err)
   279  	} else if diff := cmp.Diff(a, [][]query.Point{
   280  		{&query.UnsignedPoint{Time: 1, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 4}},
   281  		{&query.UnsignedPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   282  		{&query.UnsignedPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   283  		{&query.UnsignedPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   284  	}); diff != "" {
   285  		t.Fatalf("unexpected points:\n%s", diff)
   286  	}
   287  }
   288  
   289  // Ensure that a boolean iterator can be created for a min() call.
   290  func TestCallIterator_Min_Boolean(t *testing.T) {
   291  	itr, _ := query.NewCallIterator(
   292  		&BooleanIterator{Points: []query.BooleanPoint{
   293  			{Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
   294  			{Time: 2, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   295  			{Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostA")},
   296  			{Time: 5, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   297  
   298  			{Time: 1, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
   299  			{Time: 23, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
   300  		}},
   301  		query.IteratorOptions{
   302  			Expr:       MustParseExpr(`min("value")`),
   303  			Dimensions: []string{"host"},
   304  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   305  			Ordered:    true,
   306  			Ascending:  true,
   307  		},
   308  	)
   309  
   310  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   311  		t.Fatalf("unexpected error: %s", err)
   312  	} else if diff := cmp.Diff(a, [][]query.Point{
   313  		{&query.BooleanPoint{Time: 2, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   314  		{&query.BooleanPoint{Time: 5, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   315  		{&query.BooleanPoint{Time: 1, Value: false, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   316  		{&query.BooleanPoint{Time: 23, Value: true, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   317  	}); diff != "" {
   318  		t.Fatalf("unexpected points:\n%s", diff)
   319  	}
   320  }
   321  
   322  // Ensure that a float iterator can be created for a max() call.
   323  func TestCallIterator_Max_Float(t *testing.T) {
   324  	itr, _ := query.NewCallIterator(
   325  		&FloatIterator{Points: []query.FloatPoint{
   326  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   327  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   328  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   329  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   330  
   331  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   332  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   333  		}},
   334  		query.IteratorOptions{
   335  			Expr:       MustParseExpr(`max("value")`),
   336  			Dimensions: []string{"host"},
   337  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   338  			Ordered:    true,
   339  			Ascending:  true,
   340  		},
   341  	)
   342  
   343  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   344  		t.Fatalf("unexpected error: %s", err)
   345  	} else if diff := cmp.Diff(a, [][]query.Point{
   346  		{&query.FloatPoint{Time: 0, Value: 15, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   347  		{&query.FloatPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   348  		{&query.FloatPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   349  		{&query.FloatPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   350  	}); diff != "" {
   351  		t.Fatalf("unexpected points:\n%s", diff)
   352  	}
   353  }
   354  
   355  // Ensure that a integer iterator can be created for a max() call.
   356  func TestCallIterator_Max_Integer(t *testing.T) {
   357  	itr, _ := query.NewCallIterator(
   358  		&IntegerIterator{Points: []query.IntegerPoint{
   359  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   360  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   361  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   362  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   363  
   364  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   365  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   366  		}},
   367  		query.IteratorOptions{
   368  			Expr:       MustParseExpr(`max("value")`),
   369  			Dimensions: []string{"host"},
   370  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   371  			Ordered:    true,
   372  			Ascending:  true,
   373  		},
   374  	)
   375  
   376  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   377  		t.Fatalf("unexpected error: %s", err)
   378  	} else if diff := cmp.Diff(a, [][]query.Point{
   379  		{&query.IntegerPoint{Time: 0, Value: 15, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   380  		{&query.IntegerPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   381  		{&query.IntegerPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   382  		{&query.IntegerPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   383  	}); diff != "" {
   384  		t.Fatalf("unexpected points:\n%s", diff)
   385  	}
   386  }
   387  
   388  // Ensure that a unsigned iterator can be created for a max() call.
   389  func TestCallIterator_Max_Unsigned(t *testing.T) {
   390  	itr, _ := query.NewCallIterator(
   391  		&UnsignedIterator{Points: []query.UnsignedPoint{
   392  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   393  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   394  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   395  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   396  
   397  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   398  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   399  		}},
   400  		query.IteratorOptions{
   401  			Expr:       MustParseExpr(`max("value")`),
   402  			Dimensions: []string{"host"},
   403  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   404  			Ordered:    true,
   405  			Ascending:  true,
   406  		},
   407  	)
   408  
   409  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   410  		t.Fatalf("unexpected error: %s", err)
   411  	} else if diff := cmp.Diff(a, [][]query.Point{
   412  		{&query.UnsignedPoint{Time: 0, Value: 15, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   413  		{&query.UnsignedPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   414  		{&query.UnsignedPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   415  		{&query.UnsignedPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   416  	}); diff != "" {
   417  		t.Fatalf("unexpected points:\n%s", diff)
   418  	}
   419  }
   420  
   421  // Ensure that a boolean iterator can be created for a max() call.
   422  func TestCallIterator_Max_Boolean(t *testing.T) {
   423  	itr, _ := query.NewCallIterator(
   424  		&BooleanIterator{Points: []query.BooleanPoint{
   425  			{Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
   426  			{Time: 2, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   427  			{Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostA")},
   428  			{Time: 5, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   429  
   430  			{Time: 1, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
   431  			{Time: 23, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
   432  		}},
   433  		query.IteratorOptions{
   434  			Expr:       MustParseExpr(`max("value")`),
   435  			Dimensions: []string{"host"},
   436  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   437  			Ordered:    true,
   438  			Ascending:  true,
   439  		},
   440  	)
   441  
   442  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   443  		t.Fatalf("unexpected error: %s", err)
   444  	} else if diff := cmp.Diff(a, [][]query.Point{
   445  		{&query.BooleanPoint{Time: 0, Value: true, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   446  		{&query.BooleanPoint{Time: 5, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   447  		{&query.BooleanPoint{Time: 1, Value: false, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   448  		{&query.BooleanPoint{Time: 23, Value: true, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   449  	}); diff != "" {
   450  		t.Fatalf("unexpected points:\n%s", diff)
   451  	}
   452  }
   453  
   454  // Ensure that a float iterator can be created for a sum() call.
   455  func TestCallIterator_Sum_Float(t *testing.T) {
   456  	itr, _ := query.NewCallIterator(
   457  		&FloatIterator{Points: []query.FloatPoint{
   458  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   459  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   460  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   461  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   462  
   463  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   464  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   465  		}},
   466  		query.IteratorOptions{
   467  			Expr:       MustParseExpr(`sum("value")`),
   468  			Dimensions: []string{"host"},
   469  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   470  			Ordered:    true,
   471  			Ascending:  true,
   472  		},
   473  	)
   474  
   475  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   476  		t.Fatalf("unexpected error: %s", err)
   477  	} else if diff := cmp.Diff(a, [][]query.Point{
   478  		{&query.FloatPoint{Time: 0, Value: 35, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   479  		{&query.FloatPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   480  		{&query.FloatPoint{Time: 0, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   481  		{&query.FloatPoint{Time: 20, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   482  	}); diff != "" {
   483  		t.Fatalf("unexpected points:\n%s", diff)
   484  	}
   485  }
   486  
   487  // Ensure that an integer iterator can be created for a sum() call.
   488  func TestCallIterator_Sum_Integer(t *testing.T) {
   489  	itr, _ := query.NewCallIterator(
   490  		&IntegerIterator{Points: []query.IntegerPoint{
   491  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   492  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   493  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   494  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   495  
   496  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   497  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   498  		}},
   499  		query.IteratorOptions{
   500  			Expr:       MustParseExpr(`sum("value")`),
   501  			Dimensions: []string{"host"},
   502  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   503  			Ordered:    true,
   504  			Ascending:  true,
   505  		},
   506  	)
   507  
   508  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   509  		t.Fatalf("unexpected error: %s", err)
   510  	} else if diff := cmp.Diff(a, [][]query.Point{
   511  		{&query.IntegerPoint{Time: 0, Value: 35, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   512  		{&query.IntegerPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   513  		{&query.IntegerPoint{Time: 0, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   514  		{&query.IntegerPoint{Time: 20, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   515  	}); diff != "" {
   516  		t.Fatalf("unexpected points:\n%s", diff)
   517  	}
   518  }
   519  
   520  // Ensure that an unsigned iterator can be created for a sum() call.
   521  func TestCallIterator_Sum_Unsigned(t *testing.T) {
   522  	itr, _ := query.NewCallIterator(
   523  		&UnsignedIterator{Points: []query.UnsignedPoint{
   524  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   525  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   526  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   527  			{Time: 5, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   528  
   529  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   530  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   531  		}},
   532  		query.IteratorOptions{
   533  			Expr:       MustParseExpr(`sum("value")`),
   534  			Dimensions: []string{"host"},
   535  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   536  			Ordered:    true,
   537  			Ascending:  true,
   538  		},
   539  	)
   540  
   541  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   542  		t.Fatalf("unexpected error: %s", err)
   543  	} else if diff := cmp.Diff(a, [][]query.Point{
   544  		{&query.UnsignedPoint{Time: 0, Value: 35, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   545  		{&query.UnsignedPoint{Time: 5, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   546  		{&query.UnsignedPoint{Time: 0, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   547  		{&query.UnsignedPoint{Time: 20, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   548  	}); diff != "" {
   549  		t.Fatalf("unexpected points:\n%s", diff)
   550  	}
   551  }
   552  
   553  // Ensure that a float iterator can be created for a first() call.
   554  func TestCallIterator_First_Float(t *testing.T) {
   555  	itr, _ := query.NewCallIterator(
   556  		&FloatIterator{Points: []query.FloatPoint{
   557  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   558  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   559  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   560  			{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   561  
   562  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   563  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   564  		}},
   565  		query.IteratorOptions{
   566  			Expr:       MustParseExpr(`first("value")`),
   567  			Dimensions: []string{"host"},
   568  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   569  			Ordered:    true,
   570  			Ascending:  true,
   571  		},
   572  	)
   573  
   574  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   575  		t.Fatalf("unexpected error: %s", err)
   576  	} else if diff := cmp.Diff(a, [][]query.Point{
   577  		{&query.FloatPoint{Time: 0, Value: 15, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   578  		{&query.FloatPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   579  		{&query.FloatPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   580  		{&query.FloatPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   581  	}); diff != "" {
   582  		t.Fatalf("unexpected points:\n%s", diff)
   583  	}
   584  }
   585  
   586  // Ensure that an integer iterator can be created for a first() call.
   587  func TestCallIterator_First_Integer(t *testing.T) {
   588  	itr, _ := query.NewCallIterator(
   589  		&IntegerIterator{Points: []query.IntegerPoint{
   590  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   591  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   592  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   593  			{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   594  
   595  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   596  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   597  		}},
   598  		query.IteratorOptions{
   599  			Expr:       MustParseExpr(`first("value")`),
   600  			Dimensions: []string{"host"},
   601  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   602  			Ordered:    true,
   603  			Ascending:  true,
   604  		},
   605  	)
   606  
   607  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   608  		t.Fatalf("unexpected error: %s", err)
   609  	} else if diff := cmp.Diff(a, [][]query.Point{
   610  		{&query.IntegerPoint{Time: 0, Value: 15, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   611  		{&query.IntegerPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   612  		{&query.IntegerPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   613  		{&query.IntegerPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   614  	}); diff != "" {
   615  		t.Fatalf("unexpected points:\n%s", diff)
   616  	}
   617  }
   618  
   619  // Ensure that an unsigned iterator can be created for a first() call.
   620  func TestCallIterator_First_Unsigned(t *testing.T) {
   621  	itr, _ := query.NewCallIterator(
   622  		&UnsignedIterator{Points: []query.UnsignedPoint{
   623  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   624  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   625  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   626  			{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   627  
   628  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   629  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   630  		}},
   631  		query.IteratorOptions{
   632  			Expr:       MustParseExpr(`first("value")`),
   633  			Dimensions: []string{"host"},
   634  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   635  			Ordered:    true,
   636  			Ascending:  true,
   637  		},
   638  	)
   639  
   640  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   641  		t.Fatalf("unexpected error: %s", err)
   642  	} else if diff := cmp.Diff(a, [][]query.Point{
   643  		{&query.UnsignedPoint{Time: 0, Value: 15, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   644  		{&query.UnsignedPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   645  		{&query.UnsignedPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   646  		{&query.UnsignedPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   647  	}); diff != "" {
   648  		t.Fatalf("unexpected points:\n%s", diff)
   649  	}
   650  }
   651  
   652  // Ensure that a string iterator can be created for a first() call.
   653  func TestCallIterator_First_String(t *testing.T) {
   654  	itr, _ := query.NewCallIterator(
   655  		&StringIterator{Points: []query.StringPoint{
   656  			{Time: 2, Value: "b", Tags: ParseTags("region=us-east,host=hostA")},
   657  			{Time: 0, Value: "d", Tags: ParseTags("region=us-east,host=hostA")},
   658  			{Time: 1, Value: "b", Tags: ParseTags("region=us-west,host=hostA")},
   659  			{Time: 6, Value: "e", Tags: ParseTags("region=us-east,host=hostA")},
   660  
   661  			{Time: 1, Value: "c", Tags: ParseTags("region=us-west,host=hostB")},
   662  			{Time: 23, Value: "a", Tags: ParseTags("region=us-west,host=hostB")},
   663  		}},
   664  		query.IteratorOptions{
   665  			Expr:       MustParseExpr(`first("value")`),
   666  			Dimensions: []string{"host"},
   667  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   668  			Ordered:    true,
   669  			Ascending:  true,
   670  		},
   671  	)
   672  
   673  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   674  		t.Fatalf("unexpected error: %s", err)
   675  	} else if diff := cmp.Diff(a, [][]query.Point{
   676  		{&query.StringPoint{Time: 0, Value: "d", Tags: ParseTags("host=hostA"), Aggregated: 3}},
   677  		{&query.StringPoint{Time: 6, Value: "e", Tags: ParseTags("host=hostA"), Aggregated: 1}},
   678  		{&query.StringPoint{Time: 1, Value: "c", Tags: ParseTags("host=hostB"), Aggregated: 1}},
   679  		{&query.StringPoint{Time: 23, Value: "a", Tags: ParseTags("host=hostB"), Aggregated: 1}},
   680  	}); diff != "" {
   681  		t.Fatalf("unexpected points:\n%s", diff)
   682  	}
   683  }
   684  
   685  // Ensure that a boolean iterator can be created for a first() call.
   686  func TestCallIterator_First_Boolean(t *testing.T) {
   687  	itr, _ := query.NewCallIterator(
   688  		&BooleanIterator{Points: []query.BooleanPoint{
   689  			{Time: 2, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   690  			{Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
   691  			{Time: 1, Value: false, Tags: ParseTags("region=us-west,host=hostA")},
   692  			{Time: 6, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   693  
   694  			{Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
   695  			{Time: 23, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
   696  		}},
   697  		query.IteratorOptions{
   698  			Expr:       MustParseExpr(`first("value")`),
   699  			Dimensions: []string{"host"},
   700  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   701  			Ordered:    true,
   702  			Ascending:  true,
   703  		},
   704  	)
   705  
   706  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   707  		t.Fatalf("unexpected error: %s", err)
   708  	} else if diff := cmp.Diff(a, [][]query.Point{
   709  		{&query.BooleanPoint{Time: 0, Value: true, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   710  		{&query.BooleanPoint{Time: 6, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   711  		{&query.BooleanPoint{Time: 1, Value: true, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   712  		{&query.BooleanPoint{Time: 23, Value: false, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   713  	}); diff != "" {
   714  		t.Fatalf("unexpected points:\n%s", diff)
   715  	}
   716  }
   717  
   718  // Ensure that a float iterator can be created for a last() call.
   719  func TestCallIterator_Last_Float(t *testing.T) {
   720  	itr, _ := query.NewCallIterator(
   721  		&FloatIterator{Points: []query.FloatPoint{
   722  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   723  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   724  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   725  			{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   726  
   727  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   728  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   729  		}},
   730  		query.IteratorOptions{
   731  			Expr:       MustParseExpr(`last("value")`),
   732  			Dimensions: []string{"host"},
   733  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   734  			Ordered:    true,
   735  			Ascending:  true,
   736  		},
   737  	)
   738  
   739  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   740  		t.Fatalf("unexpected error: %s", err)
   741  	} else if diff := cmp.Diff(a, [][]query.Point{
   742  		{&query.FloatPoint{Time: 2, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   743  		{&query.FloatPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   744  		{&query.FloatPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   745  		{&query.FloatPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   746  	}); diff != "" {
   747  		t.Fatalf("unexpected points:\n%s", diff)
   748  	}
   749  }
   750  
   751  // Ensure that an integer iterator can be created for a last() call.
   752  func TestCallIterator_Last_Integer(t *testing.T) {
   753  	itr, _ := query.NewCallIterator(
   754  		&IntegerIterator{Points: []query.IntegerPoint{
   755  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   756  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   757  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   758  			{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   759  
   760  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   761  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   762  		}},
   763  		query.IteratorOptions{
   764  			Expr:       MustParseExpr(`last("value")`),
   765  			Dimensions: []string{"host"},
   766  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   767  			Ordered:    true,
   768  			Ascending:  true,
   769  		},
   770  	)
   771  
   772  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   773  		t.Fatalf("unexpected error: %s", err)
   774  	} else if diff := cmp.Diff(a, [][]query.Point{
   775  		{&query.IntegerPoint{Time: 2, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   776  		{&query.IntegerPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   777  		{&query.IntegerPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   778  		{&query.IntegerPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   779  	}); diff != "" {
   780  		t.Fatalf("unexpected points:\n%s", diff)
   781  	}
   782  }
   783  
   784  // Ensure that an unsigned iterator can be created for a last() call.
   785  func TestCallIterator_Last_Unsigned(t *testing.T) {
   786  	itr, _ := query.NewCallIterator(
   787  		&UnsignedIterator{Points: []query.UnsignedPoint{
   788  			{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   789  			{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   790  			{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   791  			{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   792  
   793  			{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   794  			{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   795  		}},
   796  		query.IteratorOptions{
   797  			Expr:       MustParseExpr(`last("value")`),
   798  			Dimensions: []string{"host"},
   799  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   800  			Ordered:    true,
   801  			Ascending:  true,
   802  		},
   803  	)
   804  
   805  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   806  		t.Fatalf("unexpected error: %s", err)
   807  	} else if diff := cmp.Diff(a, [][]query.Point{
   808  		{&query.UnsignedPoint{Time: 2, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   809  		{&query.UnsignedPoint{Time: 6, Value: 20, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   810  		{&query.UnsignedPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   811  		{&query.UnsignedPoint{Time: 23, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   812  	}); diff != "" {
   813  		t.Fatalf("unexpected points:\n%s", diff)
   814  	}
   815  }
   816  
   817  // Ensure that a string iterator can be created for a last() call.
   818  func TestCallIterator_Last_String(t *testing.T) {
   819  	itr, _ := query.NewCallIterator(
   820  		&StringIterator{Points: []query.StringPoint{
   821  			{Time: 2, Value: "b", Tags: ParseTags("region=us-east,host=hostA")},
   822  			{Time: 0, Value: "d", Tags: ParseTags("region=us-east,host=hostA")},
   823  			{Time: 1, Value: "b", Tags: ParseTags("region=us-west,host=hostA")},
   824  			{Time: 6, Value: "e", Tags: ParseTags("region=us-east,host=hostA")},
   825  
   826  			{Time: 1, Value: "c", Tags: ParseTags("region=us-west,host=hostB")},
   827  			{Time: 23, Value: "a", Tags: ParseTags("region=us-west,host=hostB")},
   828  		}},
   829  		query.IteratorOptions{
   830  			Expr:       MustParseExpr(`last("value")`),
   831  			Dimensions: []string{"host"},
   832  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   833  			Ordered:    true,
   834  			Ascending:  true,
   835  		},
   836  	)
   837  
   838  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   839  		t.Fatalf("unexpected error: %s", err)
   840  	} else if diff := cmp.Diff(a, [][]query.Point{
   841  		{&query.StringPoint{Time: 2, Value: "b", Tags: ParseTags("host=hostA"), Aggregated: 3}},
   842  		{&query.StringPoint{Time: 6, Value: "e", Tags: ParseTags("host=hostA"), Aggregated: 1}},
   843  		{&query.StringPoint{Time: 1, Value: "c", Tags: ParseTags("host=hostB"), Aggregated: 1}},
   844  		{&query.StringPoint{Time: 23, Value: "a", Tags: ParseTags("host=hostB"), Aggregated: 1}},
   845  	}); diff != "" {
   846  		t.Fatalf("unexpected points:\n%s", diff)
   847  	}
   848  }
   849  
   850  // Ensure that a boolean iterator can be created for a last() call.
   851  func TestCallIterator_Last_Boolean(t *testing.T) {
   852  	itr, _ := query.NewCallIterator(
   853  		&BooleanIterator{Points: []query.BooleanPoint{
   854  			{Time: 2, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   855  			{Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
   856  			{Time: 1, Value: false, Tags: ParseTags("region=us-west,host=hostA")},
   857  			{Time: 6, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
   858  
   859  			{Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
   860  			{Time: 23, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
   861  		}},
   862  		query.IteratorOptions{
   863  			Expr:       MustParseExpr(`last("value")`),
   864  			Dimensions: []string{"host"},
   865  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   866  			Ordered:    true,
   867  			Ascending:  true,
   868  		},
   869  	)
   870  
   871  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   872  		t.Fatalf("unexpected error: %s", err)
   873  	} else if diff := cmp.Diff(a, [][]query.Point{
   874  		{&query.BooleanPoint{Time: 2, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 3}},
   875  		{&query.BooleanPoint{Time: 6, Value: false, Tags: ParseTags("host=hostA"), Aggregated: 1}},
   876  		{&query.BooleanPoint{Time: 1, Value: true, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   877  		{&query.BooleanPoint{Time: 23, Value: false, Tags: ParseTags("host=hostB"), Aggregated: 1}},
   878  	}); diff != "" {
   879  		t.Fatalf("unexpected points:\n%s", diff)
   880  	}
   881  }
   882  
   883  // Ensure that a float iterator can be created for a mode() call.
   884  func TestCallIterator_Mode_Float(t *testing.T) {
   885  	itr, _ := query.NewModeIterator(&FloatIterator{Points: []query.FloatPoint{
   886  		{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   887  		{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   888  		{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   889  		{Time: 3, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   890  		{Time: 4, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   891  		{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   892  		{Time: 7, Value: 21, Tags: ParseTags("region=us-east,host=hostA")},
   893  		{Time: 8, Value: 21, Tags: ParseTags("region=us-east,host=hostA")},
   894  
   895  		{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   896  		{Time: 22, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   897  		{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   898  		{Time: 24, Value: 25, Tags: ParseTags("region=us-west,host=hostB")},
   899  	}},
   900  		query.IteratorOptions{
   901  			Expr:       MustParseExpr(`mode("value")`),
   902  			Dimensions: []string{"host"},
   903  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   904  			Ordered:    true,
   905  			Ascending:  true,
   906  		},
   907  	)
   908  
   909  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   910  		t.Fatalf("unexpected error: %s", err)
   911  	} else if diff := cmp.Diff(a, [][]query.Point{
   912  		{&query.FloatPoint{Time: 0, Value: 10, Tags: ParseTags("host=hostA"), Aggregated: 0}},
   913  		{&query.FloatPoint{Time: 5, Value: 21, Tags: ParseTags("host=hostA"), Aggregated: 0}},
   914  		{&query.FloatPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB"), Aggregated: 0}},
   915  		{&query.FloatPoint{Time: 20, Value: 8, Tags: ParseTags("host=hostB"), Aggregated: 0}},
   916  	}); diff != "" {
   917  		t.Fatalf("unexpected points:\n%s", diff)
   918  	}
   919  }
   920  
   921  // Ensure that a integer iterator can be created for a mode() call.
   922  func TestCallIterator_Mode_Integer(t *testing.T) {
   923  	itr, _ := query.NewModeIterator(&IntegerIterator{Points: []query.IntegerPoint{
   924  		{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   925  		{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   926  		{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   927  		{Time: 3, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   928  		{Time: 4, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   929  		{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   930  		{Time: 7, Value: 21, Tags: ParseTags("region=us-east,host=hostA")},
   931  		{Time: 8, Value: 21, Tags: ParseTags("region=us-east,host=hostA")},
   932  		{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   933  		{Time: 22, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   934  		{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   935  		{Time: 24, Value: 25, Tags: ParseTags("region=us-west,host=hostB")},
   936  	}},
   937  		query.IteratorOptions{
   938  			Expr:       MustParseExpr(`mode("value")`),
   939  			Dimensions: []string{"host"},
   940  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   941  			Ordered:    true,
   942  			Ascending:  true,
   943  		},
   944  	)
   945  
   946  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   947  		t.Fatalf("unexpected error: %s", err)
   948  	} else if diff := cmp.Diff(a, [][]query.Point{
   949  		{&query.IntegerPoint{Time: 0, Value: 10, Tags: ParseTags("host=hostA")}},
   950  		{&query.IntegerPoint{Time: 5, Value: 21, Tags: ParseTags("host=hostA")}},
   951  		{&query.IntegerPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB")}},
   952  		{&query.IntegerPoint{Time: 20, Value: 8, Tags: ParseTags("host=hostB")}},
   953  	}); diff != "" {
   954  		t.Fatalf("unexpected points:\n%s", diff)
   955  	}
   956  }
   957  
   958  // Ensure that a unsigned iterator can be created for a mode() call.
   959  func TestCallIterator_Mode_Unsigned(t *testing.T) {
   960  	itr, _ := query.NewModeIterator(&UnsignedIterator{Points: []query.UnsignedPoint{
   961  		{Time: 0, Value: 15, Tags: ParseTags("region=us-east,host=hostA")},
   962  		{Time: 1, Value: 10, Tags: ParseTags("region=us-west,host=hostA")},
   963  		{Time: 2, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   964  		{Time: 3, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   965  		{Time: 4, Value: 10, Tags: ParseTags("region=us-east,host=hostA")},
   966  		{Time: 6, Value: 20, Tags: ParseTags("region=us-east,host=hostA")},
   967  		{Time: 7, Value: 21, Tags: ParseTags("region=us-east,host=hostA")},
   968  		{Time: 8, Value: 21, Tags: ParseTags("region=us-east,host=hostA")},
   969  		{Time: 1, Value: 11, Tags: ParseTags("region=us-west,host=hostB")},
   970  		{Time: 22, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   971  		{Time: 23, Value: 8, Tags: ParseTags("region=us-west,host=hostB")},
   972  		{Time: 24, Value: 25, Tags: ParseTags("region=us-west,host=hostB")},
   973  	}},
   974  		query.IteratorOptions{
   975  			Expr:       MustParseExpr(`mode("value")`),
   976  			Dimensions: []string{"host"},
   977  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
   978  			Ordered:    true,
   979  			Ascending:  true,
   980  		},
   981  	)
   982  
   983  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
   984  		t.Fatalf("unexpected error: %s", err)
   985  	} else if diff := cmp.Diff(a, [][]query.Point{
   986  		{&query.UnsignedPoint{Time: 0, Value: 10, Tags: ParseTags("host=hostA")}},
   987  		{&query.UnsignedPoint{Time: 5, Value: 21, Tags: ParseTags("host=hostA")}},
   988  		{&query.UnsignedPoint{Time: 1, Value: 11, Tags: ParseTags("host=hostB")}},
   989  		{&query.UnsignedPoint{Time: 20, Value: 8, Tags: ParseTags("host=hostB")}},
   990  	}); diff != "" {
   991  		t.Fatalf("unexpected points:\n%s", diff)
   992  	}
   993  }
   994  
   995  // Ensure that a string iterator can be created for a mode() call.
   996  func TestCallIterator_Mode_String(t *testing.T) {
   997  	itr, _ := query.NewModeIterator(&StringIterator{Points: []query.StringPoint{
   998  		{Time: 0, Value: "15", Tags: ParseTags("region=us-east,host=hostA")},
   999  		{Time: 1, Value: "10", Tags: ParseTags("region=us-west,host=hostA")},
  1000  		{Time: 2, Value: "10", Tags: ParseTags("region=us-east,host=hostA")},
  1001  		{Time: 3, Value: "10", Tags: ParseTags("region=us-east,host=hostA")},
  1002  		{Time: 4, Value: "10", Tags: ParseTags("region=us-east,host=hostA")},
  1003  		{Time: 6, Value: "20", Tags: ParseTags("region=us-east,host=hostA")},
  1004  		{Time: 7, Value: "21", Tags: ParseTags("region=us-east,host=hostA")},
  1005  		{Time: 7, Value: "21", Tags: ParseTags("region=us-east,host=hostA")},
  1006  
  1007  		{Time: 1, Value: "11", Tags: ParseTags("region=us-west,host=hostB")},
  1008  		{Time: 22, Value: "8", Tags: ParseTags("region=us-west,host=hostB")},
  1009  		{Time: 23, Value: "8", Tags: ParseTags("region=us-west,host=hostB")},
  1010  		{Time: 24, Value: "25", Tags: ParseTags("region=us-west,host=hostB")},
  1011  	}},
  1012  		query.IteratorOptions{
  1013  			Expr:       MustParseExpr(`mode("value")`),
  1014  			Dimensions: []string{"host"},
  1015  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
  1016  			Ordered:    true,
  1017  			Ascending:  true,
  1018  		},
  1019  	)
  1020  
  1021  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
  1022  		t.Fatalf("unexpected error: %s", err)
  1023  	} else if diff := cmp.Diff(a, [][]query.Point{
  1024  		{&query.StringPoint{Time: 0, Value: "10", Tags: ParseTags("host=hostA")}},
  1025  		{&query.StringPoint{Time: 5, Value: "21", Tags: ParseTags("host=hostA")}},
  1026  		{&query.StringPoint{Time: 1, Value: "11", Tags: ParseTags("host=hostB")}},
  1027  		{&query.StringPoint{Time: 20, Value: "8", Tags: ParseTags("host=hostB")}},
  1028  	}); diff != "" {
  1029  		t.Fatalf("unexpected points:\n%s", diff)
  1030  	}
  1031  }
  1032  
  1033  // Ensure that a boolean iterator can be created for a modBooleanl.
  1034  func TestCallIterator_Mode_Boolean(t *testing.T) {
  1035  	itr, _ := query.NewModeIterator(&BooleanIterator{Points: []query.BooleanPoint{
  1036  		{Time: 0, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
  1037  		{Time: 1, Value: true, Tags: ParseTags("region=us-west,host=hostA")},
  1038  		{Time: 2, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
  1039  		{Time: 3, Value: true, Tags: ParseTags("region=us-east,host=hostA")},
  1040  		{Time: 4, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
  1041  		{Time: 6, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
  1042  		{Time: 7, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
  1043  		{Time: 8, Value: false, Tags: ParseTags("region=us-east,host=hostA")},
  1044  
  1045  		{Time: 1, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
  1046  		{Time: 22, Value: false, Tags: ParseTags("region=us-west,host=hostB")},
  1047  		{Time: 23, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
  1048  		{Time: 24, Value: true, Tags: ParseTags("region=us-west,host=hostB")},
  1049  	}},
  1050  		query.IteratorOptions{
  1051  			Expr:       MustParseExpr(`mode("value")`),
  1052  			Dimensions: []string{"host"},
  1053  			Interval:   query.Interval{Duration: 5 * time.Nanosecond},
  1054  			Ordered:    true,
  1055  			Ascending:  true,
  1056  		},
  1057  	)
  1058  
  1059  	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
  1060  		t.Fatalf("unexpected error: %s", err)
  1061  	} else if diff := cmp.Diff(a, [][]query.Point{
  1062  		{&query.BooleanPoint{Time: 0, Value: true, Tags: ParseTags("host=hostA")}},
  1063  		{&query.BooleanPoint{Time: 5, Value: false, Tags: ParseTags("host=hostA")}},
  1064  		{&query.BooleanPoint{Time: 1, Value: false, Tags: ParseTags("host=hostB")}},
  1065  		{&query.BooleanPoint{Time: 20, Value: true, Tags: ParseTags("host=hostB")}},
  1066  	}); diff != "" {
  1067  		t.Fatalf("unexpected points:\n%s", diff)
  1068  	}
  1069  }
  1070  
  1071  func TestNewCallIterator_UnsupportedExprName(t *testing.T) {
  1072  	_, err := query.NewCallIterator(
  1073  		&FloatIterator{},
  1074  		query.IteratorOptions{
  1075  			Expr: MustParseExpr(`foobar("value")`),
  1076  		},
  1077  	)
  1078  
  1079  	if err == nil || err.Error() != "unsupported function call: foobar" {
  1080  		t.Errorf("unexpected error: %s", err)
  1081  	}
  1082  }
  1083  
  1084  func BenchmarkCountIterator_1K(b *testing.B)   { benchmarkCountIterator(b, 1000) }
  1085  func BenchmarkCountIterator_100K(b *testing.B) { benchmarkCountIterator(b, 100000) }
  1086  func BenchmarkCountIterator_1M(b *testing.B)   { benchmarkCountIterator(b, 1000000) }
  1087  
  1088  func benchmarkCountIterator(b *testing.B, pointN int) {
  1089  	benchmarkCallIterator(b, query.IteratorOptions{
  1090  		Expr:      MustParseExpr("count(value)"),
  1091  		StartTime: influxql.MinTime,
  1092  		EndTime:   influxql.MaxTime,
  1093  	}, pointN)
  1094  }
  1095  
  1096  func benchmarkCallIterator(b *testing.B, opt query.IteratorOptions, pointN int) {
  1097  	b.ReportAllocs()
  1098  
  1099  	for i := 0; i < b.N; i++ {
  1100  		// Create a lightweight point generator.
  1101  		p := query.FloatPoint{Name: "cpu", Value: 100}
  1102  		input := FloatPointGenerator{
  1103  			N:  pointN,
  1104  			Fn: func(i int) *query.FloatPoint { return &p },
  1105  		}
  1106  
  1107  		// Execute call against input.
  1108  		itr, err := query.NewCallIterator(&input, opt)
  1109  		if err != nil {
  1110  			b.Fatal(err)
  1111  		}
  1112  		query.DrainIterator(itr)
  1113  	}
  1114  }
  1115  
  1116  func BenchmarkSampleIterator_1k(b *testing.B)   { benchmarkSampleIterator(b, 1000) }
  1117  func BenchmarkSampleIterator_100k(b *testing.B) { benchmarkSampleIterator(b, 100000) }
  1118  func BenchmarkSampleIterator_1M(b *testing.B)   { benchmarkSampleIterator(b, 1000000) }
  1119  
  1120  func benchmarkSampleIterator(b *testing.B, pointN int) {
  1121  	b.ReportAllocs()
  1122  
  1123  	// Create a lightweight point generator.
  1124  	p := query.FloatPoint{Name: "cpu"}
  1125  	input := FloatPointGenerator{
  1126  		N: pointN,
  1127  		Fn: func(i int) *query.FloatPoint {
  1128  			p.Value = float64(i)
  1129  			return &p
  1130  		},
  1131  	}
  1132  
  1133  	for i := 0; i < b.N; i++ {
  1134  		// Execute call against input.
  1135  		itr, err := query.NewSampleIterator(&input, query.IteratorOptions{}, 100)
  1136  		if err != nil {
  1137  			b.Fatal(err)
  1138  		}
  1139  		query.DrainIterator(itr)
  1140  	}
  1141  }
  1142  
  1143  func BenchmarkDistinctIterator_1K(b *testing.B)   { benchmarkDistinctIterator(b, 1000) }
  1144  func BenchmarkDistinctIterator_100K(b *testing.B) { benchmarkDistinctIterator(b, 100000) }
  1145  func BenchmarkDistinctIterator_1M(b *testing.B)   { benchmarkDistinctIterator(b, 1000000) }
  1146  
  1147  func benchmarkDistinctIterator(b *testing.B, pointN int) {
  1148  	b.ReportAllocs()
  1149  
  1150  	for i := 0; i < b.N; i++ {
  1151  		// Create a lightweight point generator.
  1152  		p := query.FloatPoint{Name: "cpu"}
  1153  		input := FloatPointGenerator{
  1154  			N: pointN,
  1155  			Fn: func(i int) *query.FloatPoint {
  1156  				p.Value = float64(i % 10)
  1157  				return &p
  1158  			},
  1159  		}
  1160  
  1161  		// Execute call against input.
  1162  		itr, err := query.NewDistinctIterator(&input, query.IteratorOptions{})
  1163  		if err != nil {
  1164  			b.Fatal(err)
  1165  		}
  1166  		query.DrainIterator(itr)
  1167  	}
  1168  }
  1169  
  1170  func BenchmarkModeIterator_1K(b *testing.B)   { benchmarkModeIterator(b, 1000) }
  1171  func BenchmarkModeIterator_100K(b *testing.B) { benchmarkModeIterator(b, 100000) }
  1172  func BenchmarkModeIterator_1M(b *testing.B)   { benchmarkModeIterator(b, 1000000) }
  1173  
  1174  func benchmarkModeIterator(b *testing.B, pointN int) {
  1175  	b.ReportAllocs()
  1176  
  1177  	for i := 0; i < b.N; i++ {
  1178  		// Create a lightweight point generator.
  1179  		p := query.FloatPoint{Name: "cpu"}
  1180  		input := FloatPointGenerator{
  1181  			N: pointN,
  1182  			Fn: func(i int) *query.FloatPoint {
  1183  				p.Value = float64(10)
  1184  				return &p
  1185  			},
  1186  		}
  1187  
  1188  		// Execute call against input.
  1189  		itr, err := query.NewModeIterator(&input, query.IteratorOptions{})
  1190  		if err != nil {
  1191  			b.Fatal(err)
  1192  		}
  1193  		query.DrainIterator(itr)
  1194  	}
  1195  }
  1196  
  1197  type FloatPointGenerator struct {
  1198  	i  int
  1199  	N  int
  1200  	Fn func(i int) *query.FloatPoint
  1201  }
  1202  
  1203  func (g *FloatPointGenerator) Close() error               { return nil }
  1204  func (g *FloatPointGenerator) Stats() query.IteratorStats { return query.IteratorStats{} }
  1205  
  1206  func (g *FloatPointGenerator) Next() (*query.FloatPoint, error) {
  1207  	if g.i == g.N {
  1208  		return nil, nil
  1209  	}
  1210  	p := g.Fn(g.i)
  1211  	g.i++
  1212  	return p, nil
  1213  }