opentelemetry-go-contrib/instrumentation/github.com/emicklei/go-restful/otelrestful/test/restful_test.go

183 lines
5.5 KiB
Go

// 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 test
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/emicklei/go-restful/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/contrib/instrumentation/github.com/emicklei/go-restful/otelrestful"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
oteltrace "go.opentelemetry.io/otel/trace"
)
func TestChildSpanFromGlobalTracer(t *testing.T) {
sr := tracetest.NewSpanRecorder()
otel.SetTracerProvider(sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)))
handlerFunc := func(req *restful.Request, resp *restful.Response) {
resp.WriteHeader(http.StatusOK)
}
ws := &restful.WebService{}
ws.Route(ws.GET("/user/{id}").To(handlerFunc).
Returns(200, "OK", nil).
Returns(404, "Not Found", nil))
container := restful.NewContainer()
container.Filter(otelrestful.OTelFilter("my-service"))
container.Add(ws)
r := httptest.NewRequest("GET", "/user/123", nil)
w := httptest.NewRecorder()
container.ServeHTTP(w, r)
assert.Len(t, sr.Ended(), 1)
}
func TestChildSpanFromCustomTracer(t *testing.T) {
sr := tracetest.NewSpanRecorder()
provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
handlerFunc := func(req *restful.Request, resp *restful.Response) {
resp.WriteHeader(http.StatusOK)
}
ws := &restful.WebService{}
ws.Route(ws.GET("/user/{id}").To(handlerFunc))
container := restful.NewContainer()
container.Filter(otelrestful.OTelFilter("my-service", otelrestful.WithTracerProvider(provider)))
container.Add(ws)
r := httptest.NewRequest("GET", "/user/123", nil)
w := httptest.NewRecorder()
container.ServeHTTP(w, r)
assert.Len(t, sr.Ended(), 1)
}
func TestChildSpanNames(t *testing.T) {
sr := tracetest.NewSpanRecorder()
provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
handlerFunc := func(req *restful.Request, resp *restful.Response) {
resp.WriteHeader(http.StatusOK)
}
ws := &restful.WebService{}
ws.Route(ws.GET("/user/{id:[0-9]+}").To(handlerFunc))
container := restful.NewContainer()
container.Filter(otelrestful.OTelFilter("foobar", otelrestful.WithTracerProvider(provider)))
container.Add(ws)
ws.Route(ws.GET("/book/{title}").To(func(req *restful.Request, resp *restful.Response) {
_, _ = resp.Write(([]byte)("ok"))
}))
r := httptest.NewRequest("GET", "/user/123", nil)
w := httptest.NewRecorder()
container.ServeHTTP(w, r)
spans := sr.Ended()
require.Len(t, spans, 1)
assertSpan(
t,
spans[0],
"/user/{id:[0-9]+}",
attribute.String("http.server_name", "foobar"),
attribute.Int("http.status_code", http.StatusOK),
attribute.String("http.method", "GET"),
attribute.String("http.target", "/user/123"),
attribute.String("http.route", "/user/{id:[0-9]+}"),
)
r = httptest.NewRequest("GET", "/book/foo", nil)
w = httptest.NewRecorder()
container.ServeHTTP(w, r)
spans = sr.Ended()
require.Len(t, spans, 2)
assertSpan(
t,
spans[1],
"/book/{title}",
attribute.String("http.server_name", "foobar"),
attribute.Int("http.status_code", http.StatusOK),
attribute.String("http.method", "GET"),
attribute.String("http.target", "/book/foo"),
attribute.String("http.route", "/book/{title}"),
)
}
func TestMultiFilters(t *testing.T) {
sr := tracetest.NewSpanRecorder()
provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
retOK := func(req *restful.Request, resp *restful.Response) { resp.WriteHeader(http.StatusOK) }
ws1 := &restful.WebService{}
ws1.Path("/user")
ws1.Route(ws1.GET("/{id}").
Filter(otelrestful.OTelFilter("my-service", otelrestful.WithTracerProvider(provider))).
To(retOK))
ws1.Route(ws1.GET("/{id}/books").
Filter(otelrestful.OTelFilter("book-service", otelrestful.WithTracerProvider(provider))).
To(retOK))
ws2 := &restful.WebService{}
ws2.Path("/library")
ws2.Filter(otelrestful.OTelFilter("library-service", otelrestful.WithTracerProvider(provider)))
ws2.Route(ws2.GET("/{name}").To(retOK))
container := restful.NewContainer()
container.Add(ws1)
container.Add(ws2)
r := httptest.NewRequest("GET", "/user/123", nil)
w := httptest.NewRecorder()
container.ServeHTTP(w, r)
spans := sr.Ended()
require.Len(t, spans, 1)
assertSpan(t, spans[0], "/user/{id}")
r = httptest.NewRequest("GET", "/user/123/books", nil)
w = httptest.NewRecorder()
container.ServeHTTP(w, r)
spans = sr.Ended()
require.Len(t, spans, 2)
assertSpan(t, spans[1], "/user/{id}/books")
r = httptest.NewRequest("GET", "/library/metropolitan", nil)
w = httptest.NewRecorder()
container.ServeHTTP(w, r)
spans = sr.Ended()
require.Len(t, spans, 3)
assertSpan(t, spans[2], "/library/{name}")
}
func assertSpan(t *testing.T, span sdktrace.ReadOnlySpan, name string, attrs ...attribute.KeyValue) {
assert.Equal(t, name, span.Name())
assert.Equal(t, oteltrace.SpanKindServer, span.SpanKind())
gotA := span.Attributes()
for _, a := range attrs {
assert.Contains(t, gotA, a)
}
}