1package tsdb
2
3import (
4	"fmt"
5	"reflect"
6	"sort"
7	"testing"
8)
9
10func TestStore_mergeTagValues(t *testing.T) {
11	examples := []struct {
12		in  []tagValues
13		out TagValues
14	}{
15		{},
16		{in: make([]tagValues, 4), out: TagValues{Values: []KeyValue{}}},
17		{
18			in:  []tagValues{createtagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}})},
19			out: createTagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}}),
20		},
21		{
22			in: []tagValues{
23				createtagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}}),
24				createtagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}}),
25			},
26			out: createTagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}}),
27		},
28		{
29			in: []tagValues{
30				createtagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}}),
31				createtagValues("m0", map[string][]string{"host": {"server-a", "server-d", "server-e"}}),
32			},
33			out: createTagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c", "server-d", "server-e"}}),
34		},
35		{
36			in: []tagValues{
37				createtagValues("m0", map[string][]string{"host": {"server-a"}}),
38				createtagValues("m0", map[string][]string{}),
39				createtagValues("m0", map[string][]string{"host": {"server-a"}}),
40			},
41			out: createTagValues("m0", map[string][]string{"host": {"server-a"}}),
42		},
43		{
44			in: []tagValues{
45				createtagValues("m0", map[string][]string{"host": {"server-q", "server-z"}}),
46				createtagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c"}}),
47				createtagValues("m0", map[string][]string{"host": {"server-a", "server-d", "server-e"}}),
48				createtagValues("m0", map[string][]string{"host": {"server-e", "server-q", "server-z"}}),
49				createtagValues("m0", map[string][]string{"host": {"server-a"}}),
50			},
51			out: createTagValues("m0", map[string][]string{"host": {"server-a", "server-b", "server-c", "server-d", "server-e", "server-q", "server-z"}}),
52		},
53		{
54			in: []tagValues{
55				createtagValues("m0", map[string][]string{"a": {"0", "1"}, "host1": {"server-q", "server-z"}}),
56				createtagValues("m0", map[string][]string{"a": {"0", "2"}, "host2": {"server-a", "server-b", "server-c"}}),
57				createtagValues("m0", map[string][]string{"a": {"0", "3"}, "host3": {"server-a", "server-d", "server-e"}}),
58				createtagValues("m0", map[string][]string{"a": {"0", "4"}, "host4": {"server-e", "server-q", "server-z"}}),
59				createtagValues("m0", map[string][]string{"a": {"0", "5"}, "host5": {"server-a"}}),
60			},
61			out: createTagValues("m0", map[string][]string{
62				"a":     {"0", "1", "2", "3", "4", "5"},
63				"host1": {"server-q", "server-z"},
64				"host2": {"server-a", "server-b", "server-c"},
65				"host3": {"server-a", "server-d", "server-e"},
66				"host4": {"server-e", "server-q", "server-z"},
67				"host5": {"server-a"},
68			}),
69		},
70		{
71			in: []tagValues{
72				createtagValues("m0", map[string][]string{"region": {"east-1", "west-1"}, "host": {"server-a", "server-b", "server-c"}}),
73				createtagValues("m0", map[string][]string{"region": {"north-1", "west-1"}, "host": {"server-a", "server-d", "server-e"}}),
74			},
75			out: createTagValues("m0", map[string][]string{
76				"host":   {"server-a", "server-b", "server-c", "server-d", "server-e"},
77				"region": {"east-1", "north-1", "west-1"},
78			}),
79		},
80		{
81			in: []tagValues{
82				createtagValues("m0", map[string][]string{"region": {"east-1", "west-1"}, "host": {"server-a", "server-b", "server-c"}}),
83				createtagValues("m0", map[string][]string{"city": {"Baltimore", "Las Vegas"}}),
84			},
85			out: createTagValues("m0", map[string][]string{
86				"city":   {"Baltimore", "Las Vegas"},
87				"host":   {"server-a", "server-b", "server-c"},
88				"region": {"east-1", "west-1"},
89			}),
90		},
91		{
92			in: []tagValues{
93				createtagValues("m0", map[string][]string{"city": {"Baltimore", "Las Vegas"}}),
94				createtagValues("m0", map[string][]string{"region": {"east-1", "west-1"}, "host": {"server-a", "server-b", "server-c"}}),
95			},
96			out: createTagValues("m0", map[string][]string{
97				"city":   {"Baltimore", "Las Vegas"},
98				"host":   {"server-a", "server-b", "server-c"},
99				"region": {"east-1", "west-1"},
100			}),
101		},
102		{
103			in: []tagValues{
104				createtagValues("m0", map[string][]string{"region": {"east-1", "west-1"}, "host": {"server-a", "server-b", "server-c"}}),
105				createtagValues("m0", map[string][]string{}),
106			},
107			out: createTagValues("m0", map[string][]string{
108				"host":   {"server-a", "server-b", "server-c"},
109				"region": {"east-1", "west-1"},
110			}),
111		},
112	}
113
114	buf := make([][2]int, 10)
115	for i, example := range examples {
116		t.Run(fmt.Sprintf("example_%d", i+1), func(t *testing.T) {
117			if got, exp := mergeTagValues(buf, example.in...), example.out; !reflect.DeepEqual(got, exp) {
118				t.Fatalf("\ngot\n %#v\n\n expected\n %#v", got, exp)
119			}
120		})
121	}
122}
123
124// Helper to create some tagValues.
125func createtagValues(mname string, kvs map[string][]string) tagValues {
126	out := tagValues{
127		name:   []byte(mname),
128		keys:   make([]string, 0, len(kvs)),
129		values: make([][]string, len(kvs)),
130	}
131
132	for k := range kvs {
133		out.keys = append(out.keys, k)
134	}
135	sort.Strings(out.keys)
136
137	for i, k := range out.keys {
138		values := kvs[k]
139		sort.Strings(values)
140		out.values[i] = values
141	}
142	return out
143}
144
145// Helper to create some TagValues
146func createTagValues(mname string, kvs map[string][]string) TagValues {
147	var sz int
148	for _, v := range kvs {
149		sz += len(v)
150	}
151
152	out := TagValues{
153		Measurement: mname,
154		Values:      make([]KeyValue, 0, sz),
155	}
156
157	for tk, tvs := range kvs {
158		for _, tv := range tvs {
159			out.Values = append(out.Values, KeyValue{Key: tk, Value: tv})
160		}
161		// We have to sort the KeyValues since that's how they're provided from
162		// the Store.
163		sort.Sort(KeyValues(out.Values))
164	}
165
166	return out
167}
168