open-code-review/internal/telemetry/exporter_test.go
kite e2d75b732a
Some checks are pending
CI / test (push) Waiting to run
test: fix golangci-lint errcheck/staticcheck issues in test code (#323)
2026-07-08 22:46:18 +08:00

204 lines
5.4 KiB
Go

package telemetry
import (
"bytes"
"context"
"io"
"os"
"strings"
"testing"
"go.opentelemetry.io/otel/sdk/resource"
)
func TestParseOTLPEndpoint(t *testing.T) {
cases := []struct {
name string
endpoint string
wantAddr string
wantInsecure bool
}{
{"http scheme strips and is insecure", "http://192.0.2.1:4317", "192.0.2.1:4317", true},
{"https scheme strips and keeps TLS", "https://otel.example.com:4317", "otel.example.com:4317", false},
{"bare host:port unchanged and keeps TLS", "localhost:4317", "localhost:4317", false},
{"uppercase HTTP scheme strips and is insecure", "HTTP://192.0.2.1:4317", "192.0.2.1:4317", true},
{"mixed-case Https scheme strips and keeps TLS", "Https://otel.example.com:4317", "otel.example.com:4317", false},
{"endpoint shorter than scheme prefix is unchanged", "ht", "ht", false},
{"http scheme with trailing slash is trimmed", "http://192.0.2.1:4317/", "192.0.2.1:4317", true},
{"https scheme with trailing slash is trimmed", "https://otel.example.com:4317/", "otel.example.com:4317", false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
addr, insecure := parseOTLPEndpoint(tc.endpoint)
if addr != tc.wantAddr {
t.Errorf("addr = %q, want %q", addr, tc.wantAddr)
}
if insecure != tc.wantInsecure {
t.Errorf("insecure = %v, want %v", insecure, tc.wantInsecure)
}
})
}
}
func TestNewStdoutTraceExporter(t *testing.T) {
exp, err := newStdoutTraceExporter()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if exp == nil {
t.Error("expected non-nil exporter")
}
}
func TestNewStdoutMetricExporter(t *testing.T) {
exp, err := newStdoutMetricExporter()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if exp == nil {
t.Error("expected non-nil exporter")
}
}
func TestInitConsoleProviders(t *testing.T) {
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
defer func() {
for _, fn := range shutdownFuncs {
_ = fn(context.Background())
}
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
}()
initConsoleProviders(resource.Default())
if tracerProvider == nil {
t.Error("expected tracerProvider to be set after initConsoleProviders")
}
if meterProvider == nil {
t.Error("expected meterProvider to be set after initConsoleProviders")
}
if len(shutdownFuncs) != 2 {
t.Errorf("expected 2 shutdown funcs, got %d", len(shutdownFuncs))
}
}
func TestInitOTLPProviders_InvalidEndpoint(t *testing.T) {
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
defer func() {
for _, fn := range shutdownFuncs {
_ = fn(context.Background())
}
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
}()
cfg := Config{
Exporter: "otlp",
OTLPEndpoint: "localhost:0",
}
initOTLPProviders(context.Background(), resource.Default(), cfg)
if tracerProvider == nil {
t.Error("expected tracerProvider to be set (OTLP exporter creation is lazy)")
}
}
func TestInitOTLPHTTPProviders_InvalidEndpoint(t *testing.T) {
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
defer func() {
for _, fn := range shutdownFuncs {
_ = fn(context.Background())
}
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
}()
cfg := Config{
Exporter: "otlp",
OTLPEndpoint: "localhost:0",
OTLPProtocol: "http/protobuf",
}
initOTLPHTTPProviders(context.Background(), resource.Default(), cfg)
if tracerProvider == nil {
t.Error("expected tracerProvider to be set (OTLP HTTP exporter creation is lazy)")
}
}
func TestInitOTLPProviders_ProtocolRouting(t *testing.T) {
cases := []struct {
name string
protocol string
wantWarning bool // default branch emits a gRPC fallback warning
}{
{"grpc default", "grpc", false},
{"empty defaults to grpc", "", false},
{"http/protobuf routes to http", "http/protobuf", false},
{"http/json routes to http", "http/json", false},
{"unknown falls back to grpc", "foo", true},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
// Capture stderr to assert on the fallback warning.
oldStderr := os.Stderr
r, w, _ := os.Pipe()
os.Stderr = w
cfg := Config{
Exporter: "otlp",
OTLPEndpoint: "localhost:0",
OTLPProtocol: tc.protocol,
}
initOTLPProviders(context.Background(), resource.Default(), cfg)
if err := w.Close(); err != nil {
t.Fatalf("close stderr pipe: %v", err)
}
os.Stderr = oldStderr
defer func() {
for _, fn := range shutdownFuncs {
_ = fn(context.Background())
}
tracerProvider = nil
meterProvider = nil
shutdownFuncs = nil
}()
if tracerProvider == nil {
t.Error("expected tracerProvider to be set")
}
if meterProvider == nil {
t.Error("expected meterProvider to be set")
}
if len(shutdownFuncs) != 2 {
t.Errorf("expected 2 shutdown funcs, got %d", len(shutdownFuncs))
}
var buf bytes.Buffer
if _, err := io.Copy(&buf, r); err != nil {
t.Fatalf("read stderr pipe: %v", err)
}
stderrOut := buf.String()
if tc.wantWarning {
if !strings.Contains(stderrOut, "falling back to gRPC") {
t.Errorf("expected gRPC fallback warning in stderr, got %q", stderrOut)
}
} else {
if strings.Contains(stderrOut, "falling back to gRPC") {
t.Errorf("expected no fallback warning, got %q", stderrOut)
}
}
})
}
}