feat(plugin-config): update default plugin Enabled behavior to false and expand test coverage

- Changed default plugin `Enabled` state from `true` to `false` across configurations, runtime logic, and YAML defaults.
- Added helper function `enabledPluginConfigs` for generating plugin configs with `Enabled` set explicitly.
- Expanded unit tests in `pluginhost`, `config`, and `management` to validate behavior changes for disabled plugins, default settings, and skipped load scenarios.
This commit is contained in:
Luis Pater
2026-06-17 03:46:30 +08:00
parent 125c092866
commit 8d2c00c107
8 changed files with 72 additions and 16 deletions
@@ -548,7 +548,7 @@ func pluginLocalStatuses(pluginsEnabled bool, pluginsDir string, configs map[str
status.Registered = true
status.InstalledVersion = strings.TrimSpace(info.Metadata.Version)
if _, configured := configs[info.ID]; !configured && !status.Enabled {
status.Enabled = true
status.Enabled = false
}
statuses[info.ID] = status
}
+2 -6
View File
@@ -90,7 +90,7 @@ func (h *Handler) ListPlugins(c *gin.Context) {
entries[file.ID] = pluginListEntry{
ID: htmlsanitize.String(file.ID),
Path: htmlsanitize.String(file.Path),
Enabled: true,
Enabled: false,
ConfigFields: []pluginConfigFieldInfo{},
Menus: []pluginMenuInfo{},
}
@@ -118,10 +118,6 @@ func (h *Handler) ListPlugins(c *gin.Context) {
entry.ConfigFields = pluginConfigFields(info.Metadata.ConfigFields)
entry.Menus = pluginMenus(info.Menus)
entry.Metadata = pluginMetadata(info.Metadata)
_, configured := configs[info.ID]
if !configured && !entry.Enabled {
entry.Enabled = true
}
entries[info.ID] = entry
}
}
@@ -397,7 +393,7 @@ func normalizedPluginsDir(dir string) string {
func pluginInstanceEnabled(item config.PluginInstanceConfig) bool {
if item.Enabled == nil {
return true
return false
}
return *item.Enabled
}
@@ -158,7 +158,7 @@ func TestListPluginsIncludesScannedAndConfiguredPlugins(t *testing.T) {
t.Fatalf("unregistered plugin entry has runtime fields: %#v", item)
}
}
if got, ok := entries["scanned"]; !ok || got.Configured || !got.Enabled || got.EffectiveEnabled || got.Path == "" {
if got, ok := entries["scanned"]; !ok || got.Configured || got.Enabled || got.EffectiveEnabled || got.Path == "" {
t.Fatalf("scanned entry = %#v, exists=%v", got, ok)
}
if got, ok := entries["configured-only"]; !ok || !got.Configured || got.Enabled || got.EffectiveEnabled || got.Path != "" {
+2 -2
View File
@@ -172,7 +172,7 @@ type PluginsConfig struct {
// PluginInstanceConfig stores host-owned plugin settings and the original plugin YAML subtree.
type PluginInstanceConfig struct {
// Enabled toggles this plugin instance. Nil is normalized to true during YAML parsing.
// Enabled toggles this plugin instance. Nil is normalized to false during YAML parsing.
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
// Priority controls plugin startup and routing order.
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
@@ -187,7 +187,7 @@ func (c *PluginInstanceConfig) UnmarshalYAML(value *yaml.Node) error {
}
c.Priority = 0
defaultEnabled := true
defaultEnabled := false
c.Enabled = &defaultEnabled
if value == nil || value.Kind == 0 {
+3 -3
View File
@@ -66,10 +66,10 @@ plugins:
t.Fatal("Plugins.Configs[\"sample\"] missing")
}
if plugin.Enabled == nil {
t.Fatal("Plugin.Enabled = nil, want true pointer")
t.Fatal("Plugin.Enabled = nil, want false pointer")
}
if !*plugin.Enabled {
t.Fatal("Plugin.Enabled = false, want true")
if *plugin.Enabled {
t.Fatal("Plugin.Enabled = true, want false")
}
if plugin.Priority != 0 {
t.Fatalf("Plugin.Priority = %d, want 0", plugin.Priority)
+3 -3
View File
@@ -10,7 +10,7 @@ import (
"gopkg.in/yaml.v3"
)
var defaultRuntimeConfigYAML = []byte("enabled: true\npriority: 0\n")
var defaultRuntimeConfigYAML = []byte("enabled: false\npriority: 0\n")
type runtimeConfig struct {
Enabled bool
@@ -48,7 +48,7 @@ func runtimeConfigFromConfig(cfg *config.Config) runtimeConfig {
for _, id := range ids {
item := cfg.Plugins.Configs[id]
enabled := true
enabled := false
if item.Enabled != nil {
enabled = *item.Enabled
}
@@ -66,7 +66,7 @@ func runtimeConfigFromConfig(cfg *config.Config) runtimeConfig {
func defaultRuntimeItemConfig(id string) runtimeItemConfig {
return runtimeItemConfig{
ID: id,
Enabled: true,
Enabled: false,
Priority: 0,
ConfigYAML: append([]byte(nil), defaultRuntimeConfigYAML...),
}
+16
View File
@@ -33,3 +33,19 @@ func TestRuntimeConfigYAMLAddsHostDefaultsToRawPluginConfig(t *testing.T) {
}
}
}
func TestRuntimeConfigYAMLDefaultsEnabledFalse(t *testing.T) {
item := config.PluginInstanceConfig{
Priority: 3,
}
got := string(runtimeConfigYAML(item, false))
for _, want := range []string{
"enabled: false",
"priority: 3",
} {
if !strings.Contains(got, want) {
t.Fatalf("runtimeConfigYAML() missing %q in:\n%s", want, got)
}
}
}
+44
View File
@@ -16,6 +16,15 @@ import (
"github.com/tidwall/gjson"
)
func enabledPluginConfigs(ids ...string) map[string]config.PluginInstanceConfig {
enabled := true
configs := make(map[string]config.PluginInstanceConfig, len(ids))
for _, id := range ids {
configs[id] = config.PluginInstanceConfig{Enabled: &enabled}
}
return configs
}
func TestHostApplyConfig_DisabledGlobalSkipsSnapshot(t *testing.T) {
loader := newTestSymbolLoader()
h := NewForTest(loader)
@@ -67,6 +76,30 @@ func TestHostApplyConfig_DisabledPluginSkipsCapability(t *testing.T) {
}
}
func TestHostApplyConfig_DefaultDisabledPluginSkipsLoad(t *testing.T) {
loader := newTestSymbolLoader()
plugin := &testPlugin{
registerResult: validTestPlugin("alpha"),
reconfigureResult: validTestPlugin("alpha"),
}
loader.lookups["alpha"] = newTestSymbolLookup(plugin)
h := NewForTest(loader)
h.ApplyConfig(context.Background(), &config.Config{
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
},
})
if plugin.registerCalls != 0 || loader.openCalls != 0 {
t.Fatalf("calls = register %d open %d, want 0", plugin.registerCalls, loader.openCalls)
}
if len(h.Snapshot().records) != 0 {
t.Fatalf("Snapshot records = %d, want 0", len(h.Snapshot().records))
}
}
func TestPluginLoadedTracksLoadedPluginAfterDisabled(t *testing.T) {
disabled := false
loader := newTestSymbolLoader()
@@ -83,6 +116,7 @@ func TestPluginLoadedTracksLoadedPluginAfterDisabled(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: pluginsDir,
Configs: enabledPluginConfigs("alpha"),
},
})
@@ -136,6 +170,7 @@ func TestHostUnloadPluginTargetsOnlyRequestedPlugin(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha", "bravo"),
Configs: enabledPluginConfigs("alpha", "bravo"),
},
}
@@ -191,6 +226,7 @@ func TestHostApplyConfigRegistersPluginThinkingApplier(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
}
t.Cleanup(func() {
@@ -240,6 +276,7 @@ func TestHostApplyConfigRegistersInterceptorOnlyPlugin(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
})
@@ -282,6 +319,7 @@ func TestHostApplyConfigDispatchesInterceptorRPCMethods(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
})
@@ -488,6 +526,7 @@ func TestHostApplyConfig_ReconfigureCalledOnReload(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
}
@@ -529,6 +568,7 @@ func TestRegisteredPluginsIncludesMetadataAndOAuthCapability(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
})
@@ -589,6 +629,7 @@ func TestHostApplyConfig_PanicFusesPluginForProcessLifetime(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
}
@@ -674,6 +715,7 @@ func TestHostApplyConfigSerializesLifecycleCalls(t *testing.T) {
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
}
@@ -896,6 +938,7 @@ func newBlockingOpenHost(t *testing.T) (*Host, *config.Config, <-chan struct{},
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
}
return h, cfg, openStarted, releaseOpen
@@ -928,6 +971,7 @@ func newBlockingRegisterHost(t *testing.T) (*Host, *config.Config, <-chan struct
Plugins: config.PluginsConfig{
Enabled: true,
Dir: makePluginDir(t, "alpha"),
Configs: enabledPluginConfigs("alpha"),
},
}
return h, cfg, registerStarted, releaseRegister