fix: resolve 3 test package failures for Windows compatibility
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled

- 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)
This commit is contained in:
User
2026-04-13 01:09:46 +08:00
parent 5ca850700b
commit 146a306343
6 changed files with 53 additions and 22 deletions

View File

@@ -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()

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)