feat(plugins): enhance plugin deletion test and config handling

This commit is contained in:
hkfires
2026-06-28 22:14:36 +08:00
parent 884fc3ce94
commit 60eae92bcd
2 changed files with 56 additions and 3 deletions

View File

@@ -526,16 +526,21 @@ func TestDeletePluginRemovesDiscoveredFileAndConfig(t *testing.T) {
t.Parallel()
pluginsDir := writeManagementPluginFile(t, "sample")
configPath := filepath.Join(t.TempDir(), "config.yaml")
if errWrite := os.WriteFile(configPath, []byte("plugins:\n configs:\n sample:\n enabled: true\n mode: safe\n keep:\n enabled: true\n mode: retained\n"), 0o600); errWrite != nil {
t.Fatalf("failed to write test config: %v", errWrite)
}
h := &Handler{
cfg: &config.Config{
Plugins: config.PluginsConfig{
Dir: pluginsDir,
Configs: map[string]config.PluginInstanceConfig{
"sample": pluginConfigFromYAML(t, "enabled: true\nmode: safe\n"),
"keep": pluginConfigFromYAML(t, "enabled: true\nmode: retained\n"),
},
},
},
configFilePath: writeTestConfigFile(t),
configFilePath: configPath,
}
reloads := make(chan *config.Config, 1)
releaseReload := make(chan struct{})
@@ -577,6 +582,20 @@ func TestDeletePluginRemovesDiscoveredFileAndConfig(t *testing.T) {
if _, ok := h.cfg.Plugins.Configs["sample"]; ok {
t.Fatal("plugin config still exists after delete")
}
if _, ok := h.cfg.Plugins.Configs["keep"]; !ok {
t.Fatal("retained plugin config was removed")
}
data, errReadConfig := os.ReadFile(configPath)
if errReadConfig != nil {
t.Fatalf("failed to read saved config: %v", errReadConfig)
}
text := string(data)
if strings.Contains(text, "sample:") || strings.Contains(text, "mode: safe") {
t.Fatalf("saved config still contains removed plugin:\n%s", text)
}
if !strings.Contains(text, "keep:") || !strings.Contains(text, "mode: retained") {
t.Fatalf("saved config lost retained plugin:\n%s", text)
}
if _, errStat := os.Stat(path); !os.IsNotExist(errStat) {
t.Fatalf("plugin file stat error = %v, want not exist", errStat)
}

View File

@@ -1181,6 +1181,7 @@ func SaveConfigPreserveComments(configFile string, cfg *Config) error {
pruneMappingToGeneratedKeys(original.Content[0], generated.Content[0], "oauth-excluded-models")
pruneMappingToGeneratedKeys(original.Content[0], generated.Content[0], "oauth-model-alias")
pruneMappingToGeneratedKeys(original.Content[0], generated.Content[0], "plugins", "configs")
// Merge generated into original in-place, preserving comments/order of existing nodes.
mergeMappingPreserve(original.Content[0], generated.Content[0])
@@ -1762,8 +1763,41 @@ func removeMapKey(mapNode *yaml.Node, key string) {
}
}
func pruneMappingToGeneratedKeys(dstRoot, srcRoot *yaml.Node, key string) {
if key == "" || dstRoot == nil || srcRoot == nil {
func pruneMappingToGeneratedKeys(dstRoot, srcRoot *yaml.Node, keyPath ...string) {
if len(keyPath) == 0 || dstRoot == nil || srcRoot == nil {
return
}
if len(keyPath) > 1 {
dstParent := dstRoot
srcParent := srcRoot
for _, key := range keyPath[:len(keyPath)-1] {
if key == "" || dstParent == nil || dstParent.Kind != yaml.MappingNode {
return
}
dstIdx := findMapKeyIndex(dstParent, key)
if dstIdx < 0 || dstIdx+1 >= len(dstParent.Content) {
return
}
dstParent = dstParent.Content[dstIdx+1]
if srcParent != nil && srcParent.Kind == yaml.MappingNode {
srcIdx := findMapKeyIndex(srcParent, key)
if srcIdx >= 0 && srcIdx+1 < len(srcParent.Content) {
srcParent = srcParent.Content[srcIdx+1]
} else {
srcParent = nil
}
}
}
if srcParent == nil || srcParent.Kind != yaml.MappingNode {
removeMapKey(dstParent, keyPath[len(keyPath)-1])
return
}
pruneMappingToGeneratedKeys(dstParent, srcParent, keyPath[len(keyPath)-1])
return
}
key := keyPath[0]
if key == "" {
return
}
if dstRoot.Kind != yaml.MappingNode || srcRoot.Kind != yaml.MappingNode {