func Test_distinctValues_Sort(t *testing.T) { values := interfaceValues{ "2", "1", float64(2.0), float64(1), uint64(2), uint64(1), true, false, } expect := interfaceValues{ "1", "2", false, true, uint64(1), float64(1), uint64(2), float64(2), } sort.Sort(values) if !reflect.DeepEqual(values, expect) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(expect), spew.Sdump(values)) } }
func TestReduceDistinct(t *testing.T) { v1 := interfaceValues{ "2", "1", float64(2.0), float64(1), uint64(2), uint64(1), true, false, } expect := interfaceValues{ "1", "2", false, true, uint64(1), float64(1), uint64(2), float64(2), } got := ReduceDistinct([]interface{}{v1, v1, expect}) if !reflect.DeepEqual(got, expect) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(expect), spew.Sdump(got)) } }
func TestReduceCountDistinct(t *testing.T) { v1 := map[interface{}]struct{}{ "2": struct{}{}, "1": struct{}{}, float64(2.0): struct{}{}, float64(1): struct{}{}, uint64(2): struct{}{}, uint64(1): struct{}{}, true: struct{}{}, false: struct{}{}, } v2 := map[interface{}]struct{}{ uint64(1): struct{}{}, float64(1): struct{}{}, uint64(2): struct{}{}, float64(2): struct{}{}, false: struct{}{}, true: struct{}{}, "1": struct{}{}, "2": struct{}{}, } exp := 8 got := ReduceCountDistinct([]interface{}{v1, v1, v2}) if !reflect.DeepEqual(got, exp) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(exp), spew.Sdump(got)) } }
// Ensure a SHOW SERVERS statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowServers(t *testing.T) { e := NewStatementExecutor() e.Store.NodesFn = func() ([]meta.NodeInfo, error) { return []meta.NodeInfo{ {ID: 1, Host: "node0"}, {ID: 2, Host: "node1"}, }, nil } e.Store.PeersFn = func() ([]string, error) { return []string{"node0"}, nil } if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW SERVERS`)); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Columns: []string{"id", "cluster_addr", "raft"}, Values: [][]interface{}{ {uint64(1), "node0", true}, {uint64(2), "node1", false}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
// Ensure a SHOW GRANTS FOR statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowGrantsFor(t *testing.T) { t.Skip("Intermittent test failure: issue 3028") e := NewStatementExecutor() e.Store.UserPrivilegesFn = func(username string) (map[string]influxql.Privilege, error) { if username != "dejan" { t.Fatalf("unexpected username: %s", username) } return map[string]influxql.Privilege{ "dejan": influxql.ReadPrivilege, "golja": influxql.WritePrivilege, }, nil } if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW GRANTS FOR dejan`)); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Columns: []string{"database", "privilege"}, Values: [][]interface{}{ {"dejan", "READ"}, {"golja", "WRITE"}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
// Ensure shards with deprecated "OwnerIDs" can be decoded. func TestShardInfo_UnmarshalBinary_OwnerIDs(t *testing.T) { // Encode deprecated form to bytes. buf, err := proto.Marshal(&internal.ShardInfo{ ID: proto.Uint64(1), OwnerIDs: []uint64{10, 20, 30}, }) if err != nil { t.Fatal(err) } // Decode deprecated form. var si meta.ShardInfo if err := si.UnmarshalBinary(buf); err != nil { t.Fatal(err) } // Verify data is migrated correctly. if !reflect.DeepEqual(si, meta.ShardInfo{ ID: 1, Owners: []meta.ShardOwner{ {NodeID: 10}, {NodeID: 20}, {NodeID: 30}, }, }) { t.Fatalf("unexpected shard info: %s", spew.Sdump(si)) } }
func TestMapDistinctNil(t *testing.T) { values := MapDistinct(&MapInput{}) if values != nil { t.Errorf("Wrong values. exp nil got %v", spew.Sdump(values)) } }
func TestReduceDistinctNil(t *testing.T) { tests := []struct { name string values []interface{} }{ { name: "nil values", values: nil, }, { name: "nil mapper", values: []interface{}{nil}, }, { name: "no mappers", values: []interface{}{}, }, { name: "empty mappper (len 1)", values: []interface{}{interfaceValues{}}, }, { name: "empty mappper (len 2)", values: []interface{}{interfaceValues{}, interfaceValues{}}, }, } for _, test := range tests { t.Log(test.name) got := ReduceDistinct(test.values) if got != nil { t.Errorf("Wrong values. exp nil got %v", spew.Sdump(got)) } } }
func TestMapCountDistinct(t *testing.T) { const ( // prove that we're ignoring seriesKey seriesKey1 = "1" seriesKey2 = "2" ) const ( // prove that we're ignoring time timeId1 = iota + 1 timeId2 timeId3 timeId4 timeId5 timeId6 timeId7 ) iter := &testIterator{ values: []point{ {seriesKey1, timeId1, uint64(1)}, {seriesKey1, timeId2, uint64(1)}, {seriesKey1, timeId3, "1"}, {seriesKey2, timeId4, uint64(1)}, {seriesKey2, timeId5, float64(1.0)}, {seriesKey2, timeId6, "1"}, {seriesKey2, timeId7, true}, }, } values := MapCountDistinct(iter).(map[interface{}]struct{}) if exp, got := 4, len(values); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) } exp := map[interface{}]struct{}{ uint64(1): struct{}{}, float64(1): struct{}{}, "1": struct{}{}, true: struct{}{}, } if !reflect.DeepEqual(values, exp) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(exp), spew.Sdump(values)) } }
func TestMapDistinct(t *testing.T) { const ( // prove that we're ignoring seriesKey seriesKey1 = "1" seriesKey2 = "2" ) const ( // prove that we're ignoring time timeId1 = iota + 1 timeId2 timeId3 timeId4 timeId5 timeId6 ) iter := &testIterator{ values: []point{ {seriesKey1, timeId1, uint64(1)}, {seriesKey1, timeId2, uint64(1)}, {seriesKey1, timeId3, "1"}, {seriesKey2, timeId4, uint64(1)}, {seriesKey2, timeId5, float64(1.0)}, {seriesKey2, timeId6, "1"}, }, } values := MapDistinct(iter).(distinctValues) if exp, got := 3, len(values); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) } sort.Sort(values) exp := distinctValues{ uint64(1), float64(1), "1", } if !reflect.DeepEqual(values, exp) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(exp), spew.Sdump(values)) } }
func TestMapCountDistinctNil(t *testing.T) { iter := &testIterator{ values: []point{}, } values := MapCountDistinct(iter) if values != nil { t.Errorf("Wrong values. exp nil got %v", spew.Sdump(values)) } }
func TestMapCountDistinct(t *testing.T) { const ( // prove that we're ignoring time timeId1 = iota + 1 timeId2 timeId3 timeId4 timeId5 timeId6 timeId7 ) input := &MapInput{ Items: []MapItem{ {Timestamp: timeId1, Value: uint64(1)}, {Timestamp: timeId2, Value: uint64(1)}, {Timestamp: timeId3, Value: "1"}, {Timestamp: timeId4, Value: uint64(1)}, {Timestamp: timeId5, Value: float64(1.0)}, {Timestamp: timeId6, Value: "1"}, {Timestamp: timeId7, Value: true}, }, } values := MapCountDistinct(input).(map[interface{}]struct{}) if exp, got := 4, len(values); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) } exp := map[interface{}]struct{}{ uint64(1): struct{}{}, float64(1): struct{}{}, "1": struct{}{}, true: struct{}{}, } if !reflect.DeepEqual(values, exp) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(exp), spew.Sdump(values)) } }
func TestMapDistinct(t *testing.T) { const ( // prove that we're ignoring time timeId1 = iota + 1 timeId2 timeId3 timeId4 timeId5 timeId6 ) input := &MapInput{ Items: []MapItem{ {Timestamp: timeId1, Value: uint64(1)}, {Timestamp: timeId2, Value: uint64(1)}, {Timestamp: timeId3, Value: "1"}, {Timestamp: timeId4, Value: uint64(1)}, {Timestamp: timeId5, Value: float64(1.0)}, {Timestamp: timeId6, Value: "1"}, }, } values := MapDistinct(input).(interfaceValues) if exp, got := 3, len(values); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) } sort.Sort(values) exp := interfaceValues{ "1", uint64(1), float64(1), } if !reflect.DeepEqual(values, exp) { t.Errorf("Wrong values. exp %v got %v", spew.Sdump(exp), spew.Sdump(values)) } }
// Ensure a SHOW SHARDS statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowShards(t *testing.T) { e := NewStatementExecutor() e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) { return []meta.DatabaseInfo{ { Name: "foo", RetentionPolicies: []meta.RetentionPolicyInfo{ { Duration: time.Second, ShardGroups: []meta.ShardGroupInfo{ { StartTime: time.Unix(0, 0), EndTime: time.Unix(1, 0), Shards: []meta.ShardInfo{ { ID: 1, Owners: []meta.ShardOwner{ {NodeID: 1}, {NodeID: 2}, {NodeID: 3}, }, }, { ID: 2, }, }, }, }, }, }, }, }, nil } if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW SHARDS`)); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Name: "foo", Columns: []string{"id", "start_time", "end_time", "expiry_time", "owners"}, Values: [][]interface{}{ {uint64(1), "1970-01-01T00:00:00Z", "1970-01-01T00:00:01Z", "1970-01-01T00:00:02Z", "1,2,3"}, {uint64(2), "1970-01-01T00:00:00Z", "1970-01-01T00:00:01Z", "1970-01-01T00:00:02Z", ""}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
// Ensure a SHOW CONTINUOUS QUERIES statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowContinuousQueries(t *testing.T) { e := NewStatementExecutor() e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) { return []meta.DatabaseInfo{ { Name: "db0", ContinuousQueries: []meta.ContinuousQueryInfo{ {Name: "cq0", Query: "SELECT count(field1) INTO db1 FROM db0"}, {Name: "cq1", Query: "SELECT count(field1) INTO db2 FROM db0"}, }, }, { Name: "db1", ContinuousQueries: []meta.ContinuousQueryInfo{ {Name: "cq2", Query: "SELECT count(field1) INTO db3 FROM db1"}, }, }, }, nil } stmt := influxql.MustParseStatement(`SHOW CONTINUOUS QUERIES`) if res := e.ExecuteStatement(stmt); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Name: "db0", Columns: []string{"name", "query"}, Values: [][]interface{}{ {"cq0", "SELECT count(field1) INTO db1 FROM db0"}, {"cq1", "SELECT count(field1) INTO db2 FROM db0"}, }, }, { Name: "db1", Columns: []string{"name", "query"}, Values: [][]interface{}{ {"cq2", "SELECT count(field1) INTO db3 FROM db1"}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
// Ensure a SHOW RETENTION POLICIES statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowRetentionPolicies(t *testing.T) { e := NewStatementExecutor() e.Store.DatabaseFn = func(name string) (*meta.DatabaseInfo, error) { if name != "db0" { t.Fatalf("unexpected name: %s", name) } return &meta.DatabaseInfo{ Name: name, DefaultRetentionPolicy: "rp1", RetentionPolicies: []meta.RetentionPolicyInfo{ { Name: "rp0", Duration: 2 * time.Hour, ReplicaN: 3, }, { Name: "rp1", Duration: 24 * time.Hour, ReplicaN: 1, }, }, }, nil } if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW RETENTION POLICIES ON db0`)); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Columns: []string{"name", "duration", "replicaN", "default"}, Values: [][]interface{}{ {"rp0", "2h0m0s", 3, false}, {"rp1", "24h0m0s", 1, true}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
// Ensure a SHOW USERS statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowUsers(t *testing.T) { e := NewStatementExecutor() e.Store.UsersFn = func() ([]meta.UserInfo, error) { return []meta.UserInfo{ {Name: "susy", Admin: true}, {Name: "bob", Admin: false}, }, nil } if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW USERS`)); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Columns: []string{"user", "admin"}, Values: [][]interface{}{ {"susy", true}, {"bob", false}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
func TestReduceCountDistinctNil(t *testing.T) { emptyResults := make(map[interface{}]struct{}) tests := []struct { name string values []interface{} }{ { name: "nil values", values: nil, }, { name: "nil mapper", values: []interface{}{nil}, }, { name: "no mappers", values: []interface{}{}, }, { name: "empty mappper (len 1)", values: []interface{}{emptyResults}, }, { name: "empty mappper (len 2)", values: []interface{}{emptyResults, emptyResults}, }, } for _, test := range tests { t.Log(test.name) got := ReduceCountDistinct(test.values) if got != 0 { t.Errorf("Wrong values. exp nil got %v", spew.Sdump(got)) } } }
// Ensure a SHOW DATABASES statement can be executed. func TestStatementExecutor_ExecuteStatement_ShowDatabases(t *testing.T) { e := NewStatementExecutor() e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) { return []meta.DatabaseInfo{ {Name: "foo"}, {Name: "bar"}, }, nil } if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW DATABASES`)); res.Err != nil { t.Fatal(res.Err) } else if !reflect.DeepEqual(res.Series, models.Rows{ { Name: "databases", Columns: []string{"name"}, Values: [][]interface{}{ {"foo"}, {"bar"}, }, }, }) { t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series)) } }
func TestReduceTopBottom(t *testing.T) { tests := []struct { name string skip bool values []interface{} exp PositionPoints call *influxql.Call }{ { name: "top int64 - single map", values: []interface{}{ PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, {20, int64(88), nil, map[string]string{"host": "a"}}, {10, int64(53), nil, map[string]string{"host": "b"}}, }, }, exp: PositionPoints{ PositionPoint{10, int64(99), nil, map[string]string{"host": "a"}}, PositionPoint{20, int64(88), nil, map[string]string{"host": "a"}}, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top int64 - double map", values: []interface{}{ PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, }, PositionPoints{ {20, int64(88), nil, map[string]string{"host": "a"}}, {10, int64(53), nil, map[string]string{"host": "b"}}, }, }, exp: PositionPoints{ PositionPoint{10, int64(99), nil, map[string]string{"host": "a"}}, PositionPoint{20, int64(88), nil, map[string]string{"host": "a"}}, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top int64 - double map with nil", values: []interface{}{ PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, {20, int64(88), nil, map[string]string{"host": "a"}}, {10, int64(53), nil, map[string]string{"host": "b"}}, }, nil, }, exp: PositionPoints{ PositionPoint{10, int64(99), nil, map[string]string{"host": "a"}}, PositionPoint{20, int64(88), nil, map[string]string{"host": "a"}}, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top int64 - double map with non-matching tags and tag selected", values: []interface{}{ PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, {20, int64(88), nil, map[string]string{}}, {10, int64(53), nil, map[string]string{"host": "b"}}, }, nil, }, exp: PositionPoints{ PositionPoint{10, int64(99), nil, map[string]string{"host": "a"}}, PositionPoint{20, int64(88), nil, map[string]string{}}, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, }, { skip: true, name: "top int64 - double map with non-matching tags", values: []interface{}{ PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, {20, int64(88), nil, map[string]string{}}, {10, int64(53), nil, map[string]string{"host": "b"}}, }, nil, }, exp: PositionPoints{ PositionPoint{10, int64(99), nil, map[string]string{"host": "a"}}, PositionPoint{20, int64(55), nil, map[string]string{"host": "b"}}, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom int64 - single map", values: []interface{}{ PositionPoints{ {10, int64(53), nil, map[string]string{"host": "b"}}, {20, int64(88), nil, map[string]string{"host": "a"}}, {10, int64(99), nil, map[string]string{"host": "a"}}, }, }, exp: PositionPoints{ PositionPoint{10, int64(53), nil, map[string]string{"host": "b"}}, PositionPoint{20, int64(88), nil, map[string]string{"host": "a"}}, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom int64 - double map", values: []interface{}{ PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, }, PositionPoints{ {10, int64(53), nil, map[string]string{"host": "b"}}, {20, int64(88), nil, map[string]string{"host": "a"}}, }, }, exp: PositionPoints{ PositionPoint{10, int64(53), nil, map[string]string{"host": "b"}}, PositionPoint{20, int64(88), nil, map[string]string{"host": "a"}}, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom int64 - double map with nil", values: []interface{}{ PositionPoints{ {10, int64(53), nil, map[string]string{"host": "b"}}, {20, int64(88), nil, map[string]string{"host": "a"}}, {10, int64(99), nil, map[string]string{"host": "a"}}, }, nil, }, exp: PositionPoints{ PositionPoint{10, int64(53), nil, map[string]string{"host": "b"}}, PositionPoint{20, int64(88), nil, map[string]string{"host": "a"}}, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom int64 - double map with non-matching tags and tag selected", values: []interface{}{ PositionPoints{ {10, int64(53), nil, map[string]string{"host": "b"}}, {20, int64(88), nil, map[string]string{}}, {10, int64(99), nil, map[string]string{"host": "a"}}, }, nil, }, exp: PositionPoints{ PositionPoint{10, int64(53), nil, map[string]string{"host": "b"}}, PositionPoint{20, int64(88), nil, map[string]string{}}, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.VarRef{Val: "host"}, &influxql.NumberLiteral{Val: 2}}}, }, { skip: true, name: "bottom int64 - double map with non-matching tags", values: []interface{}{ PositionPoints{ {10, int64(53), nil, map[string]string{"host": "b"}}, {20, int64(88), nil, map[string]string{}}, {10, int64(99), nil, map[string]string{"host": "a"}}, }, nil, }, exp: PositionPoints{ PositionPoint{10, int64(99), nil, map[string]string{"host": "a"}}, PositionPoint{20, int64(55), nil, map[string]string{"host": "b"}}, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, } for _, test := range tests { if test.skip { continue } values := ReduceTopBottom(test.values, test.call) t.Logf("Test: %s", test.name) if values != nil { v, _ := values.(PositionPoints) if exp, got := len(test.exp), len(v); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) } } if !reflect.DeepEqual(values, test.exp) { t.Errorf("Wrong values. \nexp\n %v\ngot\n %v", spew.Sdump(test.exp), spew.Sdump(values)) } } }
func TestMapTopBottom(t *testing.T) { tests := []struct { name string skip bool input *MapInput exp positionOut call *influxql.Call }{ { name: "top int64 - basic", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: int64(88), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {20, int64(88), nil, map[string]string{"host": "a"}}, {10, int64(53), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top int64 - tie on value, resolve based on time", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 20, Value: int64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(99), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ callArgs: []string{"host"}, points: PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, {20, int64(99), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top mixed numerics - ints", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: int64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: uint64(88), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, int64(99), nil, map[string]string{"host": "a"}}, {20, uint64(88), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top mixed numerics - ints & floats", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: float64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: uint64(88), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, float64(99), nil, map[string]string{"host": "a"}}, {20, uint64(88), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top mixed numerics - ints, floats, & strings", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: float64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: "88", Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, float64(99), nil, map[string]string{"host": "a"}}, {10, int64(53), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "top bools", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: true, Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: true, Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: false, Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, true, nil, map[string]string{"host": "a"}}, {10, true, nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "top", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom int64 - basic", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: int64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: int64(88), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, int64(53), nil, map[string]string{"host": "a"}}, {20, int64(88), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom int64 - tie on value, resolve based on time", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: int64(53), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ callArgs: []string{"host"}, points: PositionPoints{ {10, int64(53), nil, map[string]string{"host": "a"}}, {20, int64(53), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom mixed numerics - ints", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: int64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: uint64(88), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, int64(53), nil, map[string]string{"host": "a"}}, {20, uint64(88), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom mixed numerics - ints & floats", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: int64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: float64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: uint64(88), Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, float64(53), nil, map[string]string{"host": "a"}}, {20, uint64(88), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom mixed numerics - ints, floats, & strings", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: float64(99), Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: int64(53), Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: "88", Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {10, int64(53), nil, map[string]string{"host": "a"}}, {10, float64(99), nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, { name: "bottom bools", input: &MapInput{ TMin: -1, Items: []MapItem{ {Timestamp: 10, Value: true, Tags: map[string]string{"host": "a"}}, {Timestamp: 10, Value: true, Tags: map[string]string{"host": "a"}}, {Timestamp: 20, Value: false, Tags: map[string]string{"host": "a"}}, }, }, exp: positionOut{ points: PositionPoints{ {20, false, nil, map[string]string{"host": "a"}}, {10, true, nil, map[string]string{"host": "a"}}, }, }, call: &influxql.Call{Name: "bottom", Args: []influxql.Expr{&influxql.VarRef{Val: "field1"}, &influxql.NumberLiteral{Val: 2}}}, }, } for _, test := range tests { if test.skip { continue } lit, _ := test.call.Args[len(test.call.Args)-1].(*influxql.NumberLiteral) limit := int(lit.Val) fields := topCallArgs(test.call) values := MapTopBottom(test.input, limit, fields, len(test.call.Args), test.call.Name).(PositionPoints) t.Logf("Test: %s", test.name) if exp, got := len(test.exp.points), len(values); exp != got { t.Errorf("Wrong number of values. exp %v got %v", exp, got) } if !reflect.DeepEqual(values, test.exp.points) { t.Errorf("Wrong values. \nexp\n %v\ngot\n %v", spew.Sdump(test.exp.points), spew.Sdump(values)) } } }