152 lines
4.3 KiB
Go
152 lines
4.3 KiB
Go
package scripts
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestUnixInstallerInstallsVerifiedRelease(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("install.sh is not used on Windows")
|
|
}
|
|
root := repositoryRoot(t)
|
|
repository := t.TempDir()
|
|
installDir := t.TempDir()
|
|
createUnixRelease(t, repository, false)
|
|
|
|
output, err := runUnixInstaller(root, repository, installDir)
|
|
if err != nil {
|
|
t.Fatalf("install.sh failed: %v\n%s", err, output)
|
|
}
|
|
if !strings.Contains(output, "Installed klink v0.1.0") {
|
|
t.Fatalf("install output does not report success:\n%s", output)
|
|
}
|
|
|
|
binary := filepath.Join(installDir, "klink")
|
|
info, err := os.Stat(binary)
|
|
if err != nil {
|
|
t.Fatalf("installed binary: %v", err)
|
|
}
|
|
if info.Mode()&0o111 == 0 {
|
|
t.Fatalf("installed binary is not executable: mode %v", info.Mode())
|
|
}
|
|
commandOutput, err := exec.Command(binary).CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("run installed binary: %v\n%s", err, commandOutput)
|
|
}
|
|
if got := strings.TrimSpace(string(commandOutput)); got != "klink installer test" {
|
|
t.Fatalf("installed binary output = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestUnixInstallerRejectsChecksumMismatch(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("install.sh is not used on Windows")
|
|
}
|
|
root := repositoryRoot(t)
|
|
repository := t.TempDir()
|
|
installDir := t.TempDir()
|
|
createUnixRelease(t, repository, true)
|
|
|
|
output, err := runUnixInstaller(root, repository, installDir)
|
|
if err == nil {
|
|
t.Fatalf("install.sh accepted an invalid checksum:\n%s", output)
|
|
}
|
|
if !strings.Contains(output, "SHA256 checksum mismatch") {
|
|
t.Fatalf("unexpected checksum failure:\n%s", output)
|
|
}
|
|
if _, statErr := os.Stat(filepath.Join(installDir, "klink")); !os.IsNotExist(statErr) {
|
|
t.Fatalf("installer left a binary after checksum failure: %v", statErr)
|
|
}
|
|
}
|
|
|
|
func repositoryRoot(t *testing.T) string {
|
|
t.Helper()
|
|
_, filename, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
t.Fatal("could not locate installer test")
|
|
}
|
|
return filepath.Dir(filepath.Dir(filename))
|
|
}
|
|
|
|
func createUnixRelease(t *testing.T, repository string, corruptChecksum bool) {
|
|
t.Helper()
|
|
const asset = "klink_0.1.0_linux_amd64.tar.gz"
|
|
releaseDir := filepath.Join(repository, "releases", "download", "v0.1.0")
|
|
if err := os.MkdirAll(releaseDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var archive bytes.Buffer
|
|
gzipWriter := gzip.NewWriter(&archive)
|
|
tarWriter := tar.NewWriter(gzipWriter)
|
|
content := []byte("#!/bin/sh\nprintf '%s\\n' 'klink installer test'\n")
|
|
header := &tar.Header{Name: "klink", Mode: 0o755, Size: int64(len(content))}
|
|
if err := tarWriter.WriteHeader(header); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := tarWriter.Write(content); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tarWriter.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := gzipWriter.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
archiveBytes := archive.Bytes()
|
|
if err := os.WriteFile(filepath.Join(releaseDir, asset), archiveBytes, 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
digest := sha256.Sum256(archiveBytes)
|
|
if corruptChecksum {
|
|
digest = sha256.Sum256([]byte("not the release archive"))
|
|
}
|
|
checksums := fmt.Sprintf("%x %s\n", digest, asset)
|
|
if err := os.WriteFile(filepath.Join(releaseDir, "checksums.txt"), []byte(checksums), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func runUnixInstaller(root, repository, installDir string) (string, error) {
|
|
command := exec.Command("sh", filepath.Join(root, "install.sh"))
|
|
command.Env = installerEnvironment(repository, installDir)
|
|
output, err := command.CombinedOutput()
|
|
return string(output), err
|
|
}
|
|
|
|
func installerEnvironment(repository, installDir string) []string {
|
|
overrides := map[string]string{
|
|
"KLINK_ALLOW_INSECURE": "1",
|
|
"KLINK_ARCH": "amd64",
|
|
"KLINK_INSTALL_DIR": installDir,
|
|
"KLINK_OS": "linux",
|
|
"KLINK_REPOSITORY_URL": "file://" + filepath.ToSlash(repository),
|
|
"KLINK_VERSION": "v0.1.0",
|
|
}
|
|
environment := make([]string, 0, len(os.Environ())+len(overrides))
|
|
for _, entry := range os.Environ() {
|
|
name, _, found := strings.Cut(entry, "=")
|
|
if !found {
|
|
continue
|
|
}
|
|
if _, overridden := overrides[name]; !overridden {
|
|
environment = append(environment, entry)
|
|
}
|
|
}
|
|
for name, value := range overrides {
|
|
environment = append(environment, name+"="+value)
|
|
}
|
|
return environment
|
|
}
|