Manager env block (downward-API resource attrs, commented OTLP examples), architecture §10 + Decisions entries, README section. Lint: goconst constants, gofmt, logcheck (Setup now takes its logger from ctx via logf.FromContext). Co-Authored-By: Claude <noreply@anthropic.com>
119 lines
3.8 KiB
Go
119 lines
3.8 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"slices"
|
|
"testing"
|
|
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/codes"
|
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
|
"go.opentelemetry.io/otel/sdk/trace/tracetest"
|
|
"go.opentelemetry.io/otel/trace"
|
|
|
|
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/tracing"
|
|
)
|
|
|
|
func TestWithTracing_spanPerCall(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inner *staticProvider
|
|
call func(p Provider) error
|
|
wantSpan string
|
|
wantStatus codes.Code
|
|
wantResult string
|
|
wantAttr attribute.KeyValue
|
|
}{
|
|
{
|
|
name: "successful create",
|
|
inner: &staticProvider{},
|
|
call: func(p Provider) error { _, err := p.Create(context.Background(), CreateRequest{}); return err },
|
|
wantSpan: "provider.create",
|
|
wantStatus: codes.Ok,
|
|
wantResult: resultOK,
|
|
wantAttr: attribute.String("provider.id", "id-1"),
|
|
},
|
|
{
|
|
name: "get NotFound is not a span error",
|
|
inner: &staticProvider{getErr: Wrap(ErrNotFound, "get", "x", "id-1", nil)},
|
|
call: func(p Provider) error { _, err := p.Get(context.Background(), "id-1"); return err },
|
|
wantSpan: "provider.get",
|
|
wantStatus: codes.Ok,
|
|
wantResult: resultNotFound,
|
|
wantAttr: attribute.String("provider.id", "id-1"),
|
|
},
|
|
{
|
|
name: "delete transient error",
|
|
inner: &staticProvider{deleteErr: Wrap(ErrTransient, "delete", "x", "id-1", errors.New("503"))},
|
|
call: func(p Provider) error { return p.Delete(context.Background(), "id-1") },
|
|
wantSpan: "provider.delete",
|
|
wantStatus: codes.Error,
|
|
wantResult: resultTransient,
|
|
wantAttr: attribute.String("provider.id", "id-1"),
|
|
},
|
|
{
|
|
name: "quota exceeded create",
|
|
inner: &staticProvider{createErr: Wrap(ErrQuotaExceeded, "create", "x", "", nil)},
|
|
call: func(p Provider) error { _, err := p.Create(context.Background(), CreateRequest{}); return err },
|
|
wantSpan: "provider.create",
|
|
wantStatus: codes.Error,
|
|
wantResult: resultQuotaExceeded,
|
|
wantAttr: attribute.String("provider.name", "x"),
|
|
},
|
|
{
|
|
name: "list records instance count",
|
|
inner: &staticProvider{},
|
|
call: func(p Provider) error { _, err := p.ListByTag(context.Background()); return err },
|
|
wantSpan: "provider.list",
|
|
wantStatus: codes.Ok,
|
|
wantResult: resultOK,
|
|
wantAttr: attribute.Int("provider.instances", 0),
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
sr := tracetest.NewSpanRecorder()
|
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))
|
|
t.Cleanup(func() { _ = tp.Shutdown(context.Background()) })
|
|
|
|
p := WithTracing("x", tc.inner, tracing.WithTracerProvider(tp))
|
|
err := tc.call(p)
|
|
|
|
wantErr := errors.Join(tc.inner.createErr, tc.inner.getErr, tc.inner.deleteErr, tc.inner.listErr)
|
|
if (wantErr == nil) != (err == nil) {
|
|
t.Fatalf("decorator changed the error: got %v", err)
|
|
}
|
|
|
|
ended := sr.Ended()
|
|
if len(ended) != 1 {
|
|
t.Fatalf("got %d spans, want 1", len(ended))
|
|
}
|
|
span := ended[0]
|
|
if span.Name() != tc.wantSpan {
|
|
t.Errorf("span name = %q, want %q", span.Name(), tc.wantSpan)
|
|
}
|
|
if span.SpanKind() != trace.SpanKindClient {
|
|
t.Errorf("span kind = %v, want client", span.SpanKind())
|
|
}
|
|
if span.Status().Code != tc.wantStatus {
|
|
t.Errorf("status = %v, want %v", span.Status().Code, tc.wantStatus)
|
|
}
|
|
attrs := span.Attributes()
|
|
hasAttr := func(want attribute.KeyValue) bool {
|
|
return slices.Contains(attrs, want)
|
|
}
|
|
if !hasAttr(attribute.String("provider.result", tc.wantResult)) {
|
|
t.Errorf("provider.result %q missing in %v", tc.wantResult, attrs)
|
|
}
|
|
if !hasAttr(tc.wantAttr) {
|
|
t.Errorf("attribute %v missing in %v", tc.wantAttr, attrs)
|
|
}
|
|
})
|
|
}
|
|
}
|