open-code-review/internal/telemetry/events_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

202 lines
5.2 KiB
Go

package telemetry
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"testing"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func setupEnabledTelemetry(t *testing.T) {
t.Helper()
tp := sdktrace.NewTracerProvider(sdktrace.WithResource(resource.Default()))
mp := sdkmetric.NewMeterProvider(sdkmetric.WithResource(resource.Default()))
otel.SetTracerProvider(tp)
otel.SetMeterProvider(mp)
tracerProvider = tp
meterProvider = mp
initialized = true
shutdownFuncs = []func(context.Context) error{
func(ctx context.Context) error { return tp.Shutdown(ctx) },
func(ctx context.Context) error { return mp.Shutdown(ctx) },
}
initMetricsOnce = false
t.Cleanup(func() {
_ = tp.Shutdown(context.Background())
_ = mp.Shutdown(context.Background())
tracerProvider = nil
meterProvider = nil
initialized = false
shutdownFuncs = nil
initMetricsOnce = false
})
}
func captureStderr(t *testing.T, fn func()) string {
t.Helper()
r, w, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
oldStderr := os.Stderr
os.Stderr = w
defer func() { os.Stderr = oldStderr }()
fn()
_ = w.Close()
var buf bytes.Buffer
_, _ = io.Copy(&buf, r)
return buf.String()
}
func TestEvent_Enabled(t *testing.T) {
setupEnabledTelemetry(t)
ctx := context.Background()
Event(ctx, "test.event", attribute.String("key", "value"))
}
func TestEvent_Disabled(t *testing.T) {
initialized = false
shutdownFuncs = nil
defer func() { initialized = false }()
Event(context.Background(), "test.event")
}
func TestEvent_NilCtx(t *testing.T) {
setupEnabledTelemetry(t)
Event(nil, "test.event") //nolint:staticcheck
}
func TestEventf_Enabled(t *testing.T) {
setupEnabledTelemetry(t)
ctx := context.Background()
Eventf(ctx, "test.eventf", "hello world", attribute.Int("count", 5))
}
func TestErrorEvent_Enabled(t *testing.T) {
setupEnabledTelemetry(t)
ctx := context.Background()
ErrorEvent(ctx, "test.error", errors.New("something failed"), attribute.String("detail", "extra"))
}
func TestErrorEvent_NilErr(t *testing.T) {
setupEnabledTelemetry(t)
ctx := context.Background()
ErrorEvent(ctx, "test.error", nil)
}
func TestErrorEvent_NilCtx(t *testing.T) {
setupEnabledTelemetry(t)
ErrorEvent(nil, "test.error", errors.New("fail")) //nolint:staticcheck
}
func TestErrorEvent_Disabled(t *testing.T) {
initialized = false
shutdownFuncs = nil
defer func() { initialized = false }()
ErrorEvent(context.Background(), "test.error", errors.New("fail"))
}
func TestPhaseEvent_Success(t *testing.T) {
setupEnabledTelemetry(t)
ctx := context.Background()
PhaseEvent(ctx, "scan", "main.go", 500*time.Millisecond, nil)
}
func TestPhaseEvent_WithError(t *testing.T) {
setupEnabledTelemetry(t)
ctx := context.Background()
PhaseEvent(ctx, "scan", "main.go", 500*time.Millisecond, errors.New("parse error"))
}
func TestPrintTraceSummary_WithTokenDetails(t *testing.T) {
PrintTraceSummary(5, 10, 1000, 200, 1200, 0, 0, 3*time.Second)
}
func TestPrintTraceSummary_WithCacheTokens(t *testing.T) {
PrintTraceSummary(3, 2, 500, 100, 600, 200, 50, 2*time.Second)
}
func TestPrintTraceSummary_NoTokenDetails(t *testing.T) {
PrintTraceSummary(2, 1, 0, 0, 500, 0, 0, 1*time.Second)
}
func TestPrintToolCallStarted_WithArgs(t *testing.T) {
PrintToolCallStarted("file_read", map[string]any{"path": "main.go"})
}
func TestPrintToolCallStarted_NoArgs(t *testing.T) {
PrintToolCallStarted("list_files", nil)
}
func TestPrintToolCallFinished(t *testing.T) {
PrintToolCallFinished("file_read", 123*time.Millisecond)
}
func TestPrintToolCallError(t *testing.T) {
out := captureStderr(t, func() {
PrintToolCallError("file_read", fmt.Errorf("permission denied"))
})
if !strings.Contains(out, "✘ file_read") {
t.Errorf("expected tool name with X mark, got %q", out)
}
if !strings.Contains(out, "permission denied") {
t.Errorf("expected error message, got %q", out)
}
}
func TestFormatDuration(t *testing.T) {
tests := []struct {
dur time.Duration
want string
}{
{0, "0s"},
{1500 * time.Millisecond, "1.5s"},
{60 * time.Second, "1m0s"},
{123 * time.Millisecond, "123ms"},
{2*time.Minute + 30*time.Second, "2m30s"},
}
for _, tc := range tests {
got := FormatDuration(tc.dur)
if got != tc.want {
t.Errorf("FormatDuration(%v) = %q, want %q", tc.dur, got, tc.want)
}
}
}
func TestSummarizeArgs(t *testing.T) {
tests := []struct {
name string
args map[string]any
want string
}{
{"nil map", nil, ""},
{"empty map", map[string]any{}, ""},
{"path key returns quoted", map[string]any{"path": "foo/bar.go"}, `"foo/bar.go"`},
{"search key returns quoted", map[string]any{"search": "hello"}, `"hello"`},
{"query key returns quoted", map[string]any{"query": "world"}, `"world"`},
{"pattern key returns quoted", map[string]any{"pattern": "*.go"}, `"*.go"`},
{"generic short value", map[string]any{"foo": "bar"}, "foo=bar"},
{"long value skipped", map[string]any{"data": string(make([]byte, 60))}, ""},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := summarizeArgs(tc.args)
if got != tc.want {
t.Errorf("summarizeArgs(%v) = %q, want %q", tc.args, got, tc.want)
}
})
}
}