fix: resolve plugin lifecycle dependencies deterministically

This commit is contained in:
2026-07-10 04:03:08 +08:00
parent 0f293640f9
commit a323710a6f
7 changed files with 247 additions and 92 deletions
+8
View File
@@ -33,10 +33,18 @@ func (r *Registry) Register(pluginID string, capabilities []string) error {
r.mu.Lock()
defer r.mu.Unlock()
pending := make(map[string]struct{}, len(capabilities))
for _, name := range capabilities {
if existing, ok := r.capabilities[name]; ok {
return fmt.Errorf("capability %q already registered by plugin %q", name, existing.PluginID)
}
if _, ok := pending[name]; ok {
return fmt.Errorf("capability %q is registered more than once by plugin %q", name, pluginID)
}
pending[name] = struct{}{}
}
for _, name := range capabilities {
r.capabilities[name] = &Entry{
Name: name,
PluginID: pluginID,
+21
View File
@@ -0,0 +1,21 @@
package capability
import "testing"
func TestRegisterDoesNotPartiallyRegisterCapabilitiesOnConflict(t *testing.T) {
registry := NewRegistry()
if err := registry.Register("existing.plugin", []string{"shared.capability"}); err != nil {
t.Fatalf("register existing capability: %v", err)
}
if err := registry.Register("failed.plugin", []string{"new.capability", "shared.capability"}); err == nil {
t.Fatal("Register returned nil for a duplicate capability")
}
if registry.Has("new.capability") {
t.Fatal("Register leaked a capability from the failed registration")
}
entry := registry.Get("shared.capability")
if entry == nil || entry.PluginID != "existing.plugin" {
t.Fatalf("shared capability entry = %#v, want existing.plugin", entry)
}
}