github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/point_test.go (about) 1 package query_test 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 8 "github.com/davecgh/go-spew/spew" 9 "github.com/influxdata/influxdb/v2/influxql/query" 10 "github.com/influxdata/influxdb/v2/pkg/deep" 11 ) 12 13 func TestPoint_Clone_Float(t *testing.T) { 14 p := &query.FloatPoint{ 15 Name: "cpu", 16 Tags: ParseTags("host=server01"), 17 Time: 5, 18 Value: 2, 19 Aux: []interface{}{float64(45)}, 20 } 21 c := p.Clone() 22 if p == c { 23 t.Errorf("clone has the same address as the original: %v == %v", p, c) 24 } 25 if !deep.Equal(p, c) { 26 t.Errorf("mismatched point: %s", spew.Sdump(c)) 27 } 28 if &p.Aux[0] == &c.Aux[0] { 29 t.Errorf("aux values share the same address: %v == %v", p.Aux, c.Aux) 30 } else if !deep.Equal(p.Aux, c.Aux) { 31 t.Errorf("mismatched aux fields: %v != %v", p.Aux, c.Aux) 32 } 33 } 34 35 func TestPoint_Clone_Integer(t *testing.T) { 36 p := &query.IntegerPoint{ 37 Name: "cpu", 38 Tags: ParseTags("host=server01"), 39 Time: 5, 40 Value: 2, 41 Aux: []interface{}{float64(45)}, 42 } 43 c := p.Clone() 44 if p == c { 45 t.Errorf("clone has the same address as the original: %v == %v", p, c) 46 } 47 if !deep.Equal(p, c) { 48 t.Errorf("mismatched point: %s", spew.Sdump(c)) 49 } 50 if &p.Aux[0] == &c.Aux[0] { 51 t.Errorf("aux values share the same address: %v == %v", p.Aux, c.Aux) 52 } else if !deep.Equal(p.Aux, c.Aux) { 53 t.Errorf("mismatched aux fields: %v != %v", p.Aux, c.Aux) 54 } 55 } 56 57 func TestPoint_Clone_String(t *testing.T) { 58 p := &query.StringPoint{ 59 Name: "cpu", 60 Tags: ParseTags("host=server01"), 61 Time: 5, 62 Value: "clone", 63 Aux: []interface{}{float64(45)}, 64 } 65 c := p.Clone() 66 if p == c { 67 t.Errorf("clone has the same address as the original: %v == %v", p, c) 68 } 69 if !deep.Equal(p, c) { 70 t.Errorf("mismatched point: %s", spew.Sdump(c)) 71 } 72 if &p.Aux[0] == &c.Aux[0] { 73 t.Errorf("aux values share the same address: %v == %v", p.Aux, c.Aux) 74 } else if !deep.Equal(p.Aux, c.Aux) { 75 t.Errorf("mismatched aux fields: %v != %v", p.Aux, c.Aux) 76 } 77 } 78 79 func TestPoint_Clone_Boolean(t *testing.T) { 80 p := &query.BooleanPoint{ 81 Name: "cpu", 82 Tags: ParseTags("host=server01"), 83 Time: 5, 84 Value: true, 85 Aux: []interface{}{float64(45)}, 86 } 87 c := p.Clone() 88 if p == c { 89 t.Errorf("clone has the same address as the original: %v == %v", p, c) 90 } 91 if !deep.Equal(p, c) { 92 t.Errorf("mismatched point: %s", spew.Sdump(c)) 93 } 94 if &p.Aux[0] == &c.Aux[0] { 95 t.Errorf("aux values share the same address: %v == %v", p.Aux, c.Aux) 96 } else if !deep.Equal(p.Aux, c.Aux) { 97 t.Errorf("mismatched aux fields: %v != %v", p.Aux, c.Aux) 98 } 99 } 100 101 func TestPoint_Clone_Nil(t *testing.T) { 102 var fp *query.FloatPoint 103 if p := fp.Clone(); p != nil { 104 t.Errorf("expected nil, got %v", p) 105 } 106 107 var ip *query.IntegerPoint 108 if p := ip.Clone(); p != nil { 109 t.Errorf("expected nil, got %v", p) 110 } 111 112 var sp *query.StringPoint 113 if p := sp.Clone(); p != nil { 114 t.Errorf("expected nil, got %v", p) 115 } 116 117 var bp *query.BooleanPoint 118 if p := bp.Clone(); p != nil { 119 t.Errorf("expected nil, got %v", p) 120 } 121 } 122 123 // TestPoint_Fields ensures that no additional fields are added to the point structs. 124 // This struct is very sensitive and can effect performance unless handled carefully. 125 // To avoid the struct becoming a dumping ground for every function that needs to store 126 // miscellaneous information, this test is meant to ensure that new fields don't slip 127 // into the struct. 128 func TestPoint_Fields(t *testing.T) { 129 allowedFields := map[string]bool{ 130 "Name": true, 131 "Tags": true, 132 "Time": true, 133 "Nil": true, 134 "Value": true, 135 "Aux": true, 136 "Aggregated": true, 137 } 138 139 for _, typ := range []reflect.Type{ 140 reflect.TypeOf(query.FloatPoint{}), 141 reflect.TypeOf(query.IntegerPoint{}), 142 reflect.TypeOf(query.StringPoint{}), 143 reflect.TypeOf(query.BooleanPoint{}), 144 } { 145 f, ok := typ.FieldByNameFunc(func(name string) bool { 146 return !allowedFields[name] 147 }) 148 if ok { 149 t.Errorf("found an unallowed field in %s: %s %s", typ, f.Name, f.Type) 150 } 151 } 152 } 153 154 // Ensure that tags can return a unique id. 155 func TestTags_ID(t *testing.T) { 156 tags := query.NewTags(map[string]string{"foo": "bar", "baz": "bat"}) 157 if id := tags.ID(); id != "baz\x00foo\x00bat\x00bar" { 158 t.Fatalf("unexpected id: %q", id) 159 } 160 } 161 162 // Ensure that a subset can be created from a tag set. 163 func TestTags_Subset(t *testing.T) { 164 tags := query.NewTags(map[string]string{"a": "0", "b": "1", "c": "2"}) 165 subset := tags.Subset([]string{"b", "c", "d"}) 166 if keys := subset.Keys(); !reflect.DeepEqual(keys, []string{"b", "c", "d"}) { 167 t.Fatalf("unexpected keys: %+v", keys) 168 } else if v := subset.Value("a"); v != "" { 169 t.Fatalf("unexpected 'a' value: %s", v) 170 } else if v := subset.Value("b"); v != "1" { 171 t.Fatalf("unexpected 'b' value: %s", v) 172 } else if v := subset.Value("c"); v != "2" { 173 t.Fatalf("unexpected 'c' value: %s", v) 174 } else if v := subset.Value("d"); v != "" { 175 t.Fatalf("unexpected 'd' value: %s", v) 176 } 177 } 178 179 // ParseTags returns an instance of Tags for a comma-delimited list of key/values. 180 func ParseTags(s string) query.Tags { 181 m := make(map[string]string) 182 for _, kv := range strings.Split(s, ",") { 183 a := strings.Split(kv, "=") 184 m[a[0]] = a[1] 185 } 186 return query.NewTags(m) 187 }