package observability import ( "context" "testing" "time" "go.opentelemetry.io/otel/trace/noop" ) func TestInitTracer_Disabled(t *testing.T) { t.Parallel() cfg := Config{ Enabled: false, } ctx := context.Background() tp, err := InitTracer(ctx, cfg) if err != nil { t.Fatalf("InitTracer failed: %v", err) } if tp == nil { t.Fatal("Expected tracer provider, got nil") } } func TestInitTracer_DevelopmentMode(t *testing.T) { t.Parallel() cfg := Config{ Enabled: true, ServiceName: "test-service", ServiceVersion: "1.0.0", Environment: "development", } ctx := context.Background() tp, err := InitTracer(ctx, cfg) if err != nil { t.Fatalf("InitTracer failed: %v", err) } if tp == nil { t.Fatal("Expected tracer provider, got nil") } // Verify it's not a no-op tracer if _, ok := tp.(*noop.TracerProvider); ok { t.Error("Expected real tracer provider in development mode") } // Clean up if err := ShutdownTracer(ctx, tp); err != nil { t.Logf("Failed to shutdown tracer: %v", err) } } func TestInitTracer_ProductionMode_WithOTLP(t *testing.T) { t.Parallel() cfg := Config{ Enabled: true, ServiceName: "test-service", ServiceVersion: "1.0.0", Environment: "production", OTLPEndpoint: "http://localhost:4318", } ctx := context.Background() tp, err := InitTracer(ctx, cfg) if err != nil { // OTLP endpoint might not be available in tests, that's okay t.Skipf("Skipping test - OTLP endpoint not available: %v", err) } if tp == nil { t.Fatal("Expected tracer provider, got nil") } // Clean up if err := ShutdownTracer(ctx, tp); err != nil { t.Logf("Failed to shutdown tracer: %v", err) } } func TestInitTracer_ProductionMode_WithoutOTLP(t *testing.T) { t.Parallel() cfg := Config{ Enabled: true, ServiceName: "test-service", ServiceVersion: "1.0.0", Environment: "production", OTLPEndpoint: "", } ctx := context.Background() tp, err := InitTracer(ctx, cfg) if err != nil { t.Fatalf("InitTracer failed: %v", err) } if tp == nil { t.Fatal("Expected tracer provider, got nil") } // Clean up if err := ShutdownTracer(ctx, tp); err != nil { t.Logf("Failed to shutdown tracer: %v", err) } } func TestShutdownTracer(t *testing.T) { t.Parallel() cfg := Config{ Enabled: true, ServiceName: "test-service", ServiceVersion: "1.0.0", Environment: "development", } ctx := context.Background() tp, err := InitTracer(ctx, cfg) if err != nil { t.Fatalf("InitTracer failed: %v", err) } shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := ShutdownTracer(shutdownCtx, tp); err != nil { t.Errorf("ShutdownTracer failed: %v", err) } } func TestShutdownTracer_NoopTracer(t *testing.T) { t.Parallel() tp := noop.NewTracerProvider() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Should not fail for no-op tracer if err := ShutdownTracer(ctx, tp); err != nil { t.Errorf("ShutdownTracer should handle no-op tracer gracefully: %v", err) } } func TestInitTracer_InvalidResource(t *testing.T) { t.Parallel() // This test would require invalid resource configuration // Since resource.New doesn't have easy ways to fail, we'll skip this // In practice, resource.New should always succeed with valid inputs t.Skip("Skipping - resource.New doesn't easily fail with test inputs") } func TestTracerProvider_ImplementsInterface(t *testing.T) { t.Parallel() cfg := Config{ Enabled: true, ServiceName: "test-service", ServiceVersion: "1.0.0", Environment: "development", } ctx := context.Background() tp, err := InitTracer(ctx, cfg) if err != nil { t.Skipf("Skipping test - tracer init failed: %v", err) } // Verify it implements the interface (compile-time check) // If tp doesn't implement trace.TracerProvider, this won't compile _ = tp // Clean up if err := ShutdownTracer(ctx, tp); err != nil { t.Logf("Failed to shutdown tracer: %v", err) } }