1package statsd
2
3import (
4	"sort"
5	"strings"
6	"sync"
7	"testing"
8
9	"github.com/stretchr/testify/assert"
10)
11
12func TestAggregatorSample(t *testing.T) {
13	a := newAggregator(nil)
14
15	tags := []string{"tag1", "tag2"}
16
17	for i := 0; i < 2; i++ {
18		a.gauge("gaugeTest", 21, tags)
19		assert.Len(t, a.gauges, 1)
20		assert.Contains(t, a.gauges, "gaugeTest:tag1,tag2")
21
22		a.count("countTest", 21, tags)
23		assert.Len(t, a.counts, 1)
24		assert.Contains(t, a.counts, "countTest:tag1,tag2")
25
26		a.set("setTest", "value1", tags)
27		assert.Len(t, a.sets, 1)
28		assert.Contains(t, a.sets, "setTest:tag1,tag2")
29
30		a.set("setTest", "value1", tags)
31		assert.Len(t, a.sets, 1)
32		assert.Contains(t, a.sets, "setTest:tag1,tag2")
33
34		a.histogram("histogramTest", 21, tags)
35		assert.Len(t, a.histograms.values, 1)
36		assert.Contains(t, a.histograms.values, "histogramTest:tag1,tag2")
37
38		a.distribution("distributionTest", 21, tags)
39		assert.Len(t, a.distributions.values, 1)
40		assert.Contains(t, a.distributions.values, "distributionTest:tag1,tag2")
41
42		a.timing("timingTest", 21, tags)
43		assert.Len(t, a.timings.values, 1)
44		assert.Contains(t, a.timings.values, "timingTest:tag1,tag2")
45	}
46}
47
48func TestAggregatorFlush(t *testing.T) {
49	a := newAggregator(nil)
50
51	tags := []string{"tag1", "tag2"}
52
53	a.gauge("gaugeTest1", 21, tags)
54	a.gauge("gaugeTest1", 10, tags)
55	a.gauge("gaugeTest2", 15, tags)
56
57	a.count("countTest1", 21, tags)
58	a.count("countTest1", 10, tags)
59	a.count("countTest2", 1, tags)
60
61	a.set("setTest1", "value1", tags)
62	a.set("setTest1", "value1", tags)
63	a.set("setTest1", "value2", tags)
64	a.set("setTest2", "value1", tags)
65
66	a.histogram("histogramTest1", 21, tags)
67	a.histogram("histogramTest1", 22, tags)
68	a.histogram("histogramTest2", 23, tags)
69
70	a.distribution("distributionTest1", 21, tags)
71	a.distribution("distributionTest1", 22, tags)
72	a.distribution("distributionTest2", 23, tags)
73
74	a.timing("timingTest1", 21, tags)
75	a.timing("timingTest1", 22, tags)
76	a.timing("timingTest2", 23, tags)
77
78	metrics := a.flushMetrics()
79
80	assert.Len(t, a.gauges, 0)
81	assert.Len(t, a.counts, 0)
82	assert.Len(t, a.sets, 0)
83	assert.Len(t, a.histograms.values, 0)
84	assert.Len(t, a.distributions.values, 0)
85	assert.Len(t, a.timings.values, 0)
86
87	assert.Len(t, metrics, 13)
88
89	sort.Slice(metrics, func(i, j int) bool {
90		if metrics[i].metricType == metrics[j].metricType {
91			res := strings.Compare(metrics[i].name, metrics[j].name)
92			// this happens fo set
93			if res == 0 {
94				return strings.Compare(metrics[i].svalue, metrics[j].svalue) != 1
95			}
96			return res != 1
97		}
98		return metrics[i].metricType < metrics[j].metricType
99	})
100
101	assert.Equal(t, []metric{
102		metric{
103			metricType: gauge,
104			name:       "gaugeTest1",
105			tags:       tags,
106			rate:       1,
107			fvalue:     float64(10),
108		},
109		metric{
110			metricType: gauge,
111			name:       "gaugeTest2",
112			tags:       tags,
113			rate:       1,
114			fvalue:     float64(15),
115		},
116		metric{
117			metricType: count,
118			name:       "countTest1",
119			tags:       tags,
120			rate:       1,
121			ivalue:     int64(31),
122		},
123		metric{
124			metricType: count,
125			name:       "countTest2",
126			tags:       tags,
127			rate:       1,
128			ivalue:     int64(1),
129		},
130		metric{
131			metricType: histogramAggregated,
132			name:       "histogramTest1",
133			stags:      strings.Join(tags, tagSeparatorSymbol),
134			rate:       1,
135			fvalues:    []float64{21.0, 22.0},
136		},
137		metric{
138			metricType: histogramAggregated,
139			name:       "histogramTest2",
140			stags:      strings.Join(tags, tagSeparatorSymbol),
141			rate:       1,
142			fvalues:    []float64{23.0},
143		},
144		metric{
145			metricType: distributionAggregated,
146			name:       "distributionTest1",
147			stags:      strings.Join(tags, tagSeparatorSymbol),
148			rate:       1,
149			fvalues:    []float64{21.0, 22.0},
150		},
151		metric{
152			metricType: distributionAggregated,
153			name:       "distributionTest2",
154			stags:      strings.Join(tags, tagSeparatorSymbol),
155			rate:       1,
156			fvalues:    []float64{23.0},
157		},
158		metric{
159			metricType: set,
160			name:       "setTest1",
161			tags:       tags,
162			rate:       1,
163			svalue:     "value1",
164		},
165		metric{
166			metricType: set,
167			name:       "setTest1",
168			tags:       tags,
169			rate:       1,
170			svalue:     "value2",
171		},
172		metric{
173			metricType: set,
174			name:       "setTest2",
175			tags:       tags,
176			rate:       1,
177			svalue:     "value1",
178		},
179		metric{
180			metricType: timingAggregated,
181			name:       "timingTest1",
182			stags:      strings.Join(tags, tagSeparatorSymbol),
183			rate:       1,
184			fvalues:    []float64{21.0, 22.0},
185		},
186		metric{
187			metricType: timingAggregated,
188			name:       "timingTest2",
189			stags:      strings.Join(tags, tagSeparatorSymbol),
190			rate:       1,
191			fvalues:    []float64{23.0},
192		},
193	},
194		metrics)
195
196}
197
198func TestAggregatorFlushConcurrency(t *testing.T) {
199	a := newAggregator(nil)
200
201	var wg sync.WaitGroup
202	wg.Add(10)
203
204	tags := []string{"tag1", "tag2"}
205
206	for i := 0; i < 5; i++ {
207		go func() {
208			defer wg.Done()
209
210			a.gauge("gaugeTest1", 21, tags)
211			a.count("countTest1", 21, tags)
212			a.set("setTest1", "value1", tags)
213			a.histogram("histogramTest1", 21, tags)
214			a.distribution("distributionTest1", 21, tags)
215			a.timing("timingTest1", 21, tags)
216		}()
217	}
218
219	for i := 0; i < 5; i++ {
220		go func() {
221			defer wg.Done()
222
223			a.flushMetrics()
224		}()
225	}
226
227	wg.Wait()
228}
229