chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
package pluginmgr
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// redirectTransport rewrites every request's Host to point at target.
|
||||
type redirectTransport struct {
|
||||
target *url.URL
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
func (t redirectTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
clone := req.Clone(req.Context())
|
||||
clone.URL.Scheme = t.target.Scheme
|
||||
clone.URL.Host = t.target.Host
|
||||
clone.Host = t.target.Host
|
||||
return t.rt.RoundTrip(clone)
|
||||
}
|
||||
|
||||
func installTestClient(t *testing.T, serverURL string) {
|
||||
t.Helper()
|
||||
u, err := url.Parse(serverURL)
|
||||
if err != nil {
|
||||
t.Fatalf("parse: %v", err)
|
||||
}
|
||||
old := httpClient
|
||||
httpClient = &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
Transport: redirectTransport{target: u, rt: http.DefaultTransport},
|
||||
}
|
||||
t.Cleanup(func() { httpClient = old })
|
||||
}
|
||||
|
||||
func withTempHome(t *testing.T) string {
|
||||
t.Helper()
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
return home
|
||||
}
|
||||
|
||||
func TestScanPluginsEmptyDir(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
plugins, err := scanPlugins(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("scanPlugins: %v", err)
|
||||
}
|
||||
if len(plugins) != 0 {
|
||||
t.Errorf("expected 0 plugins in empty dir, got %d", len(plugins))
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanPluginsSingleFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
src := `plugin.register({
|
||||
name = "hello",
|
||||
version = "1.2",
|
||||
description = "says hi",
|
||||
type = "visualizer",
|
||||
})
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(dir, "hello.lua"), []byte(src), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
plugins, err := scanPlugins(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("scanPlugins: %v", err)
|
||||
}
|
||||
if len(plugins) != 1 {
|
||||
t.Fatalf("got %d plugins, want 1", len(plugins))
|
||||
}
|
||||
got := plugins[0]
|
||||
if got.name != "hello" {
|
||||
t.Errorf("name = %q, want hello", got.name)
|
||||
}
|
||||
if got.version != "1.2" {
|
||||
t.Errorf("version = %q, want 1.2", got.version)
|
||||
}
|
||||
if got.description != "says hi" {
|
||||
t.Errorf("description = %q, want 'says hi'", got.description)
|
||||
}
|
||||
if got.typ != "visualizer" {
|
||||
t.Errorf("typ = %q, want visualizer", got.typ)
|
||||
}
|
||||
if got.file != "hello.lua" {
|
||||
t.Errorf("file = %q, want hello.lua", got.file)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanPluginsFallsBackToFilename(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
// Plugin without register() call — name should default to filename.
|
||||
if err := os.WriteFile(filepath.Join(dir, "nameless.lua"), []byte(`-- nothing`), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
plugins, err := scanPlugins(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("scanPlugins: %v", err)
|
||||
}
|
||||
if len(plugins) != 1 {
|
||||
t.Fatalf("got %d plugins, want 1", len(plugins))
|
||||
}
|
||||
if plugins[0].name != "nameless" {
|
||||
t.Errorf("name = %q, want 'nameless' (filename fallback)", plugins[0].name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanPluginsDirectoryEntry(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
// Create a directory plugin: <dir>/myplug/init.lua
|
||||
sub := filepath.Join(dir, "myplug")
|
||||
if err := os.MkdirAll(sub, 0o755); err != nil {
|
||||
t.Fatalf("MkdirAll: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(sub, "init.lua"), []byte(`plugin.register({ name = "myplug", version = "0.1" })`), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
plugins, err := scanPlugins(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("scanPlugins: %v", err)
|
||||
}
|
||||
if len(plugins) != 1 {
|
||||
t.Fatalf("got %d plugins, want 1", len(plugins))
|
||||
}
|
||||
if plugins[0].file != "myplug/" {
|
||||
t.Errorf("file = %q, want 'myplug/'", plugins[0].file)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanPluginsIgnoresNonLua(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(dir, "notes.txt"), []byte("nothing"), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
plugins, err := scanPlugins(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("scanPlugins: %v", err)
|
||||
}
|
||||
if len(plugins) != 0 {
|
||||
t.Errorf("non-lua file should be ignored, got %+v", plugins)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListNoPlugins(t *testing.T) {
|
||||
withTempHome(t)
|
||||
if err := List(); err != nil {
|
||||
t.Errorf("List on empty dir should not error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPluginsShowsInstalled(t *testing.T) {
|
||||
home := withTempHome(t)
|
||||
plugDir := filepath.Join(home, ".config", "cliamp", "plugins")
|
||||
if err := os.MkdirAll(plugDir, 0o755); err != nil {
|
||||
t.Fatalf("MkdirAll: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(plugDir, "x.lua"), []byte(`plugin.register({ name = "x", version = "1.0" })`), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
// List writes to stdout — we just verify it doesn't error.
|
||||
if err := List(); err != nil {
|
||||
t.Errorf("List: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveFile(t *testing.T) {
|
||||
home := withTempHome(t)
|
||||
plugDir := filepath.Join(home, ".config", "cliamp", "plugins")
|
||||
if err := os.MkdirAll(plugDir, 0o755); err != nil {
|
||||
t.Fatalf("MkdirAll: %v", err)
|
||||
}
|
||||
path := filepath.Join(plugDir, "foo.lua")
|
||||
if err := os.WriteFile(path, []byte("x"), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
if err := Remove("foo"); err != nil {
|
||||
t.Fatalf("Remove: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
t.Errorf("plugin should be removed, stat err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveDirectory(t *testing.T) {
|
||||
home := withTempHome(t)
|
||||
plugDir := filepath.Join(home, ".config", "cliamp", "plugins")
|
||||
nested := filepath.Join(plugDir, "bar", "init.lua")
|
||||
if err := os.MkdirAll(filepath.Dir(nested), 0o755); err != nil {
|
||||
t.Fatalf("MkdirAll: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(nested, []byte("x"), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
if err := Remove("bar"); err != nil {
|
||||
t.Fatalf("Remove: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Dir(nested)); !os.IsNotExist(err) {
|
||||
t.Errorf("plugin dir should be removed, stat err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveMissing(t *testing.T) {
|
||||
withTempHome(t)
|
||||
err := Remove("ghost")
|
||||
if err == nil {
|
||||
t.Error("Remove non-existent plugin should error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "not found") {
|
||||
t.Errorf("error = %q, want to mention 'not found'", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallFromRawURL(t *testing.T) {
|
||||
withTempHome(t)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasSuffix(r.URL.Path, "/example.lua") {
|
||||
t.Errorf("unexpected path %q", r.URL.Path)
|
||||
}
|
||||
_, _ = w.Write([]byte(`plugin.register({ name = "example", version = "1" })`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
installTestClient(t, srv.URL)
|
||||
|
||||
if err := Install(srv.URL+"/example.lua", true); err != nil {
|
||||
t.Fatalf("Install: %v", err)
|
||||
}
|
||||
|
||||
// Verify the installed file exists.
|
||||
home, _ := os.UserHomeDir()
|
||||
dest := filepath.Join(home, ".config", "cliamp", "plugins", "example.lua")
|
||||
if _, err := os.Stat(dest); err != nil {
|
||||
t.Errorf("installed plugin missing: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallAlreadyExists(t *testing.T) {
|
||||
home := withTempHome(t)
|
||||
plugDir := filepath.Join(home, ".config", "cliamp", "plugins")
|
||||
if err := os.MkdirAll(plugDir, 0o755); err != nil {
|
||||
t.Fatalf("MkdirAll: %v", err)
|
||||
}
|
||||
existing := filepath.Join(plugDir, "mypl.lua")
|
||||
if err := os.WriteFile(existing, []byte("x"), 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`-- ok`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
installTestClient(t, srv.URL)
|
||||
|
||||
err := Install(srv.URL+"/mypl.lua", true)
|
||||
if err == nil {
|
||||
t.Fatal("Install over existing plugin should error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "already exists") {
|
||||
t.Errorf("error = %q, want to mention 'already exists'", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallAllURLsFail(t *testing.T) {
|
||||
withTempHome(t)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
}))
|
||||
defer srv.Close()
|
||||
installTestClient(t, srv.URL)
|
||||
|
||||
err := Install(srv.URL+"/nonexistent.lua", true)
|
||||
if err == nil {
|
||||
t.Error("Install with all failing URLs should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallTooLarge(t *testing.T) {
|
||||
withTempHome(t)
|
||||
big := strings.Repeat("x", maxPluginSize+1)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(big))
|
||||
}))
|
||||
defer srv.Close()
|
||||
installTestClient(t, srv.URL)
|
||||
|
||||
err := Install(srv.URL+"/huge.lua", true)
|
||||
if err == nil {
|
||||
t.Error("Install of oversized plugin should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.HandlerFunc
|
||||
wantErr string
|
||||
}{
|
||||
{"404", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "missing", http.StatusNotFound)
|
||||
}, "HTTP"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
srv := httptest.NewServer(tt.handler)
|
||||
defer srv.Close()
|
||||
installTestClient(t, srv.URL)
|
||||
|
||||
_, err := download(srv.URL + "/x.lua")
|
||||
if err == nil {
|
||||
t.Fatal("download should have errored")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.wantErr) {
|
||||
t.Errorf("error = %q, want to contain %q", err.Error(), tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user