1 package generic_test
2
3
4
5
6
7 import (
8 "go/ast"
9 "go/importer"
10 "go/parser"
11 "go/token"
12 "go/types"
13 "io/ioutil"
14 "math"
15 "math/rand"
16 "sync"
17 "testing"
18
19 "github.com/go-kit/kit/metrics/generic"
20 "github.com/go-kit/kit/metrics/teststat"
21 )
22
23 func TestCounter(t *testing.T) {
24 name := "my_counter"
25 counter := generic.NewCounter(name).With("label", "counter").(*generic.Counter)
26 if want, have := name, counter.Name; want != have {
27 t.Errorf("Name: want %q, have %q", want, have)
28 }
29 value := counter.Value
30 if err := teststat.TestCounter(counter, value); err != nil {
31 t.Fatal(err)
32 }
33 }
34
35 func TestValueReset(t *testing.T) {
36 counter := generic.NewCounter("test_value_reset")
37 counter.Add(123)
38 counter.Add(456)
39 counter.Add(789)
40 if want, have := float64(123+456+789), counter.ValueReset(); want != have {
41 t.Errorf("want %f, have %f", want, have)
42 }
43 if want, have := float64(0), counter.Value(); want != have {
44 t.Errorf("want %f, have %f", want, have)
45 }
46 }
47
48 func TestGauge(t *testing.T) {
49 name := "my_gauge"
50 gauge := generic.NewGauge(name).With("label", "gauge").(*generic.Gauge)
51 if want, have := name, gauge.Name; want != have {
52 t.Errorf("Name: want %q, have %q", want, have)
53 }
54 value := func() []float64 { return []float64{gauge.Value()} }
55 if err := teststat.TestGauge(gauge, value); err != nil {
56 t.Fatal(err)
57 }
58 }
59
60 func TestHistogram(t *testing.T) {
61 name := "my_histogram"
62 histogram := generic.NewHistogram(name, 50).With("label", "histogram").(*generic.Histogram)
63 if want, have := name, histogram.Name; want != have {
64 t.Errorf("Name: want %q, have %q", want, have)
65 }
66 quantiles := func() (float64, float64, float64, float64) {
67 return histogram.Quantile(0.50), histogram.Quantile(0.90), histogram.Quantile(0.95), histogram.Quantile(0.99)
68 }
69 if err := teststat.TestHistogram(histogram, quantiles, 0.01); err != nil {
70 t.Fatal(err)
71 }
72 }
73
74 func TestIssue424(t *testing.T) {
75 var (
76 histogram = generic.NewHistogram("dont_panic", 50)
77 concurrency = 100
78 operations = 1000
79 wg sync.WaitGroup
80 )
81
82 wg.Add(concurrency)
83 for i := 0; i < concurrency; i++ {
84 go func() {
85 defer wg.Done()
86 for j := 0; j < operations; j++ {
87 histogram.Observe(float64(j))
88 histogram.Observe(histogram.Quantile(0.5))
89 }
90 }()
91 }
92 wg.Wait()
93 }
94
95 func TestSimpleHistogram(t *testing.T) {
96 histogram := generic.NewSimpleHistogram().With("label", "simple_histogram").(*generic.SimpleHistogram)
97 var (
98 sum int
99 count = 1234
100 )
101 for i := 0; i < count; i++ {
102 value := rand.Intn(1000)
103 sum += value
104 histogram.Observe(float64(value))
105 }
106
107 var (
108 want = float64(sum) / float64(count)
109 have = histogram.ApproximateMovingAverage()
110 tolerance = 0.001
111 )
112 if math.Abs(want-have)/want > tolerance {
113 t.Errorf("want %f, have %f", want, have)
114 }
115 }
116
117
118
119
120
121 func TestAtomicAlignment(t *testing.T) {
122 content, err := ioutil.ReadFile("./generic.go")
123 if err != nil {
124 t.Fatal(err)
125 }
126
127 fset := token.NewFileSet()
128
129 file, err := parser.ParseFile(fset, "generic.go", content, parser.ParseComments)
130 if err != nil {
131 t.Fatal(err)
132 }
133
134 conf := types.Config{Importer: importer.ForCompiler(fset, "source", nil)}
135
136 pkg, err := conf.Check(".", fset, []*ast.File{file}, nil)
137 if err != nil {
138 t.Fatal(err)
139 }
140
141
142 sizes := types.SizesFor("gc", "arm")
143
144 names := []string{"Counter", "Gauge"}
145
146 for _, name := range names {
147 t.Run(name, func(t *testing.T) {
148 checkAtomicAlignment(t, sizes, pkg.Scope().Lookup(name), pkg)
149 })
150 }
151 }
152
153 func checkAtomicAlignment(t *testing.T, sizes types.Sizes, obj types.Object, pkg *types.Package) {
154 t.Helper()
155
156 st := obj.Type().Underlying().(*types.Struct)
157
158 posToCheck := make(map[int]types.Type)
159
160 var vars []*types.Var
161 for i := 0; i < st.NumFields(); i++ {
162 field := st.Field(i)
163
164 if v, ok := field.Type().(*types.Basic); ok {
165 switch v.Kind() {
166 case types.Uint64, types.Float64, types.Int64:
167 posToCheck[i] = v
168 }
169 }
170
171 vars = append(vars, types.NewVar(field.Pos(), pkg, field.Name(), field.Type()))
172 }
173
174 offsets := sizes.Offsetsof(vars)
175 for i, offset := range offsets {
176 if _, ok := posToCheck[i]; !ok {
177 continue
178 }
179
180 if offset%8 != 0 {
181 t.Errorf("misalignment detected in %s for the type %s, offset %d", obj.Name(), posToCheck[i], offset)
182 }
183 }
184 }
185
View as plain text