From 3dd6aa17f3690fce468c6c66e1cab57683744e8c Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Fri, 22 Jan 2016 14:41:36 -0500 Subject: [PATCH] Test the merge iterator for every type instead of just floats --- influxql/iterator.gen_test.go | 160 +++++++++++++++++++++++++++ influxql/iterator.gen_test.go.tmpl | 49 +++++++++ influxql/iterator_test.go | 170 +++++++++++++++++++++-------- pkg/deep/equal.go | 2 + 4 files changed, 335 insertions(+), 46 deletions(-) create mode 100644 influxql/iterator.gen_test.go create mode 100644 influxql/iterator.gen_test.go.tmpl diff --git a/influxql/iterator.gen_test.go b/influxql/iterator.gen_test.go new file mode 100644 index 0000000000..eb03679b82 --- /dev/null +++ b/influxql/iterator.gen_test.go @@ -0,0 +1,160 @@ +// Generated by tmpl +// https://github.com/benbjohnson/tmpl + +package influxql_test + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/influxdb/influxdb/influxql" + "github.com/influxdb/influxdb/pkg/deep" +) + +// Test implementation of influxql.FloatIterator +type FloatIterator struct { + Points []influxql.FloatPoint +} + +// Close is a no-op. +func (itr *FloatIterator) Close() error { return nil } + +// Next returns the next value and shifts it off the beginning of the points slice. +func (itr *FloatIterator) Next() *influxql.FloatPoint { + if len(itr.Points) == 0 { + return nil + } + + v := &itr.Points[0] + itr.Points = itr.Points[1:] + return v +} + +type TestFloatIterator struct { + Iterator influxql.Iterator + Points []influxql.FloatPoint +} + +func (ti *TestFloatIterator) run(t *testing.T) { + itr := ti.Iterator.(influxql.FloatIterator) + + points := make([]influxql.FloatPoint, 0, len(ti.Points)) + for p := itr.Next(); p != nil; p = itr.Next() { + points = append(points, *p) + } + + if !deep.Equal(ti.Points, points) { + t.Fatalf("unexpected points: %s %s", spew.Sdump(points), spew.Sdump(ti.Points)) + } +} + +// Test implementation of influxql.IntegerIterator +type IntegerIterator struct { + Points []influxql.IntegerPoint +} + +// Close is a no-op. +func (itr *IntegerIterator) Close() error { return nil } + +// Next returns the next value and shifts it off the beginning of the points slice. +func (itr *IntegerIterator) Next() *influxql.IntegerPoint { + if len(itr.Points) == 0 { + return nil + } + + v := &itr.Points[0] + itr.Points = itr.Points[1:] + return v +} + +type TestIntegerIterator struct { + Iterator influxql.Iterator + Points []influxql.IntegerPoint +} + +func (ti *TestIntegerIterator) run(t *testing.T) { + itr := ti.Iterator.(influxql.IntegerIterator) + + points := make([]influxql.IntegerPoint, 0, len(ti.Points)) + for p := itr.Next(); p != nil; p = itr.Next() { + points = append(points, *p) + } + + if !deep.Equal(ti.Points, points) { + t.Fatalf("unexpected points: %s %s", spew.Sdump(points), spew.Sdump(ti.Points)) + } +} + +// Test implementation of influxql.StringIterator +type StringIterator struct { + Points []influxql.StringPoint +} + +// Close is a no-op. +func (itr *StringIterator) Close() error { return nil } + +// Next returns the next value and shifts it off the beginning of the points slice. +func (itr *StringIterator) Next() *influxql.StringPoint { + if len(itr.Points) == 0 { + return nil + } + + v := &itr.Points[0] + itr.Points = itr.Points[1:] + return v +} + +type TestStringIterator struct { + Iterator influxql.Iterator + Points []influxql.StringPoint +} + +func (ti *TestStringIterator) run(t *testing.T) { + itr := ti.Iterator.(influxql.StringIterator) + + points := make([]influxql.StringPoint, 0, len(ti.Points)) + for p := itr.Next(); p != nil; p = itr.Next() { + points = append(points, *p) + } + + if !deep.Equal(ti.Points, points) { + t.Fatalf("unexpected points: %s %s", spew.Sdump(points), spew.Sdump(ti.Points)) + } +} + +// Test implementation of influxql.BooleanIterator +type BooleanIterator struct { + Points []influxql.BooleanPoint +} + +// Close is a no-op. +func (itr *BooleanIterator) Close() error { return nil } + +// Next returns the next value and shifts it off the beginning of the points slice. +func (itr *BooleanIterator) Next() *influxql.BooleanPoint { + if len(itr.Points) == 0 { + return nil + } + + v := &itr.Points[0] + itr.Points = itr.Points[1:] + return v +} + +type TestBooleanIterator struct { + Iterator influxql.Iterator + Points []influxql.BooleanPoint +} + +func (ti *TestBooleanIterator) run(t *testing.T) { + itr := ti.Iterator.(influxql.BooleanIterator) + + points := make([]influxql.BooleanPoint, 0, len(ti.Points)) + for p := itr.Next(); p != nil; p = itr.Next() { + points = append(points, *p) + } + + if !deep.Equal(ti.Points, points) { + t.Fatalf("unexpected points: %s %s", spew.Sdump(points), spew.Sdump(ti.Points)) + } +} diff --git a/influxql/iterator.gen_test.go.tmpl b/influxql/iterator.gen_test.go.tmpl new file mode 100644 index 0000000000..769774a6f8 --- /dev/null +++ b/influxql/iterator.gen_test.go.tmpl @@ -0,0 +1,49 @@ +package influxql_test + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/influxdb/influxdb/influxql" + "github.com/influxdb/influxdb/pkg/deep" +) + +{{range .}} + +// Test implementation of influxql.{{.Name}}Iterator +type {{.Name}}Iterator struct { + Points []influxql.{{.Name}}Point +} + +// Close is a no-op. +func (itr *{{.Name}}Iterator) Close() error { return nil } + +// Next returns the next value and shifts it off the beginning of the points slice. +func (itr *{{.Name}}Iterator) Next() *influxql.{{.Name}}Point { + if len(itr.Points) == 0 { + return nil + } + + v := &itr.Points[0] + itr.Points = itr.Points[1:] + return v +} + +type Test{{.Name}}Iterator struct { + Iterator influxql.Iterator + Points []influxql.{{.Name}}Point +} + +func (ti *Test{{.Name}}Iterator) run(t *testing.T) { + itr := ti.Iterator.(influxql.{{.Name}}Iterator) + + points := make([]influxql.{{.Name}}Point, 0, len(ti.Points)) + for p := itr.Next(); p != nil; p = itr.Next() { + points = append(points, *p) + } + + if !deep.Equal(ti.Points, points) { + t.Fatalf("unexpected points: %s %s", spew.Sdump(points), spew.Sdump(ti.Points)) + } +} +{{end}} diff --git a/influxql/iterator_test.go b/influxql/iterator_test.go index 11629cbae8..433818a7f4 100644 --- a/influxql/iterator_test.go +++ b/influxql/iterator_test.go @@ -13,45 +13,142 @@ import ( "github.com/influxdb/influxdb/pkg/deep" ) +//go:generate tmpl -data=@tmpldata iterator.gen_test.go.tmpl + // Ensure that a set of iterators can be merged together, sorted by window and name/tag. -func TestMergeIterator(t *testing.T) { - itr := influxql.NewMergeIterator([]influxql.Iterator{ - &FloatIterator{Points: []influxql.FloatPoint{ +func TestMergeIterator_Float(t *testing.T) { + test := TestFloatIterator{ + Iterator: influxql.NewMergeIterator([]influxql.Iterator{ + &FloatIterator{Points: []influxql.FloatPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, + }}, + &FloatIterator{Points: []influxql.FloatPoint{ + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, + }}, + }, influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 10 * time.Nanosecond, + }, + Ascending: true, + }), + Points: []influxql.FloatPoint{ {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, - {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, - }}, - &FloatIterator{Points: []influxql.FloatPoint{ {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, - }}, - }, influxql.IteratorOptions{ - Interval: influxql.Interval{ - Duration: 10 * time.Nanosecond, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, }, - Ascending: true, - }).(influxql.FloatIterator) + } + test.run(t) +} - if p := itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}) { - t.Fatalf("unexpected point: %#v", p) - } else if p = itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}) { - t.Fatalf("unexpected point: %#v", p) +// Ensure that a set of iterators can be merged together, sorted by window and name/tag. +func TestMergeIterator_Integer(t *testing.T) { + test := TestIntegerIterator{ + Iterator: influxql.NewMergeIterator([]influxql.Iterator{ + &IntegerIterator{Points: []influxql.IntegerPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, + }}, + &IntegerIterator{Points: []influxql.IntegerPoint{ + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, + }}, + }, influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 10 * time.Nanosecond, + }, + Ascending: true, + }), + Points: []influxql.IntegerPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: 1}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: 2}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}, + }, } - if p := itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: 3}) { - t.Fatalf("unexpected point: %#v", p) - } else if p = itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: 5}) { - t.Fatalf("unexpected point: %#v", p) - } else if p := itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: 6}) { - t.Fatalf("unexpected point: %#v", p) + test.run(t) +} + +// Ensure that a set of iterators can be merged together, sorted by window and name/tag. +func TestMergeIterator_String(t *testing.T) { + test := TestStringIterator{ + Iterator: influxql.NewMergeIterator([]influxql.Iterator{ + &StringIterator{Points: []influxql.StringPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: "a"}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: "b"}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: "c"}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: "d"}, + }}, + &StringIterator{Points: []influxql.StringPoint{ + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: "e"}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: "f"}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: "g"}, + }}, + }, influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 10 * time.Nanosecond, + }, + Ascending: true, + }), + Points: []influxql.StringPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: "a"}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: "b"}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: "c"}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: "e"}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: "f"}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: "g"}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: "d"}, + }, } - if p := itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: 7}) { - t.Fatalf("unexpected point: %#v", p) - } - if p := itr.Next(); !reflect.DeepEqual(p, &influxql.FloatPoint{Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: 4}) { - t.Fatalf("unexpected point: %#v", p) + test.run(t) +} + +// Ensure that a set of iterators can be merged together, sorted by window and name/tag. +func TestMergeIterator_Boolean(t *testing.T) { + test := TestBooleanIterator{ + Iterator: influxql.NewMergeIterator([]influxql.Iterator{ + &BooleanIterator{Points: []influxql.BooleanPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: true}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: false}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: true}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: false}, + }}, + &BooleanIterator{Points: []influxql.BooleanPoint{ + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: true}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: false}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: true}, + }}, + }, influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 10 * time.Nanosecond, + }, + Ascending: true, + }), + Points: []influxql.BooleanPoint{ + {Name: "cpu", Tags: ParseTags("host=A"), Time: 0, Value: true}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 1, Value: false}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 12, Value: true}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 11, Value: true}, + {Name: "cpu", Tags: ParseTags("host=B"), Time: 13, Value: false}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 20, Value: true}, + {Name: "cpu", Tags: ParseTags("host=A"), Time: 30, Value: false}, + }, } + test.run(t) } func TestMergeIterator_Nil(t *testing.T) { @@ -223,25 +320,6 @@ func (ic *IteratorCreator) FieldDimensions(sources influxql.Sources) (fields, di return ic.FieldDimensionsFn(sources) } -// Test implementation of influxql.FloatIterator. -type FloatIterator struct { - Points []influxql.FloatPoint -} - -// Close is a no-op. -func (itr *FloatIterator) Close() error { return nil } - -// Next returns the next value and shifts it off the beginning of the points slice. -func (itr *FloatIterator) Next() *influxql.FloatPoint { - if len(itr.Points) == 0 { - return nil - } - - v := &itr.Points[0] - itr.Points = itr.Points[1:] - return v -} - // GenerateFloatIterator creates a FloatIterator with random data. func GenerateFloatIterator(rand *rand.Rand, valueN int) *FloatIterator { const interval = 10 * time.Second diff --git a/pkg/deep/equal.go b/pkg/deep/equal.go index 8ffba1a93c..cc30ff7214 100644 --- a/pkg/deep/equal.go +++ b/pkg/deep/equal.go @@ -140,6 +140,8 @@ func deepValueEqual(v1, v2 reflect.Value, visited map[visit]bool, depth int) boo return true } return f1 == f2 + case reflect.Bool: + return v1.Bool() == v2.Bool() default: panic(fmt.Sprintf("cannot compare type: %s", v1.Kind().String())) }