1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package otlpconfig
19
20 import (
21 "errors"
22 "testing"
23 "time"
24
25 "github.com/stretchr/testify/assert"
26
27 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/envconfig"
28 )
29
30 const (
31 WeakCertificate = `
32 -----BEGIN CERTIFICATE-----
33 MIIBhzCCASygAwIBAgIRANHpHgAWeTnLZpTSxCKs0ggwCgYIKoZIzj0EAwIwEjEQ
34 MA4GA1UEChMHb3RlbC1nbzAeFw0yMTA0MDExMzU5MDNaFw0yMTA0MDExNDU5MDNa
35 MBIxEDAOBgNVBAoTB290ZWwtZ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS9
36 nWSkmPCxShxnp43F+PrOtbGV7sNfkbQ/kxzi9Ego0ZJdiXxkmv/C05QFddCW7Y0Z
37 sJCLHGogQsYnWJBXUZOVo2MwYTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
38 KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAsBgNVHREEJTAjgglsb2NhbGhvc3SHEAAA
39 AAAAAAAAAAAAAAAAAAGHBH8AAAEwCgYIKoZIzj0EAwIDSQAwRgIhANwZVVKvfvQ/
40 1HXsTvgH+xTQswOwSSKYJ1cVHQhqK7ZbAiEAus8NxpTRnp5DiTMuyVmhVNPB+bVH
41 Lhnm4N/QDk5rek0=
42 -----END CERTIFICATE-----
43 `
44 WeakPrivateKey = `
45 -----BEGIN PRIVATE KEY-----
46 MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgN8HEXiXhvByrJ1zK
47 SFT6Y2l2KqDWwWzKf+t4CyWrNKehRANCAAS9nWSkmPCxShxnp43F+PrOtbGV7sNf
48 kbQ/kxzi9Ego0ZJdiXxkmv/C05QFddCW7Y0ZsJCLHGogQsYnWJBXUZOV
49 -----END PRIVATE KEY-----
50 `
51 )
52
53 type env map[string]string
54
55 func (e *env) getEnv(env string) string {
56 return (*e)[env]
57 }
58
59 type fileReader map[string][]byte
60
61 func (f *fileReader) readFile(filename string) ([]byte, error) {
62 if b, ok := (*f)[filename]; ok {
63 return b, nil
64 }
65 return nil, errors.New("file not found")
66 }
67
68 func TestConfigs(t *testing.T) {
69 tlsCert, err := CreateTLSConfig([]byte(WeakCertificate))
70 assert.NoError(t, err)
71
72 tests := []struct {
73 name string
74 opts []GenericOption
75 env env
76 fileReader fileReader
77 asserts func(t *testing.T, c *Config, grpcOption bool)
78 }{
79 {
80 name: "Test default configs",
81 asserts: func(t *testing.T, c *Config, grpcOption bool) {
82 if grpcOption {
83 assert.Equal(t, "localhost:4317", c.Traces.Endpoint)
84 } else {
85 assert.Equal(t, "localhost:4318", c.Traces.Endpoint)
86 }
87 assert.Equal(t, NoCompression, c.Traces.Compression)
88 assert.Equal(t, map[string]string(nil), c.Traces.Headers)
89 assert.Equal(t, 10*time.Second, c.Traces.Timeout)
90 },
91 },
92
93
94 {
95 name: "Test With Endpoint",
96 opts: []GenericOption{
97 WithEndpoint("someendpoint"),
98 },
99 asserts: func(t *testing.T, c *Config, grpcOption bool) {
100 assert.Equal(t, "someendpoint", c.Traces.Endpoint)
101 },
102 },
103 {
104 name: "Test Environment Endpoint",
105 env: map[string]string{
106 "OTEL_EXPORTER_OTLP_ENDPOINT": "https://env.endpoint/prefix",
107 },
108 asserts: func(t *testing.T, c *Config, grpcOption bool) {
109 assert.False(t, c.Traces.Insecure)
110 if grpcOption {
111 assert.Equal(t, "env.endpoint/prefix", c.Traces.Endpoint)
112 } else {
113 assert.Equal(t, "env.endpoint", c.Traces.Endpoint)
114 assert.Equal(t, "/prefix/v1/traces", c.Traces.URLPath)
115 }
116 },
117 },
118 {
119 name: "Test Environment Signal Specific Endpoint",
120 env: map[string]string{
121 "OTEL_EXPORTER_OTLP_ENDPOINT": "https://overrode.by.signal.specific/env/var",
122 "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "http://env.traces.endpoint",
123 },
124 asserts: func(t *testing.T, c *Config, grpcOption bool) {
125 assert.True(t, c.Traces.Insecure)
126 assert.Equal(t, "env.traces.endpoint", c.Traces.Endpoint)
127 if !grpcOption {
128 assert.Equal(t, "/", c.Traces.URLPath)
129 }
130 },
131 },
132 {
133 name: "Test Mixed Environment and With Endpoint",
134 opts: []GenericOption{
135 WithEndpoint("traces_endpoint"),
136 },
137 env: map[string]string{
138 "OTEL_EXPORTER_OTLP_ENDPOINT": "env_endpoint",
139 },
140 asserts: func(t *testing.T, c *Config, grpcOption bool) {
141 assert.Equal(t, "traces_endpoint", c.Traces.Endpoint)
142 },
143 },
144 {
145 name: "Test Environment Endpoint with HTTP scheme",
146 env: map[string]string{
147 "OTEL_EXPORTER_OTLP_ENDPOINT": "http://env_endpoint",
148 },
149 asserts: func(t *testing.T, c *Config, grpcOption bool) {
150 assert.Equal(t, "env_endpoint", c.Traces.Endpoint)
151 assert.Equal(t, true, c.Traces.Insecure)
152 },
153 },
154 {
155 name: "Test Environment Endpoint with HTTP scheme and leading & trailingspaces",
156 env: map[string]string{
157 "OTEL_EXPORTER_OTLP_ENDPOINT": " http://env_endpoint ",
158 },
159 asserts: func(t *testing.T, c *Config, grpcOption bool) {
160 assert.Equal(t, "env_endpoint", c.Traces.Endpoint)
161 assert.Equal(t, true, c.Traces.Insecure)
162 },
163 },
164 {
165 name: "Test Environment Endpoint with HTTPS scheme",
166 env: map[string]string{
167 "OTEL_EXPORTER_OTLP_ENDPOINT": "https://env_endpoint",
168 },
169 asserts: func(t *testing.T, c *Config, grpcOption bool) {
170 assert.Equal(t, "env_endpoint", c.Traces.Endpoint)
171 assert.Equal(t, false, c.Traces.Insecure)
172 },
173 },
174 {
175 name: "Test Environment Signal Specific Endpoint with uppercase scheme",
176 env: map[string]string{
177 "OTEL_EXPORTER_OTLP_ENDPOINT": "HTTPS://overrode_by_signal_specific",
178 "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "HtTp://env_traces_endpoint",
179 },
180 asserts: func(t *testing.T, c *Config, grpcOption bool) {
181 assert.Equal(t, "env_traces_endpoint", c.Traces.Endpoint)
182 assert.Equal(t, true, c.Traces.Insecure)
183 },
184 },
185
186
187 {
188 name: "Test Default Certificate",
189 asserts: func(t *testing.T, c *Config, grpcOption bool) {
190 if grpcOption {
191 assert.NotNil(t, c.Traces.GRPCCredentials)
192 } else {
193 assert.Nil(t, c.Traces.TLSCfg)
194 }
195 },
196 },
197 {
198 name: "Test With Certificate",
199 opts: []GenericOption{
200 WithTLSClientConfig(tlsCert),
201 },
202 asserts: func(t *testing.T, c *Config, grpcOption bool) {
203 if grpcOption {
204
205 assert.NotNil(t, c.Traces.GRPCCredentials)
206 } else {
207
208 assert.Equal(t, tlsCert.RootCAs.Subjects(), c.Traces.TLSCfg.RootCAs.Subjects())
209 }
210 },
211 },
212 {
213 name: "Test Environment Certificate",
214 env: map[string]string{
215 "OTEL_EXPORTER_OTLP_CERTIFICATE": "cert_path",
216 },
217 fileReader: fileReader{
218 "cert_path": []byte(WeakCertificate),
219 },
220 asserts: func(t *testing.T, c *Config, grpcOption bool) {
221 if grpcOption {
222 assert.NotNil(t, c.Traces.GRPCCredentials)
223 } else {
224
225 assert.Equal(t, tlsCert.RootCAs.Subjects(), c.Traces.TLSCfg.RootCAs.Subjects())
226 }
227 },
228 },
229 {
230 name: "Test Environment Signal Specific Certificate",
231 env: map[string]string{
232 "OTEL_EXPORTER_OTLP_CERTIFICATE": "overrode_by_signal_specific",
233 "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE": "cert_path",
234 },
235 fileReader: fileReader{
236 "cert_path": []byte(WeakCertificate),
237 "invalid_cert": []byte("invalid certificate file."),
238 },
239 asserts: func(t *testing.T, c *Config, grpcOption bool) {
240 if grpcOption {
241 assert.NotNil(t, c.Traces.GRPCCredentials)
242 } else {
243
244 assert.Equal(t, tlsCert.RootCAs.Subjects(), c.Traces.TLSCfg.RootCAs.Subjects())
245 }
246 },
247 },
248 {
249 name: "Test Mixed Environment and With Certificate",
250 opts: []GenericOption{},
251 env: map[string]string{
252 "OTEL_EXPORTER_OTLP_CERTIFICATE": "cert_path",
253 },
254 fileReader: fileReader{
255 "cert_path": []byte(WeakCertificate),
256 },
257 asserts: func(t *testing.T, c *Config, grpcOption bool) {
258 if grpcOption {
259 assert.NotNil(t, c.Traces.GRPCCredentials)
260 } else {
261
262 assert.Equal(t, tlsCert.RootCAs.Subjects(), c.Traces.TLSCfg.RootCAs.Subjects())
263 }
264 },
265 },
266
267
268 {
269 name: "Test With Headers",
270 opts: []GenericOption{
271 WithHeaders(map[string]string{"h1": "v1"}),
272 },
273 asserts: func(t *testing.T, c *Config, grpcOption bool) {
274 assert.Equal(t, map[string]string{"h1": "v1"}, c.Traces.Headers)
275 },
276 },
277 {
278 name: "Test Environment Headers",
279 env: map[string]string{"OTEL_EXPORTER_OTLP_HEADERS": "h1=v1,h2=v2"},
280 asserts: func(t *testing.T, c *Config, grpcOption bool) {
281 assert.Equal(t, map[string]string{"h1": "v1", "h2": "v2"}, c.Traces.Headers)
282 },
283 },
284 {
285 name: "Test Environment Signal Specific Headers",
286 env: map[string]string{
287 "OTEL_EXPORTER_OTLP_HEADERS": "overrode_by_signal_specific",
288 "OTEL_EXPORTER_OTLP_TRACES_HEADERS": "h1=v1,h2=v2",
289 },
290 asserts: func(t *testing.T, c *Config, grpcOption bool) {
291 assert.Equal(t, map[string]string{"h1": "v1", "h2": "v2"}, c.Traces.Headers)
292 },
293 },
294 {
295 name: "Test Mixed Environment and With Headers",
296 env: map[string]string{"OTEL_EXPORTER_OTLP_HEADERS": "h1=v1,h2=v2"},
297 opts: []GenericOption{},
298 asserts: func(t *testing.T, c *Config, grpcOption bool) {
299 assert.Equal(t, map[string]string{"h1": "v1", "h2": "v2"}, c.Traces.Headers)
300 },
301 },
302
303
304 {
305 name: "Test With Compression",
306 opts: []GenericOption{
307 WithCompression(GzipCompression),
308 },
309 asserts: func(t *testing.T, c *Config, grpcOption bool) {
310 assert.Equal(t, GzipCompression, c.Traces.Compression)
311 },
312 },
313 {
314 name: "Test Environment Compression",
315 env: map[string]string{
316 "OTEL_EXPORTER_OTLP_COMPRESSION": "gzip",
317 },
318 asserts: func(t *testing.T, c *Config, grpcOption bool) {
319 assert.Equal(t, GzipCompression, c.Traces.Compression)
320 },
321 },
322 {
323 name: "Test Environment Signal Specific Compression",
324 env: map[string]string{
325 "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION": "gzip",
326 },
327 asserts: func(t *testing.T, c *Config, grpcOption bool) {
328 assert.Equal(t, GzipCompression, c.Traces.Compression)
329 },
330 },
331 {
332 name: "Test Mixed Environment and With Compression",
333 opts: []GenericOption{
334 WithCompression(NoCompression),
335 },
336 env: map[string]string{
337 "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION": "gzip",
338 },
339 asserts: func(t *testing.T, c *Config, grpcOption bool) {
340 assert.Equal(t, NoCompression, c.Traces.Compression)
341 },
342 },
343
344
345 {
346 name: "Test With Timeout",
347 opts: []GenericOption{
348 WithTimeout(time.Duration(5 * time.Second)),
349 },
350 asserts: func(t *testing.T, c *Config, grpcOption bool) {
351 assert.Equal(t, 5*time.Second, c.Traces.Timeout)
352 },
353 },
354 {
355 name: "Test Environment Timeout",
356 env: map[string]string{
357 "OTEL_EXPORTER_OTLP_TIMEOUT": "15000",
358 },
359 asserts: func(t *testing.T, c *Config, grpcOption bool) {
360 assert.Equal(t, c.Traces.Timeout, 15*time.Second)
361 },
362 },
363 {
364 name: "Test Environment Signal Specific Timeout",
365 env: map[string]string{
366 "OTEL_EXPORTER_OTLP_TIMEOUT": "15000",
367 "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT": "27000",
368 },
369 asserts: func(t *testing.T, c *Config, grpcOption bool) {
370 assert.Equal(t, c.Traces.Timeout, 27*time.Second)
371 },
372 },
373 {
374 name: "Test Mixed Environment and With Timeout",
375 env: map[string]string{
376 "OTEL_EXPORTER_OTLP_TIMEOUT": "15000",
377 "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT": "27000",
378 },
379 opts: []GenericOption{
380 WithTimeout(5 * time.Second),
381 },
382 asserts: func(t *testing.T, c *Config, grpcOption bool) {
383 assert.Equal(t, c.Traces.Timeout, 5*time.Second)
384 },
385 },
386 }
387
388 for _, tt := range tests {
389 t.Run(tt.name, func(t *testing.T) {
390 origEOR := DefaultEnvOptionsReader
391 DefaultEnvOptionsReader = envconfig.EnvOptionsReader{
392 GetEnv: tt.env.getEnv,
393 ReadFile: tt.fileReader.readFile,
394 Namespace: "OTEL_EXPORTER_OTLP",
395 }
396 t.Cleanup(func() { DefaultEnvOptionsReader = origEOR })
397
398
399 cfg := NewHTTPConfig(asHTTPOptions(tt.opts)...)
400 tt.asserts(t, &cfg, false)
401
402
403 cfg = NewGRPCConfig(asGRPCOptions(tt.opts)...)
404 tt.asserts(t, &cfg, true)
405 })
406 }
407 }
408
409 func asHTTPOptions(opts []GenericOption) []HTTPOption {
410 converted := make([]HTTPOption, len(opts))
411 for i, o := range opts {
412 converted[i] = NewHTTPOption(o.ApplyHTTPOption)
413 }
414 return converted
415 }
416
417 func asGRPCOptions(opts []GenericOption) []GRPCOption {
418 converted := make([]GRPCOption, len(opts))
419 for i, o := range opts {
420 converted[i] = NewGRPCOption(o.ApplyGRPCOption)
421 }
422 return converted
423 }
424
425 func TestCleanPath(t *testing.T) {
426 type args struct {
427 urlPath string
428 defaultPath string
429 }
430 tests := []struct {
431 name string
432 args args
433 want string
434 }{
435 {
436 name: "clean empty path",
437 args: args{
438 urlPath: "",
439 defaultPath: "DefaultPath",
440 },
441 want: "DefaultPath",
442 },
443 {
444 name: "clean metrics path",
445 args: args{
446 urlPath: "/prefix/v1/metrics",
447 defaultPath: "DefaultMetricsPath",
448 },
449 want: "/prefix/v1/metrics",
450 },
451 {
452 name: "clean traces path",
453 args: args{
454 urlPath: "https://env_endpoint",
455 defaultPath: "DefaultTracesPath",
456 },
457 want: "/https:/env_endpoint",
458 },
459 {
460 name: "spaces trimmed",
461 args: args{
462 urlPath: " /dir",
463 },
464 want: "/dir",
465 },
466 {
467 name: "clean path empty",
468 args: args{
469 urlPath: "dir/..",
470 defaultPath: "DefaultTracesPath",
471 },
472 want: "DefaultTracesPath",
473 },
474 {
475 name: "make absolute",
476 args: args{
477 urlPath: "dir/a",
478 },
479 want: "/dir/a",
480 },
481 }
482 for _, tt := range tests {
483 t.Run(tt.name, func(t *testing.T) {
484 if got := cleanPath(tt.args.urlPath, tt.args.defaultPath); got != tt.want {
485 t.Errorf("CleanPath() = %v, want %v", got, tt.want)
486 }
487 })
488 }
489 }
490
View as plain text