srs/internal/logger/context_test.go
Winlin 30fc7775a5
Proxy: Modernize internal packages on stdlib and add unit tests. v7.0.145 (#4667)
Modernizes several `internal/*` packages under the Go proxy, replaces
third-party forks with standard-library primitives, and brings the
test suite from near-zero to high coverage across the touched packages.

Package changes

- **`internal/errors`** — Rewrites the `pkg/errors` fork as a thin
wrapper
  over stdlib `errors`. A single `withStack` struct captures stack
  traces via `runtime.Callers`; `fmt.Errorf("%w", ...)` handles all
  message wrapping. Restores `errors.Is`/`As`/`Unwrap` chain traversal
  (silently broken in the fork) and deletes ~190 lines of stack/frame
  formatting. `Is`, `As`, `Unwrap`, and `Join` are re-exported so
  callers need a single import.
- **`internal/logger`** — Swaps stdlib `log.Logger` for `log/slog` JSON
  handlers with UTC timestamps and custom level labels (`verb`, `debug`,
  `warn`, `error`). Hides `withContextID` (no external callers).
- **`internal/sync`** — Converts `Map[K, V]` from a concrete struct to
  an interface with a `NewMap` constructor for testability.
- **`internal/signal`** — Adds `signalNotify` / `osExit` indirections so
  `InstallSignals` and `InstallForceQuit` can be exercised without real
  OS signals or process termination.
- **`internal/utils`** — Drops deprecated `io/ioutil` and the stdlib
  `errors` alias (the internal `errors` package re-exports what's
  needed).
- **`internal/version`** — No code changes; fully covered by new tests.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:25:48 -04:00

83 lines
2.1 KiB
Go

// Copyright (c) 2026 Winlin
//
// SPDX-License-Identifier: MIT
package logger
import (
"context"
"encoding/hex"
"testing"
)
func TestGenerateContextID_LengthAndHex(t *testing.T) {
cid := GenerateContextID()
if len(cid) != 7 {
t.Fatalf("len(cid) = %d, want 7", len(cid))
}
if _, err := hex.DecodeString(cid + "0"); err != nil {
t.Fatalf("cid %q is not hex: %v", cid, err)
}
}
func TestGenerateContextID_Unique(t *testing.T) {
seen := make(map[string]struct{}, 1000)
for i := range 1000 {
cid := GenerateContextID()
if _, dup := seen[cid]; dup {
t.Fatalf("duplicate cid %q at iteration %d", cid, i)
}
seen[cid] = struct{}{}
}
}
func TestWithContext_AttachesCID(t *testing.T) {
ctx := WithContext(context.Background())
cid := ContextID(ctx)
if len(cid) != 7 {
t.Fatalf("ContextID length = %d, want 7", len(cid))
}
}
func TestWithContext_IndependentCIDs(t *testing.T) {
c1 := WithContext(context.Background())
c2 := WithContext(context.Background())
if ContextID(c1) == ContextID(c2) {
t.Fatalf("expected distinct cids, got %q twice", ContextID(c1))
}
}
func TestContextID_Missing(t *testing.T) {
if got := ContextID(context.Background()); got != "" {
t.Fatalf("ContextID on empty ctx = %q, want \"\"", got)
}
}
func TestContextID_WrongTypeReturnsEmpty(t *testing.T) {
ctx := context.WithValue(context.Background(), cidKey, 42)
if got := ContextID(ctx); got != "" {
t.Fatalf("ContextID with int value = %q, want \"\"", got)
}
}
func TestWithContextID_RoundTrip(t *testing.T) {
ctx := withContextID(context.Background(), "abcdef1")
if got := ContextID(ctx); got != "abcdef1" {
t.Fatalf("ContextID = %q, want %q", got, "abcdef1")
}
}
func TestWithContextID_Overwrite(t *testing.T) {
ctx := withContextID(context.Background(), "first00")
ctx = withContextID(ctx, "second1")
if got := ContextID(ctx); got != "second1" {
t.Fatalf("ContextID after overwrite = %q, want %q", got, "second1")
}
}
func TestCIDKey_NotCollidingWithPlainString(t *testing.T) {
ctx := context.WithValue(context.Background(), string(cidKey), "plain")
if got := ContextID(ctx); got != "" {
t.Fatalf("ContextID leaked through string key = %q, want \"\"", got)
}
}