mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-09-05 23:50:29 +08:00
feat(plugins): enhance plugin deletion test and config handling
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user