186 lines
6.2 KiB
Go
186 lines
6.2 KiB
Go
package localmcp
|
|
|
|
import (
|
|
"bytes"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"hugin/cli/internal/bundle"
|
|
)
|
|
|
|
const example = "../../../contract/examples/bundles/local-mcp"
|
|
|
|
func TestHome(t *testing.T) {
|
|
t.Setenv("HUGIN_MCP_HOME", "")
|
|
t.Setenv("HOME", "/home/anna")
|
|
t.Setenv("USERPROFILE", `C:\Users\anna`)
|
|
home, err := Home()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
user, _ := os.UserHomeDir()
|
|
if home != filepath.Join(user, ".local", "share", "mcp") {
|
|
t.Errorf("Home = %s", home)
|
|
}
|
|
t.Setenv("HUGIN_MCP_HOME", t.TempDir())
|
|
if home, _ := Home(); home != os.Getenv("HUGIN_MCP_HOME") {
|
|
t.Errorf("HUGIN_MCP_HOME nicht beachtet: %s", home)
|
|
}
|
|
}
|
|
|
|
func TestFindRepoFromSubfolder(t *testing.T) {
|
|
repo := t.TempDir()
|
|
os.WriteFile(filepath.Join(repo, "hugin.lock"), []byte("packages: {}\n"), 0o644)
|
|
sub := filepath.Join(repo, "a", "b")
|
|
os.MkdirAll(sub, 0o755)
|
|
found, err := FindRepo(sub)
|
|
if err != nil || found != repo {
|
|
t.Errorf("FindRepo = %q, %v", found, err)
|
|
}
|
|
other := t.TempDir()
|
|
os.WriteFile(filepath.Join(other, ".hugin.yaml"), []byte("server: x\n"), 0o644)
|
|
if found, _ := FindRepo(other); found != other {
|
|
t.Errorf("Repo ohne hugin.lock nicht gefunden: %q", found)
|
|
}
|
|
if _, err := FindRepo(t.TempDir()); err == nil {
|
|
t.Error("ohne hugin.lock kein Fehler")
|
|
}
|
|
}
|
|
|
|
func TestCommand(t *testing.T) {
|
|
folder := filepath.Join("srv", "1.0.0")
|
|
_, args, env := Command(folder, &Marker{Entry: "jira_mcp"})
|
|
if !slices.Equal(args, []string{"-m", "jira_mcp"}) {
|
|
t.Errorf("Modul: %v", args)
|
|
}
|
|
_, args, _ = Command(folder, &Marker{Entry: "tools/server.py"})
|
|
if !slices.Equal(args, []string{filepath.Join(folder, "tools", "server.py")}) {
|
|
t.Errorf("Skript: %v", args)
|
|
}
|
|
if !slices.Contains(env, "PYTHONUTF8=1") {
|
|
t.Error("PYTHONUTF8 fehlt")
|
|
}
|
|
}
|
|
|
|
// Echte venv mit dem Python des Rechners; das Beispiel braucht keine Abhängigkeiten.
|
|
func TestInstallAndRun(t *testing.T) {
|
|
if _, err := FindPython(""); err != nil {
|
|
t.Skip(err)
|
|
}
|
|
b, err := bundle.Read(example)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
op := b.Installs()[0]
|
|
home := t.TempDir()
|
|
if Installed(home, op) {
|
|
t.Fatal("vor der Installation schon installiert")
|
|
}
|
|
if err := Install(home, b, op, &bytes.Buffer{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !Installed(home, op) {
|
|
t.Fatal("nach der Installation nicht installiert")
|
|
}
|
|
folder := Folder(home, op.Package, op.Version)
|
|
m, _ := Read(folder)
|
|
program, args, env := Command(folder, m)
|
|
c := exec.Command(program, args...)
|
|
c.Env = env
|
|
c.Stdin = bytes.NewBufferString(`{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"zeit"}}` + "\n")
|
|
out, err := c.Output()
|
|
if err != nil || !bytes.Contains(out, []byte("UHR-4711")) {
|
|
t.Errorf("Server antwortet nicht: %s %v", out, err)
|
|
}
|
|
// Andere Fassung derselben Version gilt als nicht installiert
|
|
op.Checksum = "sha256:anders"
|
|
if Installed(home, op) {
|
|
t.Error("andere Prüfsumme gilt als installiert")
|
|
}
|
|
}
|
|
|
|
func TestOlderThan(t *testing.T) {
|
|
for _, tt := range []struct {
|
|
version, minimum string
|
|
older bool
|
|
}{{"3.9", "3.10", true}, {"3.12", "3.10", false}, {"3.10", "3.10", false}, {"3.13", "", false}} {
|
|
if olderThan(tt.version, tt.minimum) != tt.older {
|
|
t.Errorf("olderThan(%s, %s) != %v", tt.version, tt.minimum, tt.older)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFindPythonRespectsMinimum(t *testing.T) {
|
|
if _, err := exec.LookPath("sh"); err != nil {
|
|
t.Skip("braucht sh")
|
|
}
|
|
fake := filepath.Join(t.TempDir(), "python")
|
|
os.WriteFile(fake, []byte("#!/bin/sh\necho 3.9\n"), 0o755)
|
|
t.Setenv("HUGIN_PYTHON", fake)
|
|
if _, err := FindPython("3.10"); err == nil || !strings.Contains(err.Error(), "3.9") {
|
|
t.Errorf("zu altes Python nicht gemeldet: %v", err)
|
|
}
|
|
if got, err := FindPython("3.9"); err != nil || got[0] != fake {
|
|
t.Errorf("passendes Python nicht genommen: %v %v", got, err)
|
|
}
|
|
}
|
|
|
|
func TestPipGetsHashesAndNoIndex(t *testing.T) {
|
|
if _, err := exec.LookPath("sh"); err != nil {
|
|
t.Skip("braucht sh")
|
|
}
|
|
home, fake := t.TempDir(), t.TempDir()
|
|
log := filepath.Join(fake, "aufrufe")
|
|
// Stellvertreter für python: legt die venv-Struktur an und schreibt die Aufrufe mit
|
|
script := "#!/bin/sh\nif [ \"$1\" = -c ]; then echo 3.12; exit; fi\necho \"$@\" >> " + log +
|
|
"\nif [ \"$1\" = -m ] && [ \"$2\" = venv ]; then mkdir -p \"$3/bin\"; cp \"$0\" \"$3/bin/python\"; fi\n"
|
|
python := filepath.Join(fake, "python")
|
|
os.WriteFile(python, []byte(script), 0o755)
|
|
t.Setenv("HUGIN_PYTHON", python)
|
|
b, _ := bundle.Read(example)
|
|
op := b.Installs()[0]
|
|
op.Files = append(op.Files, bundle.InstallFile{Path: "requirements.txt", Source: op.Files[0].Source})
|
|
if err := Install(home, b, op, &bytes.Buffer{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
calls, _ := os.ReadFile(log)
|
|
want := "-m pip install --quiet --no-input --disable-pip-version-check --require-hashes -r requirements.txt"
|
|
if !bytes.Contains(calls, []byte(want)) {
|
|
t.Errorf("pip-Aufruf fehlt:\n%s", calls)
|
|
}
|
|
}
|
|
|
|
func TestPruneKeepsUsedAndForeign(t *testing.T) {
|
|
home, repo := t.TempDir(), t.TempDir()
|
|
marker := func(pkg, version string) {
|
|
folder := Folder(home, pkg, version)
|
|
os.MkdirAll(folder, 0o755)
|
|
os.WriteFile(filepath.Join(folder, markerFile), []byte(`{"package":"`+pkg+`","version":"`+version+`"}`), 0o644)
|
|
}
|
|
marker("pub-a", "1.0.0")
|
|
marker("pub-a", "1.1.0")
|
|
marker("pub-a", "1.2.0") // gerade mit hugin try installiert
|
|
os.MkdirAll(filepath.Join(repo, ".hugin"), 0o755)
|
|
os.WriteFile(filepath.Join(repo, ".hugin", "trial.lock"), []byte("packages:\n pub-a:\n version: 1.2.0\n checksum: y\n"), 0o644)
|
|
// Ordner ohne Markierung gehört nicht Hugin, etwa ein eigener Server
|
|
os.MkdirAll(filepath.Join(home, "eigener-server", "bin"), 0o755)
|
|
os.MkdirAll(filepath.Join(home, "noch-leer"), 0o755)
|
|
os.WriteFile(filepath.Join(repo, "hugin.lock"), []byte("packages:\n pub-a:\n version: 1.1.0\n checksum: x\n"), 0o644)
|
|
if err := Register(home, repo); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
removed, err := Prune(home, false)
|
|
if err != nil || !slices.Equal(removed, []string{"pub-a 1.0.0"}) {
|
|
t.Fatalf("Prune = %v, %v", removed, err)
|
|
}
|
|
for _, keep := range []string{Folder(home, "pub-a", "1.1.0"), Folder(home, "pub-a", "1.2.0"), filepath.Join(home, "eigener-server", "bin"),
|
|
filepath.Join(home, "noch-leer")} {
|
|
if _, err := os.Stat(keep); err != nil {
|
|
t.Errorf("%s gelöscht", keep)
|
|
}
|
|
}
|
|
}
|