1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package global
16
17 import (
18 "context"
19 "fmt"
20 "sync"
21 "testing"
22
23 "github.com/stretchr/testify/assert"
24 "github.com/stretchr/testify/require"
25
26 "go.opentelemetry.io/otel/metric"
27 "go.opentelemetry.io/otel/metric/noop"
28 )
29
30 func TestMeterProviderConcurrentSafe(t *testing.T) {
31 mp := &meterProvider{}
32 done := make(chan struct{})
33 finish := make(chan struct{})
34 go func() {
35 defer close(done)
36 for i := 0; ; i++ {
37 mp.Meter(fmt.Sprintf("a%d", i))
38 select {
39 case <-finish:
40 return
41 default:
42 }
43 }
44 }()
45
46 mp.setDelegate(noop.NewMeterProvider())
47 close(finish)
48 <-done
49 }
50
51 var zeroCallback metric.Callback = func(ctx context.Context, or metric.Observer) error {
52 return nil
53 }
54
55 func TestMeterConcurrentSafe(t *testing.T) {
56 mtr := &meter{}
57
58 wg := &sync.WaitGroup{}
59 wg.Add(1)
60 done := make(chan struct{})
61 finish := make(chan struct{})
62 go func() {
63 defer close(done)
64 for i, once := 0, false; ; i++ {
65 name := fmt.Sprintf("a%d", i)
66 _, _ = mtr.Float64ObservableCounter(name)
67 _, _ = mtr.Float64ObservableUpDownCounter(name)
68 _, _ = mtr.Float64ObservableGauge(name)
69 _, _ = mtr.Int64ObservableCounter(name)
70 _, _ = mtr.Int64ObservableUpDownCounter(name)
71 _, _ = mtr.Int64ObservableGauge(name)
72 _, _ = mtr.Float64Counter(name)
73 _, _ = mtr.Float64UpDownCounter(name)
74 _, _ = mtr.Float64Histogram(name)
75 _, _ = mtr.Int64Counter(name)
76 _, _ = mtr.Int64UpDownCounter(name)
77 _, _ = mtr.Int64Histogram(name)
78 _, _ = mtr.RegisterCallback(zeroCallback)
79 if !once {
80 wg.Done()
81 once = true
82 }
83 select {
84 case <-finish:
85 return
86 default:
87 }
88 }
89 }()
90
91 wg.Wait()
92 mtr.setDelegate(noop.NewMeterProvider())
93 close(finish)
94 <-done
95 }
96
97 func TestUnregisterConcurrentSafe(t *testing.T) {
98 mtr := &meter{}
99 reg, err := mtr.RegisterCallback(zeroCallback)
100 require.NoError(t, err)
101
102 wg := &sync.WaitGroup{}
103 wg.Add(1)
104 done := make(chan struct{})
105 finish := make(chan struct{})
106 go func() {
107 defer close(done)
108 for i, once := 0, false; ; i++ {
109 _ = reg.Unregister()
110 if !once {
111 wg.Done()
112 once = true
113 }
114 select {
115 case <-finish:
116 return
117 default:
118 }
119 }
120 }()
121 _ = reg.Unregister()
122
123 wg.Wait()
124 mtr.setDelegate(noop.NewMeterProvider())
125 close(finish)
126 <-done
127 }
128
129 func testSetupAllInstrumentTypes(t *testing.T, m metric.Meter) (metric.Float64Counter, metric.Float64ObservableCounter) {
130 afcounter, err := m.Float64ObservableCounter("test_Async_Counter")
131 require.NoError(t, err)
132 _, err = m.Float64ObservableUpDownCounter("test_Async_UpDownCounter")
133 assert.NoError(t, err)
134 _, err = m.Float64ObservableGauge("test_Async_Gauge")
135 assert.NoError(t, err)
136
137 _, err = m.Int64ObservableCounter("test_Async_Counter")
138 assert.NoError(t, err)
139 _, err = m.Int64ObservableUpDownCounter("test_Async_UpDownCounter")
140 assert.NoError(t, err)
141 _, err = m.Int64ObservableGauge("test_Async_Gauge")
142 assert.NoError(t, err)
143
144 _, err = m.RegisterCallback(func(ctx context.Context, obs metric.Observer) error {
145 obs.ObserveFloat64(afcounter, 3)
146 return nil
147 }, afcounter)
148 require.NoError(t, err)
149
150 sfcounter, err := m.Float64Counter("test_Async_Counter")
151 require.NoError(t, err)
152 _, err = m.Float64UpDownCounter("test_Async_UpDownCounter")
153 assert.NoError(t, err)
154 _, err = m.Float64Histogram("test_Async_Histogram")
155 assert.NoError(t, err)
156
157 _, err = m.Int64Counter("test_Async_Counter")
158 assert.NoError(t, err)
159 _, err = m.Int64UpDownCounter("test_Async_UpDownCounter")
160 assert.NoError(t, err)
161 _, err = m.Int64Histogram("test_Async_Histogram")
162 assert.NoError(t, err)
163
164 return sfcounter, afcounter
165 }
166
167
168 func testCollect(t *testing.T, m metric.Meter) {
169 if tMeter, ok := m.(*meter); ok {
170 m, ok = tMeter.delegate.Load().(metric.Meter)
171 if !ok {
172 t.Error("meter was not delegated")
173 return
174 }
175 }
176 tMeter, ok := m.(*testMeter)
177 if !ok {
178 t.Error("collect called on non-test Meter")
179 return
180 }
181 tMeter.collect()
182 }
183
184 func TestMeterProviderDelegatesCalls(t *testing.T) {
185
186
187
188
189 globalMeterProvider := &meterProvider{}
190
191 mp := &testMeterProvider{}
192
193
194 globalMeterProvider.setDelegate(mp)
195
196 assert.Equal(t, 0, mp.count)
197
198 meter := globalMeterProvider.Meter("go.opentelemetry.io/otel/metric/internal/global/meter_test")
199
200 ctr, actr := testSetupAllInstrumentTypes(t, meter)
201
202 ctr.Add(context.Background(), 5)
203
204 testCollect(t, meter)
205
206
207 require.IsType(t, &testMeter{}, meter)
208 tMeter := meter.(*testMeter)
209 assert.Equal(t, 1, tMeter.afCount)
210 assert.Equal(t, 1, tMeter.afUDCount)
211 assert.Equal(t, 1, tMeter.afGauge)
212 assert.Equal(t, 1, tMeter.aiCount)
213 assert.Equal(t, 1, tMeter.aiUDCount)
214 assert.Equal(t, 1, tMeter.aiGauge)
215 assert.Equal(t, 1, tMeter.sfCount)
216 assert.Equal(t, 1, tMeter.sfUDCount)
217 assert.Equal(t, 1, tMeter.sfHist)
218 assert.Equal(t, 1, tMeter.siCount)
219 assert.Equal(t, 1, tMeter.siUDCount)
220 assert.Equal(t, 1, tMeter.siHist)
221 assert.Equal(t, 1, len(tMeter.callbacks))
222
223
224 require.IsType(t, &testCountingFloatInstrument{}, ctr, "the meter did not delegate calls to the meter")
225 assert.Equal(t, 1, ctr.(*testCountingFloatInstrument).count)
226
227 require.IsType(t, &testCountingFloatInstrument{}, actr, "the meter did not delegate calls to the meter")
228 assert.Equal(t, 1, actr.(*testCountingFloatInstrument).count)
229
230 assert.Equal(t, 1, mp.count)
231 }
232
233 func TestMeterDelegatesCalls(t *testing.T) {
234
235
236
237
238
239 globalMeterProvider := &meterProvider{}
240
241 mp := &testMeterProvider{}
242
243 assert.Equal(t, 0, mp.count)
244
245 m := globalMeterProvider.Meter("go.opentelemetry.io/otel/metric/internal/global/meter_test")
246
247 globalMeterProvider.setDelegate(mp)
248
249 ctr, actr := testSetupAllInstrumentTypes(t, m)
250
251 ctr.Add(context.Background(), 5)
252
253 testCollect(t, m)
254
255
256 require.IsType(t, &meter{}, m)
257 tMeter := m.(*meter).delegate.Load().(*testMeter)
258 require.NotNil(t, tMeter)
259 assert.Equal(t, 1, tMeter.afCount)
260 assert.Equal(t, 1, tMeter.afUDCount)
261 assert.Equal(t, 1, tMeter.afGauge)
262 assert.Equal(t, 1, tMeter.aiCount)
263 assert.Equal(t, 1, tMeter.aiUDCount)
264 assert.Equal(t, 1, tMeter.aiGauge)
265 assert.Equal(t, 1, tMeter.sfCount)
266 assert.Equal(t, 1, tMeter.sfUDCount)
267 assert.Equal(t, 1, tMeter.sfHist)
268 assert.Equal(t, 1, tMeter.siCount)
269 assert.Equal(t, 1, tMeter.siUDCount)
270 assert.Equal(t, 1, tMeter.siHist)
271
272
273 require.IsType(t, &testCountingFloatInstrument{}, ctr, "the meter did not delegate calls to the meter")
274 assert.Equal(t, 1, ctr.(*testCountingFloatInstrument).count)
275
276
277 require.IsType(t, &testCountingFloatInstrument{}, actr, "the meter did not delegate calls to the meter")
278 assert.Equal(t, 1, actr.(*testCountingFloatInstrument).count)
279
280 assert.Equal(t, 1, mp.count)
281 }
282
283 func TestMeterDefersDelegations(t *testing.T) {
284
285
286
287
288 globalMeterProvider := &meterProvider{}
289
290 m := globalMeterProvider.Meter("go.opentelemetry.io/otel/metric/internal/global/meter_test")
291
292 ctr, actr := testSetupAllInstrumentTypes(t, m)
293
294 ctr.Add(context.Background(), 5)
295
296 mp := &testMeterProvider{}
297
298
299 globalMeterProvider.setDelegate(mp)
300
301 testCollect(t, m)
302
303
304 require.IsType(t, &meter{}, m)
305 tMeter := m.(*meter).delegate.Load().(*testMeter)
306 require.NotNil(t, tMeter)
307 assert.Equal(t, 1, tMeter.afCount)
308 assert.Equal(t, 1, tMeter.afUDCount)
309 assert.Equal(t, 1, tMeter.afGauge)
310 assert.Equal(t, 1, tMeter.aiCount)
311 assert.Equal(t, 1, tMeter.aiUDCount)
312 assert.Equal(t, 1, tMeter.aiGauge)
313 assert.Equal(t, 1, tMeter.sfCount)
314 assert.Equal(t, 1, tMeter.sfUDCount)
315 assert.Equal(t, 1, tMeter.sfHist)
316 assert.Equal(t, 1, tMeter.siCount)
317 assert.Equal(t, 1, tMeter.siUDCount)
318 assert.Equal(t, 1, tMeter.siHist)
319
320
321
322 assert.IsType(t, &sfCounter{}, ctr)
323 assert.IsType(t, &afCounter{}, actr)
324 assert.Equal(t, 1, mp.count)
325 }
326
327 func TestRegistrationDelegation(t *testing.T) {
328
329 globalMeterProvider := &meterProvider{}
330
331 m := globalMeterProvider.Meter("go.opentelemetry.io/otel/metric/internal/global/meter_test")
332 require.IsType(t, &meter{}, m)
333 mImpl := m.(*meter)
334
335 actr, err := m.Float64ObservableCounter("test_Async_Counter")
336 require.NoError(t, err)
337
338 var called0 bool
339 reg0, err := m.RegisterCallback(func(context.Context, metric.Observer) error {
340 called0 = true
341 return nil
342 }, actr)
343 require.NoError(t, err)
344 require.Equal(t, 1, mImpl.registry.Len(), "callback not registered")
345
346 assert.NoError(t, reg0.Unregister())
347 assert.Equal(t, 0, mImpl.registry.Len(), "callback not unregistered")
348
349 var called1 bool
350 reg1, err := m.RegisterCallback(func(context.Context, metric.Observer) error {
351 called1 = true
352 return nil
353 }, actr)
354 require.NoError(t, err)
355 require.Equal(t, 1, mImpl.registry.Len(), "second callback not registered")
356
357 mp := &testMeterProvider{}
358
359
360 globalMeterProvider.setDelegate(mp)
361
362 testCollect(t, m)
363 require.False(t, called0, "pre-delegation unregistered callback called")
364 require.True(t, called1, "callback not called")
365
366 called1 = false
367 assert.NoError(t, reg1.Unregister(), "unregister second callback")
368
369 testCollect(t, m)
370 assert.False(t, called1, "unregistered callback called")
371
372 assert.NotPanics(t, func() {
373 assert.NoError(t, reg1.Unregister(), "duplicate unregister calls")
374 })
375 }
376
View as plain text