This repository has been archived on 2026-10-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
submarine/internal/update/update_test.go
T
simonfrankenandClaude Opus 5.5 1ee394cfdf Move releases to GitHub, with one bridge release on Gitea
GitHub has no generic package registry, so releases become GitHub
release assets. The updater and install.sh read releases/latest/download
and releases/download/<v>/, plain redirects with no API rate limit.
make release publishes a draft with all assets, then makes it latest.
make release-gitea publishes the same version to the old Gitea registry
for binaries that still update from there, and refuses until GitHub
serves it. See D33.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:38:50 +01:00

116 lines
3.3 KiB
Go

package update
import (
"context"
"crypto/sha256"
"encoding/hex"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
)
func TestNewer(t *testing.T) {
cases := []struct {
cur, latest string
want bool
}{
{"v0.1.0", "v0.2.0", true},
{"v0.2.0", "v0.2.0", false},
{"v0.10.0", "v0.9.0", false},
{"v1.0.0", "v0.9.9", false},
{"dev", "v0.1.0", true},
{"v0.1.0-3-gabc", "v0.1.0", true},
{"v0.1.0", "garbage", false},
}
for _, c := range cases {
if got := Newer(c.cur, c.latest); got != c.want {
t.Errorf("Newer(%q, %q) = %v, want %v", c.cur, c.latest, got, c.want)
}
}
}
// registry mimics GitHub releases: every asset URL redirects to storage.
func registry(t *testing.T, bin, sum string) *Client {
t.Helper()
mux := http.NewServeMux()
redirect := func(from, to string) {
mux.HandleFunc(from, func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, to, http.StatusFound)
})
}
redirect("/latest/download/VERSION", "/assets/VERSION")
redirect("/download/v0.2.0/checksums.txt", "/assets/checksums.txt")
redirect("/download/v0.2.0/submarine_linux_arm64", "/assets/submarine_linux_arm64")
mux.HandleFunc("/assets/VERSION", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("v0.2.0\n"))
})
mux.HandleFunc("/assets/checksums.txt", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte(sum + " submarine_linux_arm64\n"))
})
mux.HandleFunc("/assets/submarine_linux_arm64", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte(bin))
})
srv := httptest.NewServer(mux)
t.Cleanup(srv.Close)
return &Client{BaseURL: srv.URL, HTTP: srv.Client(), GOOS: "linux", GOARCH: "arm64"}
}
func sha(s string) string { h := sha256.Sum256([]byte(s)); return hex.EncodeToString(h[:]) }
func TestLatest(t *testing.T) {
c := registry(t, "x", sha("x"))
v, err := c.Latest(context.Background())
if err != nil || v != "v0.2.0" {
t.Fatalf("Latest = %q, %v", v, err)
}
}
func TestInstallReplaces(t *testing.T) {
dir := t.TempDir()
target := filepath.Join(dir, "submarine")
os.WriteFile(target, []byte("old"), 0o755)
c := registry(t, "new-binary", sha("new-binary"))
if err := c.InstallTo(context.Background(), "v0.2.0", target); err != nil {
t.Fatal(err)
}
got, _ := os.ReadFile(target)
if string(got) != "new-binary" {
t.Fatalf("target = %q", got)
}
if fi, _ := os.Stat(target); fi.Mode().Perm()&0o111 == 0 {
t.Error("target not executable")
}
if entries, _ := os.ReadDir(dir); len(entries) != 1 {
t.Errorf("leftover files: %v", entries)
}
}
func TestInstallChecksumMismatch(t *testing.T) {
dir := t.TempDir()
target := filepath.Join(dir, "submarine")
os.WriteFile(target, []byte("old"), 0o755)
c := registry(t, "tampered", sha("original"))
err := c.InstallTo(context.Background(), "v0.2.0", target)
if err == nil || !strings.Contains(err.Error(), "checksum mismatch") {
t.Fatalf("err = %v", err)
}
if got, _ := os.ReadFile(target); string(got) != "old" {
t.Errorf("target modified: %q", got)
}
if entries, _ := os.ReadDir(dir); len(entries) != 1 {
t.Errorf("temp file left behind: %v", entries)
}
}
func TestInstallMissingAsset(t *testing.T) {
c := registry(t, "x", sha("x"))
c.GOARCH = "riscv64"
err := c.InstallTo(context.Background(), "v0.2.0", filepath.Join(t.TempDir(), "submarine"))
if err == nil {
t.Fatal("expected error")
}
}