diff --git a/api/global/internal/propagator_test.go b/api/global/internal/propagator_test.go new file mode 100644 index 00000000000..4500df89f43 --- /dev/null +++ b/api/global/internal/propagator_test.go @@ -0,0 +1,108 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal_test + +import ( + "context" + "testing" + + "go.opentelemetry.io/otel/api/global/internal" + "go.opentelemetry.io/otel/oteltest" +) + +func TestTextMapPropagatorDelegation(t *testing.T) { + internal.ResetForTest() + ctx := context.Background() + carrier := oteltest.NewTextMapCarrier(nil) + + // The default should be a noop. + initial := internal.TextMapPropagator() + initial.Inject(ctx, carrier) + ctx = initial.Extract(ctx, carrier) + if !carrier.GotN(t, 0) || !carrier.SetN(t, 0) { + return + } + + // Make sure the delegate woks as expected. + delegate := oteltest.NewTextMapPropagator("test") + delegate.Inject(ctx, carrier) + ctx = delegate.Extract(ctx, carrier) + if !delegate.InjectedN(t, carrier, 1) || !delegate.ExtractedN(t, ctx, 1) { + return + } + + // The initial propagator should use the delegate after it is set as the + // global. + internal.SetTextMapPropagator(delegate) + initial.Inject(ctx, carrier) + ctx = initial.Extract(ctx, carrier) + delegate.InjectedN(t, carrier, 2) + delegate.ExtractedN(t, ctx, 2) +} + +func TestTextMapPropagatorDelegationNil(t *testing.T) { + internal.ResetForTest() + ctx := context.Background() + carrier := oteltest.NewTextMapCarrier(nil) + + // The default should be a noop. + initial := internal.TextMapPropagator() + initial.Inject(ctx, carrier) + ctx = initial.Extract(ctx, carrier) + if !carrier.GotN(t, 0) || !carrier.SetN(t, 0) { + return + } + + // Delegation to nil should not make a change. + internal.SetTextMapPropagator(nil) + initial.Inject(ctx, carrier) + initial.Extract(ctx, carrier) + if !carrier.GotN(t, 0) || !carrier.SetN(t, 0) { + return + } +} + +func TestTextMapPropagatorFields(t *testing.T) { + internal.ResetForTest() + initial := internal.TextMapPropagator() + delegate := oteltest.NewTextMapPropagator("test") + delegateFields := delegate.Fields() + + // Sanity check on the initial Fields. + if got := initial.Fields(); fieldsEqual(got, delegateFields) { + t.Fatalf("testing fields (%v) matched Noop fields (%v)", delegateFields, got) + } + internal.SetTextMapPropagator(delegate) + // Check previous returns from global not correctly delegate. + if got := initial.Fields(); !fieldsEqual(got, delegateFields) { + t.Errorf("global TextMapPropagator.Fields returned %v instead of delegating, want (%v)", got, delegateFields) + } + // Check new calls to global. + if got := internal.TextMapPropagator().Fields(); !fieldsEqual(got, delegateFields) { + t.Errorf("global TextMapPropagator.Fields returned %v, want (%v)", got, delegateFields) + } +} + +func fieldsEqual(f1, f2 []string) bool { + if len(f1) != len(f2) { + return false + } + for i := range f1 { + if f1[i] != f2[i] { + return false + } + } + return true +} diff --git a/api/global/internal/state.go b/api/global/internal/state.go index 9542e60bf98..f7c467fe27c 100644 --- a/api/global/internal/state.go +++ b/api/global/internal/state.go @@ -138,4 +138,5 @@ func ResetForTest() { globalPropagators = defaultPropagatorsValue() delegateMeterOnce = sync.Once{} delegateTraceOnce = sync.Once{} + delegateTextMapPropagatorOnce = sync.Once{} } diff --git a/api/global/internal/state_test.go b/api/global/internal/state_test.go new file mode 100644 index 00000000000..704e3782a22 --- /dev/null +++ b/api/global/internal/state_test.go @@ -0,0 +1,50 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal_test + +import ( + "testing" + + "go.opentelemetry.io/otel/api/global/internal" +) + +func TestResetsOfGlobalsPanic(t *testing.T) { + internal.ResetForTest() + tests := map[string]func(){ + "SetTextMapPropagator": func() { + internal.SetTextMapPropagator(internal.TextMapPropagator()) + }, + "SetTracerProvider": func() { + internal.SetTracerProvider(internal.TracerProvider()) + }, + "SetMeterProvider": func() { + internal.SetMeterProvider(internal.MeterProvider()) + }, + } + + for name, test := range tests { + shouldPanic(t, name, test) + } +} + +func shouldPanic(t *testing.T, name string, f func()) { + defer func() { + if r := recover(); r == nil { + t.Errorf("calling %s with default global did not panic", name) + } + }() + + f() +} diff --git a/oteltest/text_map_propagator.go b/oteltest/text_map_propagator.go index 320282a8e4b..b18919fac9b 100644 --- a/oteltest/text_map_propagator.go +++ b/oteltest/text_map_propagator.go @@ -111,7 +111,7 @@ func (c *TextMapCarrier) SetN(t *testing.T, n int) bool { c.mtx.Lock() defer c.mtx.Unlock() if len(c.sets) != n { - t.Errorf("TextMapCarrier.Set was called %d times, not %d", len(c.gets), n) + t.Errorf("TextMapCarrier.Set was called %d times, not %d", len(c.sets), n) return false } return true