- config: add optional configPaths parameter to load() for test isolation (tests now use t.TempDir() to avoid interference from D:\app\data) - handler: fix stubAccountRepoForHandler.ListByPlatform to return accounts (was returning nil, nil causing "no available accounts" errors) - logger: fix Sync() blocking on Windows pipes by closing write end first (also add Reset() function to close lumberjack file handles for cleanup)
167 lines
4.3 KiB
Go
167 lines
4.3 KiB
Go
package logger
|
|
|
|
import (
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestInferStdLogLevel(t *testing.T) {
|
|
cases := []struct {
|
|
msg string
|
|
want Level
|
|
}{
|
|
{msg: "Warning: queue full", want: LevelWarn},
|
|
{msg: "Forward request failed: timeout", want: LevelError},
|
|
{msg: "[ERROR] upstream unavailable", want: LevelError},
|
|
{msg: "[OpenAI WS Mode] reconnect_retry account_id=22 retry=1 max_retries=5", want: LevelInfo},
|
|
{msg: "service started", want: LevelInfo},
|
|
{msg: "debug: cache miss", want: LevelDebug},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
got := inferStdLogLevel(tc.msg)
|
|
if got != tc.want {
|
|
t.Fatalf("inferStdLogLevel(%q)=%v want=%v", tc.msg, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalizeStdLogMessage(t *testing.T) {
|
|
raw := " [TokenRefresh] cycle complete \n total=1 failed=0 \n"
|
|
got := normalizeStdLogMessage(raw)
|
|
want := "[TokenRefresh] cycle complete total=1 failed=0"
|
|
if got != want {
|
|
t.Fatalf("normalizeStdLogMessage()=%q want=%q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestStdLogBridgeRoutesLevels(t *testing.T) {
|
|
origStdout := os.Stdout
|
|
origStderr := os.Stderr
|
|
stdoutR, stdoutW, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatalf("create stdout pipe: %v", err)
|
|
}
|
|
stderrR, stderrW, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatalf("create stderr pipe: %v", err)
|
|
}
|
|
os.Stdout = stdoutW
|
|
os.Stderr = stderrW
|
|
t.Cleanup(func() {
|
|
os.Stdout = origStdout
|
|
os.Stderr = origStderr
|
|
_ = stdoutR.Close()
|
|
_ = stdoutW.Close()
|
|
_ = stderrR.Close()
|
|
_ = stderrW.Close()
|
|
})
|
|
|
|
if err := Init(InitOptions{
|
|
Level: "debug",
|
|
Format: "json",
|
|
ServiceName: "sub2api",
|
|
Environment: "test",
|
|
Output: OutputOptions{
|
|
ToStdout: true,
|
|
ToFile: false,
|
|
},
|
|
Sampling: SamplingOptions{Enabled: false},
|
|
}); err != nil {
|
|
t.Fatalf("Init() error: %v", err)
|
|
}
|
|
|
|
log.Printf("service started")
|
|
log.Printf("Warning: queue full")
|
|
log.Printf("Forward request failed: timeout")
|
|
_ = stdoutW.Close()
|
|
_ = stderrW.Close()
|
|
Sync()
|
|
|
|
stdoutBytes, _ := io.ReadAll(stdoutR)
|
|
stderrBytes, _ := io.ReadAll(stderrR)
|
|
stdoutText := string(stdoutBytes)
|
|
stderrText := string(stderrBytes)
|
|
|
|
if !strings.Contains(stdoutText, "service started") {
|
|
t.Fatalf("stdout missing info log: %s", stdoutText)
|
|
}
|
|
if !strings.Contains(stderrText, "Warning: queue full") {
|
|
t.Fatalf("stderr missing warn log: %s", stderrText)
|
|
}
|
|
if !strings.Contains(stderrText, "Forward request failed: timeout") {
|
|
t.Fatalf("stderr missing error log: %s", stderrText)
|
|
}
|
|
if !strings.Contains(stderrText, "\"legacy_stdlog\":true") {
|
|
t.Fatalf("stderr missing legacy_stdlog marker: %s", stderrText)
|
|
}
|
|
}
|
|
|
|
func TestLegacyPrintfRoutesLevels(t *testing.T) {
|
|
origStdout := os.Stdout
|
|
origStderr := os.Stderr
|
|
stdoutR, stdoutW, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatalf("create stdout pipe: %v", err)
|
|
}
|
|
stderrR, stderrW, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatalf("create stderr pipe: %v", err)
|
|
}
|
|
os.Stdout = stdoutW
|
|
os.Stderr = stderrW
|
|
t.Cleanup(func() {
|
|
os.Stdout = origStdout
|
|
os.Stderr = origStderr
|
|
_ = stdoutR.Close()
|
|
_ = stdoutW.Close()
|
|
_ = stderrR.Close()
|
|
_ = stderrW.Close()
|
|
})
|
|
|
|
if err := Init(InitOptions{
|
|
Level: "debug",
|
|
Format: "json",
|
|
ServiceName: "sub2api",
|
|
Environment: "test",
|
|
Output: OutputOptions{
|
|
ToStdout: true,
|
|
ToFile: false,
|
|
},
|
|
Sampling: SamplingOptions{Enabled: false},
|
|
}); err != nil {
|
|
t.Fatalf("Init() error: %v", err)
|
|
}
|
|
|
|
LegacyPrintf("service.test", "request started")
|
|
LegacyPrintf("service.test", "Warning: queue full")
|
|
LegacyPrintf("service.test", "forward failed: timeout")
|
|
_ = stdoutW.Close()
|
|
_ = stderrW.Close()
|
|
Sync()
|
|
|
|
stdoutBytes, _ := io.ReadAll(stdoutR)
|
|
stderrBytes, _ := io.ReadAll(stderrR)
|
|
stdoutText := string(stdoutBytes)
|
|
stderrText := string(stderrBytes)
|
|
|
|
if !strings.Contains(stdoutText, "request started") {
|
|
t.Fatalf("stdout missing info log: %s", stdoutText)
|
|
}
|
|
if !strings.Contains(stderrText, "Warning: queue full") {
|
|
t.Fatalf("stderr missing warn log: %s", stderrText)
|
|
}
|
|
if !strings.Contains(stderrText, "forward failed: timeout") {
|
|
t.Fatalf("stderr missing error log: %s", stderrText)
|
|
}
|
|
if !strings.Contains(stderrText, "\"legacy_printf\":true") {
|
|
t.Fatalf("stderr missing legacy_printf marker: %s", stderrText)
|
|
}
|
|
if !strings.Contains(stderrText, "\"component\":\"service.test\"") {
|
|
t.Fatalf("stderr missing component field: %s", stderrText)
|
|
}
|
|
}
|