@@ -3,8 +3,11 @@ package observability
33import (
44 "context"
55 "errors"
6+ "io"
67 "net/http"
8+ "net/http/httptest"
79 "testing"
10+ "time"
811
912 "go.opentelemetry.io/otel"
1013 "go.opentelemetry.io/otel/propagation"
@@ -143,3 +146,93 @@ func TestInit_RestoresProvidersWhenMetricExporterInitFails(t *testing.T) {
143146 t .Fatal ("Init() did not restore the original propagator" )
144147 }
145148}
149+
150+ func TestInit_ExportsTracesAndMetricsToConfiguredOTLPEndpoints (t * testing.T ) {
151+ originalTracerProvider := otel .GetTracerProvider ()
152+ originalMeterProvider := otel .GetMeterProvider ()
153+ originalPropagator := otel .GetTextMapPropagator ()
154+ t .Cleanup (func () {
155+ otel .SetTextMapPropagator (originalPropagator )
156+ otel .SetTracerProvider (originalTracerProvider )
157+ otel .SetMeterProvider (originalMeterProvider )
158+ })
159+
160+ type requestRecord struct {
161+ path string
162+ sharedToken string
163+ bodyLen int
164+ }
165+
166+ requests := make (chan requestRecord , 8 )
167+ collector := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
168+ body , err := io .ReadAll (r .Body )
169+ if err != nil {
170+ t .Fatalf ("read collector body: %v" , err )
171+ }
172+ requests <- requestRecord {
173+ path : r .URL .Path ,
174+ sharedToken : r .Header .Get ("X-OTLP-Shared-Token" ),
175+ bodyLen : len (body ),
176+ }
177+ w .WriteHeader (http .StatusAccepted )
178+ }))
179+ defer collector .Close ()
180+
181+ t .Setenv ("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" , collector .URL + "/v1/traces" )
182+ t .Setenv ("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" , collector .URL + "/v1/metrics" )
183+ t .Setenv ("OTEL_EXPORTER_OTLP_HEADERS" , "X-OTLP-Shared-Token=abc123TOKEN" )
184+
185+ shutdown , enabled , err := Init (context .Background (), Config {
186+ ServiceName : "wasteland-hosted" ,
187+ ServiceNamespace : "wasteland" ,
188+ ServiceVersion : "test" ,
189+ Environment : "test" ,
190+ })
191+ if err != nil {
192+ t .Fatalf ("Init() error = %v" , err )
193+ }
194+ if ! enabled {
195+ t .Fatal ("Init() enabled = false, want true" )
196+ }
197+
198+ tracer := otel .Tracer ("test" )
199+ _ , span := tracer .Start (context .Background (), "wasteland.otlp.proof" )
200+ span .End ()
201+
202+ meter := otel .Meter ("test" )
203+ counter , err := meter .Int64Counter ("wasteland_otlp_proof_total" )
204+ if err != nil {
205+ t .Fatalf ("Int64Counter() error = %v" , err )
206+ }
207+ counter .Add (context .Background (), 1 )
208+
209+ shutdownCtx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
210+ defer cancel ()
211+ if err := shutdown (shutdownCtx ); err != nil {
212+ t .Fatalf ("shutdown() error = %v" , err )
213+ }
214+
215+ seenPaths := map [string ]bool {}
216+ timeout := time .After (5 * time .Second )
217+ for len (seenPaths ) < 2 {
218+ select {
219+ case req := <- requests :
220+ if req .sharedToken != "abc123TOKEN" {
221+ t .Fatalf ("collector shared token = %q, want %q" , req .sharedToken , "abc123TOKEN" )
222+ }
223+ if req .bodyLen == 0 {
224+ t .Fatalf ("collector body for %s was empty" , req .path )
225+ }
226+ seenPaths [req .path ] = true
227+ case <- timeout :
228+ t .Fatalf ("timed out waiting for OTLP exports, saw %v" , seenPaths )
229+ }
230+ }
231+
232+ if ! seenPaths ["/v1/traces" ] {
233+ t .Fatal ("expected OTLP trace export to hit /v1/traces" )
234+ }
235+ if ! seenPaths ["/v1/metrics" ] {
236+ t .Fatal ("expected OTLP metrics export to hit /v1/metrics" )
237+ }
238+ }
0 commit comments