package api import ( "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/supabase/auth/internal/conf" "github.com/supabase/auth/internal/storage" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" semconv "go.opentelemetry.io/otel/semconv/v1.25.0" ) type OpenTelemetryTracerTestSuite struct { suite.Suite API *API Config *conf.GlobalConfiguration } func TestOpenTelemetryTracer(t *testing.T) { api, config, err := setupAPIForTestWithCallback(func(config *conf.GlobalConfiguration, conn *storage.Connection) { if config != nil { config.Tracing.Enabled = true config.Tracing.Exporter = conf.OpenTelemetryTracing } }) require.NoError(t, err) ts := &OpenTelemetryTracerTestSuite{ API: api, Config: config, } defer api.db.Close() suite.Run(t, ts) } func getAttribute(attributes []attribute.KeyValue, key attribute.Key) *attribute.Value { for _, value := range attributes { if value.Key == key { return &value.Value } } return nil } func (ts *OpenTelemetryTracerTestSuite) TestOpenTelemetryTracer_Spans() { exporter := tracetest.NewInMemoryExporter() bsp := sdktrace.NewSimpleSpanProcessor(exporter) traceProvider := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithSpanProcessor(bsp), ) otel.SetTracerProvider(traceProvider) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "http://localhost/something1", nil) req.Header.Set("User-Agent", "whatever") ts.API.handler.ServeHTTP(w, req) req = httptest.NewRequest(http.MethodGet, "http://localhost/something2", nil) req.Header.Set("User-Agent", "whatever") ts.API.handler.ServeHTTP(w, req) spanStubs := exporter.GetSpans() spans := spanStubs.Snapshots() if assert.Equal(ts.T(), 2, len(spans)) { attributes1 := spans[0].Attributes() method1 := getAttribute(attributes1, semconv.HTTPMethodKey) assert.Equal(ts.T(), "POST", method1.AsString()) url1 := getAttribute(attributes1, semconv.HTTPTargetKey) assert.Equal(ts.T(), "/something1", url1.AsString()) statusCode1 := getAttribute(attributes1, semconv.HTTPStatusCodeKey) assert.Equal(ts.T(), int64(404), statusCode1.AsInt64()) attributes2 := spans[1].Attributes() method2 := getAttribute(attributes2, semconv.HTTPMethodKey) assert.Equal(ts.T(), "GET", method2.AsString()) url2 := getAttribute(attributes2, semconv.HTTPTargetKey) assert.Equal(ts.T(), "/something2", url2.AsString()) statusCode2 := getAttribute(attributes2, semconv.HTTPStatusCodeKey) assert.Equal(ts.T(), int64(404), statusCode2.AsInt64()) } }