- windows/installer.nsi: installs to Program Files, manages system PATH, registers uninstaller - relspec update [--check] [--yes]: compares against the latest release and prompts; on Windows downloads and runs the installer - release workflow builds and uploads relspec-setup-windows-amd64.exe - make installer-windows
111 lines
4.1 KiB
Go
111 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func releaseServer(t *testing.T, tag string, withInstaller bool) *httptest.Server {
|
|
t.Helper()
|
|
assets := ""
|
|
if withInstaller {
|
|
assets = fmt.Sprintf(`{"name":%q,"browser_download_url":"https://x/setup.exe"}`, windowsInstallerAsset)
|
|
}
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
_, _ = fmt.Fprintf(w, `{"tag_name":%q,"html_url":"https://x/release","assets":[%s]}`, tag, assets)
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
return srv
|
|
}
|
|
|
|
func TestRunUpdate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
current string
|
|
latest string
|
|
withInstaller bool
|
|
goos string
|
|
checkOnly bool
|
|
assumeYes bool
|
|
stdin string
|
|
wantOut []string
|
|
wantInstall bool
|
|
}{
|
|
{name: "up to date", current: "v1.0.5", latest: "v1.0.5", goos: "windows", withInstaller: true, wantOut: []string{"up to date"}},
|
|
{name: "dev build never prompts", current: "dev", latest: "v9.0.0", goos: "windows", withInstaller: true, wantOut: []string{"up to date"}},
|
|
{name: "check only", current: "v1.0.5", latest: "v1.0.6", goos: "windows", withInstaller: true, checkOnly: true, wantOut: []string{"v1.0.6", "https://x/release"}},
|
|
{name: "non-windows shows url", current: "v1.0.5", latest: "v1.0.6", goos: "linux", withInstaller: true, wantOut: []string{"Download it from: https://x/release"}},
|
|
{name: "windows without installer asset", current: "v1.0.5", latest: "v1.0.6", goos: "windows", wantOut: []string{"Download it from"}},
|
|
{name: "windows prompt yes", current: "v1.0.5", latest: "v1.0.6", goos: "windows", withInstaller: true, stdin: "y\n", wantOut: []string{"[y/N]"}, wantInstall: true},
|
|
{name: "windows prompt no", current: "v1.0.5", latest: "v1.0.6", goos: "windows", withInstaller: true, stdin: "n\n", wantOut: []string{"Skipped"}},
|
|
{name: "windows prompt empty", current: "v1.0.5", latest: "v1.0.6", goos: "windows", withInstaller: true, wantOut: []string{"Skipped"}},
|
|
{name: "windows --yes", current: "v1.0.5", latest: "v1.0.6", goos: "windows", withInstaller: true, assumeYes: true, wantInstall: true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
srv := releaseServer(t, tt.latest, tt.withInstaller)
|
|
var out bytes.Buffer
|
|
var installedURL string
|
|
err := runUpdate(context.Background(), updateOptions{
|
|
current: tt.current, apiURL: srv.URL, goos: tt.goos,
|
|
checkOnly: tt.checkOnly, assumeYes: tt.assumeYes,
|
|
in: strings.NewReader(tt.stdin), out: &out,
|
|
install: func(_ context.Context, url string, _ io.Writer) error {
|
|
installedURL = url
|
|
return nil
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, want := range tt.wantOut {
|
|
if !strings.Contains(out.String(), want) {
|
|
t.Errorf("output missing %q:\n%s", want, out.String())
|
|
}
|
|
}
|
|
if (installedURL != "") != tt.wantInstall {
|
|
t.Errorf("installer called = %v, want %v", installedURL != "", tt.wantInstall)
|
|
}
|
|
if tt.wantInstall && installedURL != "https://x/setup.exe" {
|
|
t.Errorf("installer url = %q", installedURL)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunUpdate_Errors(t *testing.T) {
|
|
bad := httptest.NewServer(http.NotFoundHandler())
|
|
defer bad.Close()
|
|
if err := runUpdate(context.Background(), updateOptions{current: "v1.0.0", apiURL: bad.URL, out: io.Discard}); err == nil {
|
|
t.Error("expected lookup error")
|
|
}
|
|
|
|
srv := releaseServer(t, "v1.0.6", true)
|
|
want := errors.New("boom")
|
|
err := runUpdate(context.Background(), updateOptions{
|
|
current: "v1.0.5", apiURL: srv.URL, goos: "windows", assumeYes: true, out: io.Discard,
|
|
install: func(context.Context, string, io.Writer) error { return want },
|
|
})
|
|
if !errors.Is(err, want) {
|
|
t.Errorf("err = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDownloadAndRunInstaller_BadStatus(t *testing.T) {
|
|
srv := httptest.NewServer(http.NotFoundHandler())
|
|
defer srv.Close()
|
|
if err := downloadAndRunInstaller(context.Background(), srv.URL, io.Discard); err == nil {
|
|
t.Error("expected error for non-200")
|
|
}
|
|
if err := downloadAndRunInstaller(context.Background(), "://bad", io.Discard); err == nil {
|
|
t.Error("expected error for bad url")
|
|
}
|
|
}
|