package scripts_test import ( "os" "os/exec" "path/filepath" "strings" "testing" ) var expectedHomeSkillTargets = []string{ ".agents/skills/dws", } func TestInstallScriptSourceModeInstallsBinary(t *testing.T) { t.Parallel() root := t.TempDir() installDir := filepath.Join(root, "bin") scriptPath, err := filepath.Abs(filepath.Join("..", "..", "scripts", "install.sh")) if err != nil { t.Fatalf("Abs(install.sh) error = %v", err) } // Stub make: when invoked as "make -C build", create a fake dws binary // in the project root (the -C target directory). stubRoot := filepath.Join(root, "stubs") repoRoot, _ := filepath.Abs(filepath.Join("..", "..")) makeStub := `#!/bin/sh set -eu dir="" while [ "$#" -gt 0 ]; do case "$1" in -C) dir="$2"; shift 2 ;; *) shift ;; esac done [ -n "$dir" ] && printf 'fake-binary\n' > "$dir/dws" ` mustWriteFile(t, filepath.Join(stubRoot, "make"), []byte(makeStub), 0o755) // Also need a stub go so need_cmd check passes mustWriteFile(t, filepath.Join(stubRoot, "go"), []byte("#!/bin/sh\ntrue\n"), 0o755) cmd := exec.Command("sh", scriptPath) cmd.Env = append(os.Environ(), "PATH="+stubRoot+":"+os.Getenv("PATH"), "DWS_INSTALL_DIR="+installDir, "DWS_INSTALL_NAME=dws-test", ) output, err := cmd.CombinedOutput() // Clean up the fake binary created in the real repo root _ = os.Remove(filepath.Join(repoRoot, "dws")) if err != nil { t.Fatalf("install.sh error = %v\noutput:\n%s", err, string(output)) } got := string(output) for _, want := range []string{ "Installing dws from source checkout", "Install dir: " + installDir, "Binary installed:", installDir + "/dws-test", } { if !strings.Contains(got, want) { t.Fatalf("install output missing %q:\n%s", want, got) } } binaryPath := filepath.Join(installDir, "dws-test") binaryData, err := os.ReadFile(binaryPath) if err != nil { t.Fatalf("ReadFile(%s) error = %v", binaryPath, err) } if string(binaryData) != "fake-binary\n" { t.Fatalf("installed binary content = %q, want fake-binary", string(binaryData)) } } func TestInstallScriptSourceModeInstallsSkillsIntoAgentsDir(t *testing.T) { t.Parallel() root := t.TempDir() fakeHome := filepath.Join(root, "home") installDir := filepath.Join(root, "bin") scriptPath, err := filepath.Abs(filepath.Join("..", "..", "scripts", "install.sh")) if err != nil { t.Fatalf("Abs(install.sh) error = %v", err) } stubRoot := filepath.Join(root, "stubs") repoRoot, _ := filepath.Abs(filepath.Join("..", "..")) makeStub := `#!/bin/sh set -eu dir="" while [ "$#" -gt 0 ]; do case "$1" in -C) dir="$2"; shift 2 ;; *) shift ;; esac done [ -n "$dir" ] && printf 'fake-binary\n' > "$dir/dws" ` mustWriteFile(t, filepath.Join(stubRoot, "make"), []byte(makeStub), 0o755) mustWriteFile(t, filepath.Join(stubRoot, "go"), []byte("#!/bin/sh\ntrue\n"), 0o755) cmd := exec.Command("sh", scriptPath) cmd.Env = append(os.Environ(), "HOME="+fakeHome, "PATH="+stubRoot+":"+os.Getenv("PATH"), "DWS_INSTALL_DIR="+installDir, ) output, err := cmd.CombinedOutput() // Clean up the fake binary created in the real repo root _ = os.Remove(filepath.Join(repoRoot, "dws")) if err != nil { t.Fatalf("install.sh error = %v\noutput:\n%s", err, string(output)) } for _, rel := range expectedHomeSkillTargets { skillPath := filepath.Join(fakeHome, filepath.FromSlash(rel), "SKILL.md") if _, err := os.Stat(skillPath); err != nil { t.Fatalf("Stat(%s) error = %v\noutput:\n%s", skillPath, err, string(output)) } } } func TestInstallPowerShellScriptInstallsToAgentsDir(t *testing.T) { t.Parallel() scriptPath, err := filepath.Abs(filepath.Join("..", "..", "scripts", "install.ps1")) if err != nil { t.Fatalf("Abs(install.ps1) error = %v", err) } data, err := os.ReadFile(scriptPath) if err != nil { t.Fatalf("ReadFile(%s) error = %v", scriptPath, err) } text := string(data) if !strings.Contains(text, ".agents\\skills") { t.Fatalf("install.ps1 missing .agents\\skills") } } func TestInstallScriptsUseGitHubReleaseSkillsAsset(t *testing.T) { t.Parallel() for _, rel := range []string{ filepath.Join("..", "..", "scripts", "install.sh"), filepath.Join("..", "..", "scripts", "install.ps1"), filepath.Join("..", "..", "scripts", "install-skills.sh"), } { scriptPath, err := filepath.Abs(rel) if err != nil { t.Fatalf("Abs(%s) error = %v", rel, err) } data, err := os.ReadFile(scriptPath) if err != nil { t.Fatalf("ReadFile(%s) error = %v", scriptPath, err) } text := string(data) if !strings.Contains(text, "releases/download") || !strings.Contains(text, "dws-skills.zip") { t.Fatalf("%s should download dws-skills.zip from GitHub Releases", scriptPath) } if strings.Contains(text, "archive/refs/heads/main.tar.gz") || strings.Contains(text, "archive/refs/tags/") { t.Fatalf("%s should not download skills from repository archive refs", scriptPath) } } } func TestInstallScriptsUseFlattenedSkillsSourceRoot(t *testing.T) { t.Parallel() checks := []struct { relPath string want string avoid string }{ { relPath: filepath.Join("..", "..", "scripts", "install.sh"), want: `skill_src="${root}/skills"`, avoid: `skill_src="${root}/skills/${SKILL_NAME}"`, }, { relPath: filepath.Join("..", "..", "scripts", "install.ps1"), want: `$skillSrc = Join-Path $Root "skills"`, avoid: `$skillSrc = Join-Path $Root "skills\$SkillName"`, }, } for _, tc := range checks { scriptPath, err := filepath.Abs(tc.relPath) if err != nil { t.Fatalf("Abs(%s) error = %v", tc.relPath, err) } data, err := os.ReadFile(scriptPath) if err != nil { t.Fatalf("ReadFile(%s) error = %v", scriptPath, err) } text := string(data) if !strings.Contains(text, tc.want) { t.Fatalf("%s missing flattened skills root %q", scriptPath, tc.want) } if strings.Contains(text, tc.avoid) { t.Fatalf("%s still references legacy nested skills root %q", scriptPath, tc.avoid) } } } func TestBuildEntrypointsUseStripLdflags(t *testing.T) { t.Parallel() checks := []struct { relPath string want string }{ { relPath: filepath.Join("..", "..", "scripts", "install.ps1"), want: `go build -ldflags="-s -w" -o $tmpBin "$Root/cmd"`, }, { relPath: filepath.Join("..", "..", "scripts", "policy", "check-command-surface.sh"), want: `go build -ldflags="-s -w" -o "$BIN_PATH" ./cmd`, }, } for _, tc := range checks { scriptPath, err := filepath.Abs(tc.relPath) if err != nil { t.Fatalf("Abs(%s) error = %v", tc.relPath, err) } data, err := os.ReadFile(scriptPath) if err != nil { t.Fatalf("ReadFile(%s) error = %v", scriptPath, err) } if !strings.Contains(string(data), tc.want) { t.Fatalf("%s missing stripped ldflags build invocation %q", scriptPath, tc.want) } } } func mustWriteFile(t *testing.T, path string, data []byte, mode os.FileMode) { t.Helper() if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatalf("MkdirAll(%s) error = %v", filepath.Dir(path), err) } if err := os.WriteFile(path, data, mode); err != nil { t.Fatalf("WriteFile(%s) error = %v", path, err) } }