package telemetry // All tests in this file mutate the OpenTelemetry global tracer provider via // otel.SetTracerProvider (called by InitializeTracing / ReconfigureTracerProvider). // They MUST NOT be parallelized — t.Parallel() would race on the global state. import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" ) // TestReconfigureTracerProvider_NilOldNoOp confirms that hot-reload is a // no-op when telemetry was never initialized at startup. Hot-reloading // telemetry-on requires a different code path that's out of scope for // ADR-0023 Phase 3. func TestReconfigureTracerProvider_NilOldNoOp(t *testing.T) { s := &Setup{ ServiceName: "test", OTLPEndpoint: "localhost:4317", Insecure: true, SamplerType: "always_on", SamplerRatio: 1.0, Version: "test", } newTP, err := s.ReconfigureTracerProvider(context.Background(), nil) assert.NoError(t, err) assert.Nil(t, newTP) } // TestReconfigureTracerProvider_SwapsGlobal confirms that after a successful // reconfigure, the global otel tracer provider points to the new one and the // old one was shut down (Shutdown returns nil even after a second Shutdown, // so we just verify no error path hit). func TestReconfigureTracerProvider_SwapsGlobal(t *testing.T) { ctx := context.Background() s := &Setup{ ServiceName: "test", OTLPEndpoint: "localhost:4317", Insecure: true, SamplerType: "always_on", SamplerRatio: 1.0, Version: "test", } oldTP, err := s.InitializeTracing(ctx) require.NoError(t, err) require.NotNil(t, oldTP) t.Cleanup(func() { _ = oldTP.Shutdown(ctx) }) // belt-and-braces, harmless if already shut down // Mutate sampler before reconfigure s.SamplerType = "traceidratio" s.SamplerRatio = 0.25 newTP, err := s.ReconfigureTracerProvider(ctx, oldTP) require.NoError(t, err) require.NotNil(t, newTP) t.Cleanup(func() { _ = newTP.Shutdown(ctx) }) // otel.GetTracerProvider returns a TracerProvider interface — pointer equality // against newTP is the strongest assertion available without sdk-private state. gotTP := otel.GetTracerProvider() assert.Same(t, newTP, gotTP, "global tracer provider should be the new TP") } // TestReconfigureTracerProvider_OldShutdownErrorDoesNotFailReconfigure // confirms that even if shutting down the old TP fails, the new TP is still // returned and active. We simulate this by passing an already-shut-down // provider as oldTP — its second Shutdown is harmless on the SDK but // exercises the error-tolerance path. func TestReconfigureTracerProvider_OldShutdownErrorDoesNotFailReconfigure(t *testing.T) { ctx := context.Background() s := &Setup{ ServiceName: "test", OTLPEndpoint: "localhost:4317", Insecure: true, SamplerType: "always_on", SamplerRatio: 1.0, Version: "test", } oldTP, err := s.InitializeTracing(ctx) require.NoError(t, err) _ = oldTP.Shutdown(ctx) // pre-shutdown: subsequent Shutdown is documented to return nil newTP, err := s.ReconfigureTracerProvider(ctx, oldTP) require.NoError(t, err) require.NotNil(t, newTP) t.Cleanup(func() { _ = newTP.Shutdown(ctx) }) }