1
0

feat: 区分 server 与 desktop 配置加载入口,取消自动创建配置文件

- config.go 重构:抽取 loadConfig 共享逻辑,新增 LoadServerConfig/LoadDesktopConfig/LoadDesktopConfigAtPath,LoadConfig 保持向后兼容
- setupConfigFile 移除 SafeWriteConfigAs 自动创建逻辑,文件不存在时仅使用默认值
- cmd/desktop 切换为 LoadDesktopConfig,端口/HTTP/浏览器/托盘统一使用 cfg.Server.Port
- cmd/server 显式使用 LoadServerConfig 明确入口语义
- 提取 desktop 可测 helper:desktopListenAddr/desktopURL/desktopPortMenuTitle/desktopConfigErrorMessage
- 新增测试:desktop 忽略 CLI/env/未知参数、配置快照不变、无效配置文件不静默回退、端口 helper 一致性
- README 区分 server/desktop 配置源,移除首次启动自动创建配置文件描述
- 同步 delta specs 到 openspec/specs/ 主规范
This commit is contained in:
2026-05-06 11:59:19 +08:00
parent 598e2acb7e
commit 5513f0c13d
10 changed files with 589 additions and 147 deletions

View File

@@ -120,7 +120,7 @@ log:
assert.Equal(t, "warn", cfg.Log.Level, "YAML value should be used when no CLI/ENV override")
}
func TestLoadConfig_AutoCreate(t *testing.T) {
func TestLoadConfig_NoAutoCreate(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
@@ -132,6 +132,9 @@ func TestLoadConfig_AutoCreate(t *testing.T) {
require.NotNil(t, cfg)
assert.Equal(t, 9826, cfg.Server.Port, "should load with default values")
_, err = os.Stat(configPath)
assert.True(t, os.IsNotExist(err), "config file should not be auto-created")
}
func TestSaveAndLoadConfig(t *testing.T) {
@@ -184,3 +187,124 @@ func TestSaveAndLoadConfig(t *testing.T) {
assert.Equal(t, cfg.Log.MaxAge, loaded.Log.MaxAge)
assert.Equal(t, cfg.Log.Compress, loaded.Log.Compress)
}
func TestLoadDesktopConfig_FileOnly(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
yamlContent := `
server:
port: 8080
log:
level: debug
`
err := os.WriteFile(configPath, []byte(yamlContent), 0o600)
require.NoError(t, err)
cfg, err := config.LoadDesktopConfigAtPath(configPath)
require.NoError(t, err)
assert.Equal(t, 8080, cfg.Server.Port)
assert.Equal(t, "debug", cfg.Log.Level)
}
func TestLoadDesktopConfig_IgnoresCLI(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
err := os.WriteFile(configPath, []byte("server:\n port: 8080\n"), 0o600)
require.NoError(t, err)
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
os.Args = []string{"nex", "--server-port", "9999"}
cfg, err := config.LoadDesktopConfigAtPath(configPath)
require.NoError(t, err)
assert.Equal(t, 8080, cfg.Server.Port, "desktop should ignore CLI args and use config file")
}
func TestLoadDesktopConfig_IgnoresEnv(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
err := os.WriteFile(configPath, []byte("server:\n port: 8080\n"), 0o600)
require.NoError(t, err)
t.Setenv("NEX_SERVER_PORT", "9000")
t.Setenv("NEX_LOG_LEVEL", "debug")
cfg, err := config.LoadDesktopConfigAtPath(configPath)
require.NoError(t, err)
assert.Equal(t, 8080, cfg.Server.Port, "desktop should ignore env vars and use config file")
assert.Equal(t, "info", cfg.Log.Level, "desktop should ignore env vars and use default")
}
func TestLoadDesktopConfig_IgnoresUnknownArgs(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
err := os.WriteFile(configPath, []byte("server:\n port: 8080\n"), 0o600)
require.NoError(t, err)
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
os.Args = []string{"nex", "--unknown-flag", "value", "--another-unknown"}
cfg, err := config.LoadDesktopConfigAtPath(configPath)
require.NoError(t, err, "desktop should not fail on unknown CLI args")
assert.Equal(t, 8080, cfg.Server.Port)
}
func TestLoadDesktopConfig_Snapshot(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
err := os.WriteFile(configPath, []byte("server:\n port: 8080\n"), 0o600)
require.NoError(t, err)
cfg, err := config.LoadDesktopConfigAtPath(configPath)
require.NoError(t, err)
assert.Equal(t, 8080, cfg.Server.Port)
err = os.WriteFile(configPath, []byte("server:\n port: 9999\n"), 0o600)
require.NoError(t, err)
assert.Equal(t, 8080, cfg.Server.Port, "loaded config snapshot should not change when file changes")
cfg2, err := config.LoadDesktopConfigAtPath(configPath)
require.NoError(t, err)
assert.Equal(t, 9999, cfg2.Server.Port, "reload should pick up new config values")
}
func TestLoadDesktopConfig_InvalidFileFails(t *testing.T) {
tests := []struct {
name string
content string
}{
{
name: "invalid yaml",
content: "server:\n port: [\n",
},
{
name: "validation failure",
content: "server:\n port: 70000\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpDir := t.TempDir()
configPath := filepath.Join(tmpDir, "config.yaml")
err := os.WriteFile(configPath, []byte(tt.content), 0o600)
require.NoError(t, err)
_, err = config.LoadDesktopConfigAtPath(configPath)
require.Error(t, err, "desktop should not silently fall back to defaults for invalid config files")
})
}
}