Files
lijiaoqiao/supply-api/internal/middleware/tracing_test.go
Your Name 8ac23bf7d4 test: improve coverage and fix sanitizer bug
- Fix MaskMap to properly handle []string sensitive fields
- Add missing slice handling in sanitizer
- Add comprehensive tests for GetMetrics and CreateEventsBatch
- Improve audit/handler coverage from 49.8% to 68.8%
- Fix test expectations to match actual sanitizer behavior
- All tests pass
2026-04-08 07:44:58 +08:00

343 lines
8.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"context"
"net/http"
"net/http/httptest"
"testing"
)
// TestP106_TraceContextCreation 创建追踪上下文
func TestP106_TraceContextCreation(t *testing.T) {
tc := NewTraceContext()
if tc.TraceID == "" {
t.Error("TraceID should not be empty")
}
if tc.SpanID == "" {
t.Error("SpanID should not be empty")
}
if len(tc.TraceID) != 32 {
t.Errorf("TraceID should be 32 characters, got %d", len(tc.TraceID))
}
if len(tc.SpanID) != 16 {
t.Errorf("SpanID should be 16 characters, got %d", len(tc.SpanID))
}
t.Logf("P1-06: TraceID=%s, SpanID=%s", tc.TraceID, tc.SpanID)
}
// TestP106_ParseTraceParent 解析traceparent header
func TestP106_ParseTraceParent(t *testing.T) {
testCases := []struct {
name string
traceParent string
wantErr bool
}{
{
name: "valid traceparent",
traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01",
wantErr: false,
},
{
name: "empty traceparent",
traceParent: "",
wantErr: true,
},
{
name: "invalid version",
traceParent: "01-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01",
wantErr: true,
},
{
name: "too short",
traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331",
wantErr: true,
},
{
name: "invalid trace-flags",
traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-02",
wantErr: true,
},
{
name: "not-sampled flag valid",
traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-00",
wantErr: false,
},
{
name: "trace-id too short",
traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b716920333-01",
wantErr: true,
},
{
name: "span-id too short",
traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b71692033-01",
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
parsed, err := ParseTraceParent(tc.traceParent)
if tc.wantErr {
if err == nil {
t.Error("expected error but got nil")
}
} else {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if parsed == nil {
t.Error("parsed should not be nil")
}
}
})
}
t.Log("P1-06: traceparent解析验证通过")
}
// TestP106_FormatTraceParent 格式化traceparent header
func TestP106_FormatTraceParent(t *testing.T) {
tc := &TraceContext{
TraceID: "0af7651916cd43dd8448eb211c80319c",
SpanID: "b7ad6b7169203331",
TraceFlags: TraceFlagSampled,
}
formatted := tc.FormatTraceParent()
expected := "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
if formatted != expected {
t.Errorf("expected %s, got %s", expected, formatted)
}
t.Log("P1-06: traceparent格式化验证通过")
}
// TestP106_ChildSpan 创建子Span
func TestP106_ChildSpan(t *testing.T) {
parent := &TraceContext{
TraceID: "0af7651916cd43dd8448eb211c80319c",
SpanID: "b7ad6b7169203331",
TraceFlags: TraceFlagSampled,
}
child := parent.NewChildSpanContext()
// TraceID应该相同
if child.TraceID != parent.TraceID {
t.Error("child TraceID should inherit from parent")
}
// SpanID应该不同
if child.SpanID == parent.SpanID {
t.Error("child SpanID should be different from parent")
}
// TraceFlags应该相同
if child.TraceFlags != parent.TraceFlags {
t.Error("child TraceFlags should inherit from parent")
}
t.Log("P1-06: 子Span创建验证通过")
}
// TestP106_ContextPropagation Context传播
func TestP106_ContextPropagation(t *testing.T) {
tc := NewTraceContext()
ctx := context.Background()
// 设置到context
ctx = WithTraceContext(ctx, tc)
// 从context获取
retrieved, ok := GetTraceContext(ctx)
if !ok {
t.Error("should be able to retrieve TraceContext from context")
}
if retrieved.TraceID != tc.TraceID {
t.Error("retrieved TraceID should match")
}
t.Log("P1-06: Context传播验证通过")
}
// TestP106_IsSampled 采样标志检查
func TestP106_IsSampled(t *testing.T) {
sampled := &TraceContext{
TraceID: "0af7651916cd43dd8448eb211c80319c",
SpanID: "b7ad6b7169203331",
TraceFlags: TraceFlagSampled,
}
notSampled := &TraceContext{
TraceID: "0af7651916cd43dd8448eb211c80319c",
SpanID: "b7ad6b7169203331",
TraceFlags: TraceFlagNotSampled,
}
if !sampled.IsSampled() {
t.Error("sampled context should return true")
}
if notSampled.IsSampled() {
t.Error("not sampled context should return false")
}
t.Log("P1-06: 采样标志检查验证通过")
}
// TestP106_Summary 测试总结
func TestP106_Summary(t *testing.T) {
t.Log("=== P1-006 分布式追踪集成测试总结 ===")
t.Log("问题: 文档提到request_id和trace_id但未定义与OpenTelemetry/Jaeger集成")
t.Log("")
t.Log("修复方案:")
t.Log(" - W3C Trace Context标准实现")
t.Log(" - traceparent header解析和格式化")
t.Log(" - 支持traceparent/tracestate header")
t.Log(" - 与现有request_id映射")
}
// ==================== Additional TraceContext Tests ====================
func TestTraceContext_LogFields(t *testing.T) {
tc := &TraceContext{
TraceID: "test-trace-id-12345678901234",
SpanID: "test-span-id-1",
TraceFlags: TraceFlagSampled,
}
fields := tc.LogFields()
if fields["trace_id"] != "test-trace-id-12345678901234" {
t.Errorf("expected trace_id 'test-trace-id-12345678901234', got '%s'", fields["trace_id"])
}
if fields["span_id"] != "test-span-id-1" {
t.Errorf("expected span_id 'test-span-id-1', got '%s'", fields["span_id"])
}
}
// ==================== TracingMiddleware Tests ====================
func TestTracingMiddleware_WithValidTraceParent(t *testing.T) {
nextCalled := false
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextCalled = true
// Verify trace context was injected
tc, ok := GetTraceContext(r.Context())
if !ok {
t.Error("expected trace context in request")
}
if tc == nil {
t.Error("expected non-nil trace context")
}
})
handler := TracingMiddleware(nextHandler)
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("traceparent", "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01")
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if !nextCalled {
t.Error("next handler should be called")
}
}
func TestTracingMiddleware_WithInvalidTraceParent(t *testing.T) {
nextCalled := false
var capturedCtx context.Context
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextCalled = true
capturedCtx = r.Context()
})
handler := TracingMiddleware(nextHandler)
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("traceparent", "invalid-traceparent")
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if !nextCalled {
t.Error("next handler should be called even with invalid traceparent")
}
// Should generate new trace context
tc, ok := GetTraceContext(capturedCtx)
if !ok {
t.Error("expected trace context to be generated")
}
if tc.TraceID == "" {
t.Error("expected non-empty TraceID")
}
if tc.SpanID == "" {
t.Error("expected non-empty SpanID")
}
}
func TestTracingMiddleware_NoTraceParent(t *testing.T) {
nextCalled := false
var capturedCtx context.Context
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextCalled = true
capturedCtx = r.Context()
})
handler := TracingMiddleware(nextHandler)
req := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if !nextCalled {
t.Error("next handler should be called")
}
// Should generate new trace context
tc, ok := GetTraceContext(capturedCtx)
if !ok {
t.Error("expected trace context to be generated")
}
if tc.TraceID == "" {
t.Error("expected non-empty TraceID")
}
}
func TestTracingMiddleware_PreservesExistingContext(t *testing.T) {
nextCalled := false
var capturedCtx context.Context
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
nextCalled = true
capturedCtx = r.Context()
})
handler := TracingMiddleware(nextHandler)
// Create request with existing context
req := httptest.NewRequest("GET", "/", nil)
req = req.WithContext(context.WithValue(context.Background(), "existing-key", "existing-value"))
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if !nextCalled {
t.Error("next handler should be called")
}
// Verify existing context value is preserved
if capturedCtx.Value("existing-key") != "existing-value" {
t.Error("expected existing context value to be preserved")
}
}