Skip to content

Commit 155c74e

Browse files
committed
Generalize tests to metrics
1 parent 3ae284a commit 155c74e

File tree

2 files changed

+112
-56
lines changed

2 files changed

+112
-56
lines changed

exporters/autoexport/exporter_test.go

+20-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ import (
2222
"github.com/stretchr/testify/assert"
2323

2424
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
25+
"go.opentelemetry.io/otel/sdk/metric"
2526
"go.opentelemetry.io/otel/sdk/trace"
2627
)
2728

2829
func TestOTLPExporterReturnedWhenNoEnvOrFallbackExporterConfigured(t *testing.T) {
2930
exporter, err := NewSpanExporter(context.Background())
3031
assert.NoError(t, err)
31-
assertOTLPHTTPExporter(t, exporter)
32+
assertOTLPHTTPSpanExporter(t, exporter)
3233
}
3334

3435
func TestFallbackExporterReturnedWhenNoEnvExporterConfigured(t *testing.T) {
@@ -51,7 +52,7 @@ func TestEnvExporterIsPreferredOverFallbackExporter(t *testing.T) {
5152
WithFallbackSpanExporter(testExporter),
5253
)
5354
assert.NoError(t, err)
54-
assertOTLPHTTPExporter(t, exporter)
55+
assertOTLPHTTPSpanExporter(t, exporter)
5556
}
5657

5758
func TestEnvExporterOTLPOverHTTP(t *testing.T) {
@@ -60,7 +61,7 @@ func TestEnvExporterOTLPOverHTTP(t *testing.T) {
6061

6162
exporter, err := NewSpanExporter(context.Background())
6263
assert.NoError(t, err)
63-
assertOTLPHTTPExporter(t, exporter)
64+
assertOTLPHTTPSpanExporter(t, exporter)
6465
}
6566

6667
func TestEnvExporterOTLPOverGRPC(t *testing.T) {
@@ -69,15 +70,15 @@ func TestEnvExporterOTLPOverGRPC(t *testing.T) {
6970

7071
exporter, err := NewSpanExporter(context.Background())
7172
assert.NoError(t, err)
72-
assertOTLPGRPCExporter(t, exporter)
73+
assertOTLPGRPCSpanExporter(t, exporter)
7374
}
7475

7576
func TestEnvExporterOTLPOverGRPCOnlyProtocol(t *testing.T) {
7677
t.Setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "grpc")
7778

7879
exporter, err := NewSpanExporter(context.Background())
7980
assert.NoError(t, err)
80-
assertOTLPGRPCExporter(t, exporter)
81+
assertOTLPGRPCSpanExporter(t, exporter)
8182
}
8283

8384
func TestEnvExporterOTLPInvalidProtocol(t *testing.T) {
@@ -97,7 +98,19 @@ func TestEnvExporterNone(t *testing.T) {
9798
assert.True(t, IsNoneSpanExporter(exporter))
9899
}
99100

100-
func assertOTLPHTTPExporter(t *testing.T, got trace.SpanExporter) {
101+
func assertOTLPHTTPMetricReader(t *testing.T, got metric.Reader) {
102+
t.Helper()
103+
104+
if !assert.IsType(t, metric.NewPeriodicReader(nil), got) {
105+
return
106+
}
107+
108+
// Implementation detail hack. This may break when bumping OTLP exporter modules as it uses unexported API.
109+
clientType := reflect.Indirect(reflect.ValueOf(got)).FieldByName("exporter").Elem().Type().String()
110+
assert.Equal(t, "*internal.exporter", clientType)
111+
}
112+
113+
func assertOTLPHTTPSpanExporter(t *testing.T, got trace.SpanExporter) {
101114
t.Helper()
102115

103116
if !assert.IsType(t, &otlptrace.Exporter{}, got) {
@@ -111,7 +124,7 @@ func assertOTLPHTTPExporter(t *testing.T, got trace.SpanExporter) {
111124
assert.False(t, IsNoneSpanExporter(got))
112125
}
113126

114-
func assertOTLPGRPCExporter(t *testing.T, got trace.SpanExporter) {
127+
func assertOTLPGRPCSpanExporter(t *testing.T, got trace.SpanExporter) {
115128
t.Helper()
116129

117130
if !assert.IsType(t, &otlptrace.Exporter{}, got) {

exporters/autoexport/registry_test.go

+92-49
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ import (
2929
"go.opentelemetry.io/otel/sdk/trace"
3030
)
3131

32+
type testType struct{ string }
33+
34+
func factory(val string) func(ctx context.Context) (*testType, error) {
35+
return func(ctx context.Context) (*testType, error) { return &testType{val}, nil }
36+
}
37+
38+
func newTestRegistry() registry[*testType] {
39+
return registry[*testType]{
40+
names: map[string]func(context.Context) (*testType, error){
41+
"": factory(""),
42+
"otlp": factory("otlp"),
43+
"none": factory("none"),
44+
},
45+
}
46+
}
47+
3248
var stdoutMetricFactory = func(ctx context.Context) (metric.Reader, error) {
3349
exp, err := stdoutmetric.New()
3450
if err != nil {
@@ -46,45 +62,27 @@ var stdoutSpanFactory = func(ctx context.Context) (trace.SpanExporter, error) {
4662
}
4763

4864
func TestCanStoreExporterFactory(t *testing.T) {
49-
t.Run("spans", func(t *testing.T) {
50-
r := newSpanExporterRegistry()
51-
assert.NotPanics(t, func() {
52-
require.NoError(t, r.store("first", stdoutSpanFactory))
53-
})
54-
})
55-
t.Run("metrics", func(t *testing.T) {
56-
r := newMetricReaderRegistry()
57-
assert.NotPanics(t, func() {
58-
require.NoError(t, r.store("first", stdoutMetricFactory))
59-
})
65+
r := newTestRegistry()
66+
assert.NotPanics(t, func() {
67+
require.NoError(t, r.store("first", factory("first")))
6068
})
6169
}
6270

6371
func TestLoadOfUnknownExporterReturnsError(t *testing.T) {
64-
t.Run("spans", func(t *testing.T) {
65-
r := newSpanExporterRegistry()
66-
assert.NotPanics(t, func() {
67-
exp, err := r.load(context.Background(), "non-existent")
68-
assert.Equal(t, err, errUnknownExporter, "empty registry should hold nothing")
69-
assert.Nil(t, exp, "non-nil exporter returned")
70-
})
71-
})
72-
t.Run("metrics", func(t *testing.T) {
73-
r := newMetricReaderRegistry()
74-
assert.NotPanics(t, func() {
75-
exp, err := r.load(context.Background(), "non-existent")
76-
assert.Equal(t, err, errUnknownExporter, "empty registry should hold nothing")
77-
assert.Nil(t, exp, "non-nil exporter returned")
78-
})
72+
r := newTestRegistry()
73+
assert.NotPanics(t, func() {
74+
exp, err := r.load(context.Background(), "non-existent")
75+
assert.Equal(t, err, errUnknownExporter, "empty registry should hold nothing")
76+
assert.Nil(t, exp, "non-nil exporter returned")
7977
})
8078
}
8179

8280
func TestRegistryIsConcurrentSafe(t *testing.T) {
8381
const exporterName = "stdout"
8482

85-
r := newSpanExporterRegistry()
83+
r := newTestRegistry()
8684
assert.NotPanics(t, func() {
87-
require.NoError(t, r.store(exporterName, stdoutSpanFactory))
85+
require.NoError(t, r.store(exporterName, factory("stdout")))
8886
})
8987

9088
var wg sync.WaitGroup
@@ -93,63 +91,108 @@ func TestRegistryIsConcurrentSafe(t *testing.T) {
9391
go func() {
9492
defer wg.Done()
9593
assert.NotPanics(t, func() {
96-
require.ErrorIs(t, r.store(exporterName, stdoutSpanFactory), errDuplicateRegistration)
94+
require.ErrorIs(t, r.store(exporterName, factory("stdout")), errDuplicateRegistration)
9795
})
9896
}()
9997

10098
wg.Add(1)
10199
go func() {
102100
defer wg.Done()
103101
assert.NotPanics(t, func() {
104-
exp, err := r.load(context.Background(), exporterName)
102+
_, err := r.load(context.Background(), exporterName)
105103
assert.NoError(t, err, "missing exporter in registry")
106-
assert.IsType(t, &stdouttrace.Exporter{}, exp)
107104
})
108105
}()
109106

110107
wg.Wait()
111108
}
112109

113-
func TestSubsequentCallsToGetExporterReturnsNewInstances(t *testing.T) {
110+
type funcs[T any] struct {
111+
makeExporter func(context.Context, string) (T, error)
112+
assertOTLPHTTP func(*testing.T, T)
113+
registerFactory func(string, func(context.Context) (T, error))
114+
stdoutFactory func(ctx context.Context) (T, error)
115+
registry *registry[T]
116+
}
117+
118+
var (
119+
spanFuncs = funcs[trace.SpanExporter]{
120+
makeExporter: spanExporter,
121+
assertOTLPHTTP: assertOTLPHTTPSpanExporter,
122+
registerFactory: RegisterSpanExporter,
123+
stdoutFactory: stdoutSpanFactory,
124+
registry: &spanExporterRegistry,
125+
}
126+
127+
metricFuncs = funcs[metric.Reader]{
128+
makeExporter: metricReader,
129+
assertOTLPHTTP: assertOTLPHTTPMetricReader,
130+
registerFactory: RegisterMetricReader,
131+
stdoutFactory: stdoutMetricFactory,
132+
registry: &metricReaderRegistry,
133+
}
134+
)
135+
136+
func (f funcs[T]) testSubsequentCallsToGetExporterReturnsNewInstances(t *testing.T) {
114137
const exporterType = "otlp"
115-
exp1, err := spanExporter(context.Background(), exporterType)
138+
139+
exp1, err := f.makeExporter(context.Background(), exporterType)
116140
assert.NoError(t, err)
117-
assertOTLPHTTPExporter(t, exp1)
141+
f.assertOTLPHTTP(t, exp1)
118142

119143
exp2, err := spanExporter(context.Background(), exporterType)
120144
assert.NoError(t, err)
121-
assertOTLPHTTPExporter(t, exp2)
145+
assertOTLPHTTPSpanExporter(t, exp2)
122146

123147
assert.NotSame(t, exp1, exp2)
124148
}
125149

126-
func TestDefaultOTLPExporterFactoriesAreAutomaticallyRegistered(t *testing.T) {
127-
exp1, err := spanExporter(context.Background(), "")
150+
func TestSubsequentCallsToGetExporterReturnsNewInstances(t *testing.T) {
151+
t.Run("spans", spanFuncs.testSubsequentCallsToGetExporterReturnsNewInstances)
152+
t.Run("metrics", metricFuncs.testSubsequentCallsToGetExporterReturnsNewInstances)
153+
}
154+
155+
func (f funcs[T]) testDefaultOTLPExporterFactoriesAreAutomaticallyRegistered(t *testing.T) {
156+
exp1, err := f.makeExporter(context.Background(), "")
128157
assert.Nil(t, err)
129-
assertOTLPHTTPExporter(t, exp1)
158+
f.assertOTLPHTTP(t, exp1)
130159

131-
exp2, err := spanExporter(context.Background(), "otlp")
160+
exp2, err := f.makeExporter(context.Background(), "otlp")
132161
assert.Nil(t, err)
133-
assertOTLPHTTPExporter(t, exp2)
162+
f.assertOTLPHTTP(t, exp2)
134163
}
135164

136-
func TestEnvRegistryCanRegisterExporterFactory(t *testing.T) {
165+
func TestDefaultOTLPExporterFactoriesAreAutomaticallyRegistered(t *testing.T) {
166+
t.Run("spans", spanFuncs.testDefaultOTLPExporterFactoriesAreAutomaticallyRegistered)
167+
t.Run("metrics", metricFuncs.testDefaultOTLPExporterFactoriesAreAutomaticallyRegistered)
168+
}
169+
170+
func (f funcs[T]) testEnvRegistryCanRegisterExporterFactory(t *testing.T) {
137171
const exporterName = "custom"
138-
RegisterSpanExporter(exporterName, stdoutSpanFactory)
139-
t.Cleanup(func() { spanExporterRegistry.drop(exporterName) })
172+
f.registerFactory(exporterName, f.stdoutFactory)
173+
t.Cleanup(func() { f.registry.drop(exporterName) })
140174

141-
exp, err := spanExporterRegistry.load(context.Background(), exporterName)
175+
_, err := f.registry.load(context.Background(), exporterName)
142176
assert.Nil(t, err, "missing exporter in envRegistry")
143-
assert.IsType(t, &stdouttrace.Exporter{}, exp)
144177
}
145178

146-
func TestEnvRegistryPanicsOnDuplicateRegisterCalls(t *testing.T) {
179+
func TestEnvRegistryCanRegisterExporterFactory(t *testing.T) {
180+
t.Run("spans", spanFuncs.testEnvRegistryCanRegisterExporterFactory)
181+
t.Run("metrics", metricFuncs.testEnvRegistryCanRegisterExporterFactory)
182+
}
183+
184+
func (f funcs[T]) testEnvRegistryPanicsOnDuplicateRegisterCalls(t *testing.T) {
147185
const exporterName = "custom"
148-
RegisterSpanExporter(exporterName, stdoutSpanFactory)
149-
t.Cleanup(func() { spanExporterRegistry.drop(exporterName) })
186+
f.registerFactory(exporterName, f.stdoutFactory)
187+
t.Cleanup(func() { f.registry.drop(exporterName) })
150188

151189
errString := fmt.Sprintf("%s: %q", errDuplicateRegistration, exporterName)
152190
assert.PanicsWithError(t, errString, func() {
153-
RegisterSpanExporter(exporterName, stdoutSpanFactory)
191+
f.registerFactory(exporterName, f.stdoutFactory)
154192
})
155193
}
194+
195+
func TestEnvRegistryPanicsOnDuplicateRegisterCalls(t *testing.T) {
196+
t.Run("spans", spanFuncs.testEnvRegistryPanicsOnDuplicateRegisterCalls)
197+
t.Run("metrics", metricFuncs.testEnvRegistryPanicsOnDuplicateRegisterCalls)
198+
}

0 commit comments

Comments
 (0)