- 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
95 lines
2.6 KiB
Go
95 lines
2.6 KiB
Go
package updatecheck
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestIsNewer(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
current, latest string
|
|
want bool
|
|
}{
|
|
{"patch bump", "v1.0.85", "v1.0.86", true},
|
|
{"minor beats patch", "v1.0.99", "v1.1.0", true},
|
|
{"major bump", "v1.9.9", "v2.0.0", true},
|
|
{"numeric not lexical", "v1.0.9", "v1.0.10", true},
|
|
{"same", "v1.0.85", "v1.0.85", false},
|
|
{"older latest", "v1.0.86", "v1.0.85", false},
|
|
{"no v prefix", "1.0.1", "v1.0.2", true},
|
|
{"short version", "v1.0", "v1.0.1", true},
|
|
{"prerelease suffix ignored", "v1.0.1-rc1", "v1.0.2", true},
|
|
{"dev build", "dev", "v9.9.9", false},
|
|
{"commit hash", "abc1234", "v9.9.9", false},
|
|
{"empty current", "", "v1.0.0", false},
|
|
{"bad latest", "v1.0.0", "latest", false},
|
|
{"too many parts", "v1.0.0.0", "v1.0.1", false},
|
|
{"negative", "v1.-1.0", "v1.0.0", false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := IsNewer(tt.current, tt.latest); got != tt.want {
|
|
t.Errorf("IsNewer(%q,%q) = %v, want %v", tt.current, tt.latest, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLatest(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
status int
|
|
body string
|
|
wantTag string
|
|
wantErr bool
|
|
}{
|
|
{"ok", 200, `{"tag_name":"v1.2.3","html_url":"https://x/r","assets":[{"name":"a.exe","browser_download_url":"https://x/a.exe"}]}`, "v1.2.3", false},
|
|
{"not found", 404, `{}`, "", true},
|
|
{"bad json", 200, `{`, "", true},
|
|
{"missing tag", 200, `{"html_url":"u"}`, "", true},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(tt.status)
|
|
_, _ = w.Write([]byte(tt.body))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
rel, err := Latest(context.Background(), nil, srv.URL)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Fatalf("err = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
if err == nil {
|
|
if rel.Tag != tt.wantTag {
|
|
t.Errorf("tag = %q", rel.Tag)
|
|
}
|
|
if a, ok := rel.FindAsset("a.exe"); !ok || a.URL != "https://x/a.exe" {
|
|
t.Errorf("asset = %+v %v", a, ok)
|
|
}
|
|
if _, ok := rel.FindAsset("missing"); ok {
|
|
t.Error("unexpected asset")
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLatestUnreachable(t *testing.T) {
|
|
srv := httptest.NewServer(http.NotFoundHandler())
|
|
url := srv.URL
|
|
srv.Close()
|
|
if _, err := Latest(context.Background(), nil, url); err == nil {
|
|
t.Error("expected error for unreachable server")
|
|
}
|
|
}
|
|
|
|
func TestLatestBadURL(t *testing.T) {
|
|
if _, err := Latest(context.Background(), nil, "://bad"); err == nil {
|
|
t.Error("expected error for bad URL")
|
|
}
|
|
}
|