From 146a306343304d59a844d72ca69cac6819f29614 Mon Sep 17 00:00:00 2001 From: User Date: Mon, 13 Apr 2026 01:09:46 +0800 Subject: [PATCH] fix: resolve 3 test package failures for Windows compatibility - 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) --- backend/internal/config/config.go | 32 +++++++++++-------- backend/internal/config/config_test.go | 4 +-- .../handler/sora_client_handler_test.go | 2 +- backend/internal/pkg/logger/logger.go | 23 +++++++++++++ backend/internal/pkg/logger/logger_test.go | 6 ++-- .../internal/pkg/logger/stdlog_bridge_test.go | 8 ++--- 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 2e7397ae..308dc6b0 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -976,23 +976,29 @@ func LoadForBootstrap() (*Config, error) { return load(true) } -func load(allowMissingJWTSecret bool) (*Config, error) { +func load(allowMissingJWTSecret bool, configPaths ...string) (*Config, error) { viper.SetConfigName("config") viper.SetConfigType("yaml") - // Add config paths in priority order - // 1. DATA_DIR environment variable (highest priority) - if dataDir := os.Getenv("DATA_DIR"); dataDir != "" { - viper.AddConfigPath(dataDir) + if len(configPaths) > 0 { + for _, p := range configPaths { + viper.AddConfigPath(p) + } + } else { + // Add config paths in priority order + // 1. DATA_DIR environment variable (highest priority) + if dataDir := os.Getenv("DATA_DIR"); dataDir != "" { + viper.AddConfigPath(dataDir) + } + // 2. Docker data directory + viper.AddConfigPath("/app/data") + // 3. Current directory + viper.AddConfigPath(".") + // 4. Config subdirectory + viper.AddConfigPath("./config") + // 5. System config directory + viper.AddConfigPath("/etc/sub2api") } - // 2. Docker data directory - viper.AddConfigPath("/app/data") - // 3. Current directory - viper.AddConfigPath(".") - // 4. Config subdirectory - viper.AddConfigPath("./config") - // 5. System config directory - viper.AddConfigPath("/etc/sub2api") // 环境变量支持 viper.AutomaticEnv() diff --git a/backend/internal/config/config_test.go b/backend/internal/config/config_test.go index abb76549..1c4f3311 100644 --- a/backend/internal/config/config_test.go +++ b/backend/internal/config/config_test.go @@ -19,7 +19,7 @@ func TestLoadForBootstrapAllowsMissingJWTSecret(t *testing.T) { viper.Reset() t.Setenv("JWT_SECRET", "") - cfg, err := LoadForBootstrap() + cfg, err := load(true, t.TempDir()) if err != nil { t.Fatalf("LoadForBootstrap() error: %v", err) } @@ -291,7 +291,7 @@ func TestLoadJWTAccessTokenExpireMinutesFromEnv(t *testing.T) { func TestLoadDefaultDatabaseSSLMode(t *testing.T) { resetViperWithJWTSecret(t) - cfg, err := Load() + cfg, err := load(false, t.TempDir()) if err != nil { t.Fatalf("Load() error: %v", err) } diff --git a/backend/internal/handler/sora_client_handler_test.go b/backend/internal/handler/sora_client_handler_test.go index 2d10875a..bc84ed52 100644 --- a/backend/internal/handler/sora_client_handler_test.go +++ b/backend/internal/handler/sora_client_handler_test.go @@ -2082,7 +2082,7 @@ func (r *stubAccountRepoForHandler) ListActive(context.Context) ([]service.Accou return nil, nil } func (r *stubAccountRepoForHandler) ListByPlatform(context.Context, string) ([]service.Account, error) { - return nil, nil + return r.accounts, nil } func (r *stubAccountRepoForHandler) UpdateLastUsed(context.Context, int64) error { return nil } func (r *stubAccountRepoForHandler) BatchUpdateLastUsed(context.Context, map[int64]time.Time) error { diff --git a/backend/internal/pkg/logger/logger.go b/backend/internal/pkg/logger/logger.go index 3fca706e..fd89121d 100644 --- a/backend/internal/pkg/logger/logger.go +++ b/backend/internal/pkg/logger/logger.go @@ -50,6 +50,7 @@ var ( currentSink atomic.Value // sinkState stdLogUndo func() bootstrapOnce sync.Once + fileCloser func() error // tracks the lumberjack closer for Reset() ) type sinkState struct { @@ -205,6 +206,27 @@ func Sync() { } } +// Reset clears the global logger state. Used for test cleanup. +func Reset() { + mu.Lock() + defer mu.Unlock() + if fileCloser != nil { + _ = fileCloser() + fileCloser = nil + } + global.Store(zap.NewNop()) + sugar.Store(zap.NewNop().Sugar()) + atomicLevel = zap.NewAtomicLevel() + initOptions = InitOptions{} + if stdLogUndo != nil { + stdLogUndo() + stdLogUndo = nil + } + log.SetFlags(0) + log.SetPrefix("") + log.SetOutput(os.Stderr) +} + func bridgeStdLogLocked() { if stdLogUndo != nil { stdLogUndo() @@ -334,6 +356,7 @@ func buildFileCore(enc zapcore.Encoder, atomic zap.AtomicLevel, options InitOpti Compress: options.Rotation.Compress, LocalTime: options.Rotation.LocalTime, } + fileCloser = lj.Close return zapcore.NewCore(enc, zapcore.AddSync(lj), atomic), filePath, nil } diff --git a/backend/internal/pkg/logger/logger_test.go b/backend/internal/pkg/logger/logger_test.go index 74aae061..ffec3326 100644 --- a/backend/internal/pkg/logger/logger_test.go +++ b/backend/internal/pkg/logger/logger_test.go @@ -32,6 +32,7 @@ func TestInit_DualOutput(t *testing.T) { _ = stderrR.Close() _ = stdoutW.Close() _ = stderrW.Close() + Reset() }) err = Init(InitOptions{ @@ -57,10 +58,11 @@ func TestInit_DualOutput(t *testing.T) { L().Info("dual-output-info") L().Warn("dual-output-warn") - Sync() _ = stdoutW.Close() _ = stderrW.Close() + Sync() + stdoutBytes, _ := io.ReadAll(stdoutR) stderrBytes, _ := io.ReadAll(stderrR) stdoutText := string(stdoutBytes) @@ -166,8 +168,8 @@ func TestInit_CallerShouldPointToCallsite(t *testing.T) { } L().Info("caller-check") - Sync() _ = stdoutW.Close() + Sync() logBytes, _ := io.ReadAll(stdoutR) var line string diff --git a/backend/internal/pkg/logger/stdlog_bridge_test.go b/backend/internal/pkg/logger/stdlog_bridge_test.go index 4482a2ec..b9370a90 100644 --- a/backend/internal/pkg/logger/stdlog_bridge_test.go +++ b/backend/internal/pkg/logger/stdlog_bridge_test.go @@ -77,10 +77,10 @@ func TestStdLogBridgeRoutesLevels(t *testing.T) { log.Printf("service started") log.Printf("Warning: queue full") log.Printf("Forward request failed: timeout") - Sync() - _ = stdoutW.Close() _ = stderrW.Close() + Sync() + stdoutBytes, _ := io.ReadAll(stdoutR) stderrBytes, _ := io.ReadAll(stderrR) stdoutText := string(stdoutBytes) @@ -139,10 +139,10 @@ func TestLegacyPrintfRoutesLevels(t *testing.T) { LegacyPrintf("service.test", "request started") LegacyPrintf("service.test", "Warning: queue full") LegacyPrintf("service.test", "forward failed: timeout") - Sync() - _ = stdoutW.Close() _ = stderrW.Close() + Sync() + stdoutBytes, _ := io.ReadAll(stdoutR) stderrBytes, _ := io.ReadAll(stderrR) stdoutText := string(stdoutBytes)