package plugin import ( "io/fs" "testing" "github.com/gin-gonic/gin" "go.uber.org/fx" "go.uber.org/zap" "mengstack/internal/kernel/tenant" ) func TestSandbox_CheckDatabase(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("test-plugin", Permissions{ Database: []string{"users", "posts"}, }) tests := []struct { plugin string table string wantOK bool }{ {"test-plugin", "users", true}, {"test-plugin", "posts", true}, {"test-plugin", "orders", false}, {"unknown-plugin", "users", false}, } for _, tt := range tests { err := sb.CheckDatabase(tt.plugin, tt.table) if tt.wantOK && err != nil { t.Errorf("CheckDatabase(%q, %q) unexpected error: %v", tt.plugin, tt.table, err) } if !tt.wantOK && err == nil { t.Errorf("CheckDatabase(%q, %q) expected error, got nil", tt.plugin, tt.table) } } } func TestSandbox_CheckDatabaseWildcard(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("all-access", Permissions{ Database: []string{""}, }) if err := sb.CheckDatabase("all-access", "any_table"); err != nil { t.Errorf("wildcard database access should be allowed, got: %v", err) } } func TestSandbox_CheckStorage(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("with-storage", Permissions{Storage: true}) sb.Register("no-storage", Permissions{Storage: false}) if err := sb.CheckStorage("with-storage"); err != nil { t.Errorf("expected storage access allowed, got: %v", err) } if err := sb.CheckStorage("no-storage"); err == nil { t.Error("expected storage access denied") } } func TestSandbox_CheckNetwork(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("net-plugin", Permissions{ Network: []string{"api.example.com"}, }) if err := sb.CheckNetwork("net-plugin", "api.example.com"); err != nil { t.Errorf("expected network access allowed, got: %v", err) } if err := sb.CheckNetwork("net-plugin", "evil.com"); err == nil { t.Error("expected network access denied for unauthorized domain") } } func TestSandbox_CheckEvent(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("event-plugin", Permissions{ Events: []string{"user.created", "user.deleted"}, }) if err := sb.CheckEvent("event-plugin", "user.created"); err != nil { t.Errorf("expected event allowed, got: %v", err) } if err := sb.CheckEvent("event-plugin", "order.created"); err == nil { t.Error("expected event denied for unauthorized event") } } func TestSandbox_CheckEventWildcard(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("wildcard-events", Permissions{ Events: []string{"*"}, }) if err := sb.CheckEvent("wildcard-events", "anything"); err != nil { t.Errorf("wildcard event access should be allowed, got: %v", err) } } func TestSandbox_CheckRoute(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("route-plugin", Permissions{ Routes: []string{"/api/v1/items", "/api/v1/items/*"}, }) if err := sb.CheckRoute("route-plugin", "/api/v1/items"); err != nil { t.Errorf("expected route allowed, got: %v", err) } if err := sb.CheckRoute("route-plugin", "/api/v1/items/123"); err != nil { t.Errorf("expected wildcard route allowed, got: %v", err) } if err := sb.CheckRoute("route-plugin", "/api/v1/users"); err == nil { t.Error("expected route denied for unauthorized path") } } func TestSandbox_CheckAdminPanel(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) sb.Register("admin-plugin", Permissions{AdminPanel: true}) sb.Register("no-admin", Permissions{AdminPanel: false}) if err := sb.CheckAdminPanel("admin-plugin"); err != nil { t.Errorf("expected admin access allowed, got: %v", err) } if err := sb.CheckAdminPanel("no-admin"); err == nil { t.Error("expected admin access denied") } } func TestSandbox_SafeInit_PanicRecovery(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) panicPlugin := &mockPlugin{ name: "panic-plugin", initFn: func() error { panic("something went wrong") }, } err := sb.SafeInit(panicPlugin) if err == nil { t.Error("expected error from panicked init") } } func TestSandbox_SafeInit_Success(t *testing.T) { log := zap.NewNop() sb := NewSandbox(log) okPlugin := &mockPlugin{ name: "ok-plugin", initFn: func() error { return nil }, } if err := sb.SafeInit(okPlugin); err != nil { t.Errorf("unexpected error: %v", err) } } type mockPlugin struct { name string initFn func() error } func (m *mockPlugin) Metadata() Metadata { return Metadata{Name: m.name, Version: "0.0.1", Description: "mock"} } func (m *mockPlugin) Permissions() Permissions { return Permissions{} } func (m *mockPlugin) FxOption() fx.Option { return fx.Options() } func (m *mockPlugin) SetupRoutes(_ *gin.Engine, _ gin.HandlerFunc, _ tenant.Resolver) {} func (m *mockPlugin) Init() error { return m.initFn() } func (m *mockPlugin) MigrationsFS() fs.FS { return nil }