forked from influxdata/influxdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinternal_test.go
191 lines (162 loc) · 6.24 KB
/
internal_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package influxdb
// This file is run within the "influxdb" package and allows for internal unit tests.
import (
"reflect"
"testing"
"github.com/influxdb/influxdb/influxql"
)
// Ensure a measurement can return a set of unique tag values specified by an expression.
func TestMeasurement_uniqueTagValues(t *testing.T) {
// Create a measurement to run against.
m := NewMeasurement("cpu")
m.createFieldIfNotExists("value", influxql.Number)
for i, tt := range []struct {
expr string
values map[string][]string
}{
{expr: `1`, values: map[string][]string{}},
{expr: `foo = 'bar'`, values: map[string][]string{"foo": {"bar"}}},
{expr: `(region = 'us-west' AND value > 10) OR ('us-east' = region AND value > 20) OR (host = 'serverA' AND value > 30)`, values: map[string][]string{"region": {"us-east", "us-west"}, "host": {"serverA"}}},
} {
// Extract unique tag values from the expression.
values := m.uniqueTagValues(MustParseExpr(tt.expr))
if !reflect.DeepEqual(tt.values, values) {
t.Errorf("%d. %s: mismatch: exp=%+v, got=%+v", i, tt.expr, tt.values, values)
}
}
}
// Ensure a measurement can expand an expression for all possible tag values used.
func TestMeasurement_expandExpr(t *testing.T) {
m := NewMeasurement("cpu")
m.createFieldIfNotExists("value", influxql.Number)
type tagSetExprString struct {
tagExpr []tagExpr
expr string
}
for i, tt := range []struct {
expr string
exprs []tagSetExprString
}{
// Single tag key, single value.
{
expr: `region = 'us-east' AND value > 10`,
exprs: []tagSetExprString{
{tagExpr: []tagExpr{{"region", []string{"us-east"}, influxql.EQ}}, expr: `value > 10.000`},
},
},
// Single tag key, multiple values.
{
expr: `(region = 'us-east' AND value > 10) OR (region = 'us-west' AND value > 20)`,
exprs: []tagSetExprString{
{tagExpr: []tagExpr{{"region", []string{"us-east"}, influxql.EQ}}, expr: `value > 10.000`},
{tagExpr: []tagExpr{{"region", []string{"us-west"}, influxql.EQ}}, expr: `value > 20.000`},
},
},
// Multiple tag keys, multiple values.
{
expr: `(region = 'us-east' AND value > 10) OR ((host = 'serverA' OR host = 'serverB') AND value > 20)`,
exprs: []tagSetExprString{
{tagExpr: []tagExpr{{key: "host", values: []string{"serverA"}, op: influxql.EQ}, {key: "region", values: []string{"us-east"}, op: influxql.EQ}}, expr: "(value > 10.000) OR (value > 20.000)"},
{tagExpr: []tagExpr{{key: "host", values: []string{"serverA"}, op: influxql.EQ}, {key: "region", values: []string{"us-east"}, op: influxql.NEQ}}, expr: "value > 20.000"},
{tagExpr: []tagExpr{{key: "host", values: []string{"serverB"}, op: influxql.EQ}, {key: "region", values: []string{"us-east"}, op: influxql.EQ}}, expr: "(value > 10.000) OR (value > 20.000)"},
{tagExpr: []tagExpr{{key: "host", values: []string{"serverB"}, op: influxql.EQ}, {key: "region", values: []string{"us-east"}, op: influxql.NEQ}}, expr: "value > 20.000"},
{tagExpr: []tagExpr{{key: "host", values: []string{"serverA", "serverB"}, op: influxql.NEQ}, {key: "region", values: []string{"us-east"}, op: influxql.EQ}}, expr: "value > 10.000"},
},
},
} {
// Expand out an expression to all possible expressions based on tag values.
tagExprs := m.expandExpr(MustParseExpr(tt.expr))
// Convert to intermediate representation.
var a []tagSetExprString
for _, tagExpr := range tagExprs {
a = append(a, tagSetExprString{tagExpr: tagExpr.values, expr: tagExpr.expr.String()})
}
// Validate that the expanded expressions are what we expect.
if !reflect.DeepEqual(tt.exprs, a) {
t.Errorf("%d. %s: mismatch:\n\nexp=%#v\n\ngot=%#v\n\ns", i, tt.expr, tt.exprs, a)
}
}
}
// Ensure the createMeasurementsIfNotExistsCommand operates correctly.
func TestCreateMeasurementsCommand(t *testing.T) {
var err error
var n int
c := newCreateMeasurementsIfNotExistsCommand("foo")
if c == nil {
t.Fatal("createMeasurementsIfNotExistsCommand is nil")
}
// Add Measurement twice, to make sure nothing blows up.
c.addMeasurementIfNotExists("bar")
c.addMeasurementIfNotExists("bar")
n = len(c.Measurements)
if n != 1 {
t.Fatalf("wrong number of measurements, expected 1, got %d", n)
}
// Add Series, no tags.
c.addSeriesIfNotExists("bar", nil)
// Add Series, some tags.
tags := map[string]string{"host": "server01"}
c.addSeriesIfNotExists("bar", tags)
// Add Series, same tags again.
c.addSeriesIfNotExists("bar", tags)
n = len(c.Measurements["bar"].Tags)
if n != 2 {
t.Fatalf("measurement has wrong number of tags, expected 2, got %d", n)
}
// Add a field.
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
if err != nil {
t.Fatal("error adding field \"value\"")
}
// Add same field again.
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
if err != nil {
t.Fatal("error re-adding field \"value\"")
}
// Add another field.
err = c.addFieldIfNotExists("bar", "value2", influxql.String)
if err != nil {
t.Fatal("error re-adding field \"value2\"")
}
n = len(c.Measurements["bar"].Fields)
if n != 2 {
t.Fatalf("wrong number of fields, expected 2, got %d", n)
}
}
// Ensure the createMeasurementsIfNotExistsCommand returns expected errors.
func TestCreateMeasurementsCommand_Errors(t *testing.T) {
var err error
c := newCreateMeasurementsIfNotExistsCommand("foo")
if c == nil {
t.Fatal("createMeasurementsIfNotExistsCommand is nil")
}
// Ensure fields can be added to non-existent Measurements. The
// Measurements should be created automatically.
c.addSeriesIfNotExists("bar", nil)
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
if err != nil {
t.Fatalf("unexpected error got %s", err.Error())
}
// Add Measurement. Adding it now should be OK.
c.addMeasurementIfNotExists("bar")
// Test type conflicts
err = c.addFieldIfNotExists("bar", "value", influxql.Number)
if err != nil {
t.Fatal("error adding field \"value\"")
}
err = c.addFieldIfNotExists("bar", "value", influxql.String)
if err != ErrFieldTypeConflict {
t.Fatalf("expected ErrFieldTypeConflict got %s", err.Error())
}
}
// MustParseExpr parses an expression string and returns its AST representation.
func MustParseExpr(s string) influxql.Expr {
expr, err := influxql.ParseExpr(s)
if err != nil {
panic(err.Error())
}
return expr
}
func strref(s string) *string {
return &s
}