- Fix remaining 187 pkg/ files referencing core/cli → core/go - Move SDK library code from internal/cmd/sdk/ → pkg/sdk/ (new package) - Create pkg/rag/helpers.go with convenience functions from internal/cmd/rag/ - Fix pkg/mcp/tools_rag.go to use pkg/rag instead of internal/cmd/rag - Fix pkg/build/buildcmd/cmd_sdk.go and pkg/release/sdk.go to use pkg/sdk - Remove all non-library content: main.go, internal/, cmd/, docker/, scripts/, tasks/, tools/, .core/, .forgejo/, .woodpecker/, Taskfile.yml - Run go mod tidy to trim unused dependencies core/go is now a pure Go package suite (library only). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Claude <developers@lethean.io> Reviewed-on: #3
146 lines
3.6 KiB
Go
146 lines
3.6 KiB
Go
package plugin
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"forge.lthn.ai/core/go/pkg/io"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestLoader_Discover_Good(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
baseDir := "/home/user/.core/plugins"
|
|
|
|
// Set up mock filesystem with two plugins
|
|
m.Dirs[baseDir] = true
|
|
m.Dirs[baseDir+"/plugin-a"] = true
|
|
m.Dirs[baseDir+"/plugin-b"] = true
|
|
|
|
m.Files[baseDir+"/plugin-a/plugin.json"] = `{
|
|
"name": "plugin-a",
|
|
"version": "1.0.0",
|
|
"description": "Plugin A",
|
|
"entrypoint": "main.go"
|
|
}`
|
|
|
|
m.Files[baseDir+"/plugin-b/plugin.json"] = `{
|
|
"name": "plugin-b",
|
|
"version": "2.0.0",
|
|
"description": "Plugin B",
|
|
"entrypoint": "run.sh"
|
|
}`
|
|
|
|
loader := NewLoader(m, baseDir)
|
|
manifests, err := loader.Discover()
|
|
assert.NoError(t, err)
|
|
assert.Len(t, manifests, 2)
|
|
|
|
names := make(map[string]bool)
|
|
for _, manifest := range manifests {
|
|
names[manifest.Name] = true
|
|
}
|
|
assert.True(t, names["plugin-a"])
|
|
assert.True(t, names["plugin-b"])
|
|
}
|
|
|
|
func TestLoader_Discover_Good_SkipsInvalidPlugins(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
baseDir := "/home/user/.core/plugins"
|
|
|
|
m.Dirs[baseDir] = true
|
|
m.Dirs[baseDir+"/good-plugin"] = true
|
|
m.Dirs[baseDir+"/bad-plugin"] = true
|
|
|
|
// Valid plugin
|
|
m.Files[baseDir+"/good-plugin/plugin.json"] = `{
|
|
"name": "good-plugin",
|
|
"version": "1.0.0",
|
|
"entrypoint": "main.go"
|
|
}`
|
|
|
|
// Invalid plugin (bad JSON)
|
|
m.Files[baseDir+"/bad-plugin/plugin.json"] = `{invalid}`
|
|
|
|
loader := NewLoader(m, baseDir)
|
|
manifests, err := loader.Discover()
|
|
assert.NoError(t, err)
|
|
assert.Len(t, manifests, 1)
|
|
assert.Equal(t, "good-plugin", manifests[0].Name)
|
|
}
|
|
|
|
func TestLoader_Discover_Good_SkipsFiles(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
baseDir := "/home/user/.core/plugins"
|
|
|
|
m.Dirs[baseDir] = true
|
|
m.Dirs[baseDir+"/real-plugin"] = true
|
|
m.Files[baseDir+"/registry.json"] = `{}` // A file, not a directory
|
|
|
|
m.Files[baseDir+"/real-plugin/plugin.json"] = `{
|
|
"name": "real-plugin",
|
|
"version": "1.0.0",
|
|
"entrypoint": "main.go"
|
|
}`
|
|
|
|
loader := NewLoader(m, baseDir)
|
|
manifests, err := loader.Discover()
|
|
assert.NoError(t, err)
|
|
assert.Len(t, manifests, 1)
|
|
assert.Equal(t, "real-plugin", manifests[0].Name)
|
|
}
|
|
|
|
func TestLoader_Discover_Good_EmptyDirectory(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
baseDir := "/home/user/.core/plugins"
|
|
m.Dirs[baseDir] = true
|
|
|
|
loader := NewLoader(m, baseDir)
|
|
manifests, err := loader.Discover()
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, manifests)
|
|
}
|
|
|
|
func TestLoader_LoadPlugin_Good(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
baseDir := "/home/user/.core/plugins"
|
|
|
|
m.Dirs[baseDir+"/my-plugin"] = true
|
|
m.Files[baseDir+"/my-plugin/plugin.json"] = `{
|
|
"name": "my-plugin",
|
|
"version": "1.0.0",
|
|
"description": "My plugin",
|
|
"author": "Test",
|
|
"entrypoint": "main.go"
|
|
}`
|
|
|
|
loader := NewLoader(m, baseDir)
|
|
manifest, err := loader.LoadPlugin("my-plugin")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "my-plugin", manifest.Name)
|
|
assert.Equal(t, "1.0.0", manifest.Version)
|
|
}
|
|
|
|
func TestLoader_LoadPlugin_Bad_NotFound(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
loader := NewLoader(m, "/home/user/.core/plugins")
|
|
|
|
_, err := loader.LoadPlugin("nonexistent")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "failed to load plugin")
|
|
}
|
|
|
|
func TestLoader_LoadPlugin_Bad_InvalidManifest(t *testing.T) {
|
|
m := io.NewMockMedium()
|
|
baseDir := "/home/user/.core/plugins"
|
|
|
|
m.Dirs[baseDir+"/bad-plugin"] = true
|
|
m.Files[baseDir+"/bad-plugin/plugin.json"] = `{
|
|
"name": "bad-plugin",
|
|
"version": "1.0.0"
|
|
}` // Missing entrypoint
|
|
|
|
loader := NewLoader(m, baseDir)
|
|
_, err := loader.LoadPlugin("bad-plugin")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid plugin manifest")
|
|
}
|