The updater reports each step (checking, downloading with percent, verifying, installing, restarting). Edges and sites send that progress and their log with their reports; Hammerhead serves it to a dialog that opens when an update starts, and keeps its own last update log on disk across the restart. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
91 lines
2.8 KiB
Go
91 lines
2.8 KiB
Go
package hammerhead
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCheckForUpdates(t *testing.T) {
|
|
gitea := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/api/v1/repos/Veillax/hammerhead/releases/latest" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
fmt.Fprint(w, `{"tag_name":"v0.3.0","prerelease":false,"assets":[]}`)
|
|
}))
|
|
defer gitea.Close()
|
|
for _, c := range []struct {
|
|
version string
|
|
newer bool
|
|
}{{"v0.2.0", true}, {"v0.3.0", false}, {"dev", false}} {
|
|
s, err := New(t.TempDir(), Options{AdminEmail: "admin@test.local", AdminPassword: "password123", MasterKey: key,
|
|
Version: c.version, UpdateServer: gitea.URL, UpdateRepo: "Veillax/hammerhead", AutoUpdate: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
do := apiClient(t, s)
|
|
code, b := do("GET", "/api/admin/update", nil)
|
|
var out struct {
|
|
Current, Latest, Error string
|
|
Newer, AutoUpdate bool
|
|
}
|
|
json.Unmarshal(b, &out)
|
|
if code != 200 || out.Current != c.version || out.Latest != "v0.3.0" || out.Newer != c.newer || !out.AutoUpdate || out.Error != "" {
|
|
t.Errorf("%s: %d %s", c.version, code, b)
|
|
}
|
|
s.Close()
|
|
}
|
|
|
|
// an unreachable release server is reported, not fatal
|
|
s, err := New(t.TempDir(), Options{AdminEmail: "admin@test.local", AdminPassword: "password123", MasterKey: key, Version: "v0.1.0", UpdateServer: "http://127.0.0.1:1"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer s.Close()
|
|
code, b := apiClient(t, s)("GET", "/api/admin/update", nil)
|
|
var out struct{ Error string }
|
|
json.Unmarshal(b, &out)
|
|
if code != 200 || out.Error == "" {
|
|
t.Errorf("unreachable server: %d %s", code, b)
|
|
}
|
|
}
|
|
|
|
func TestSelfUpdateLogSurvivesTheRestartItEndsWith(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(dir, "update.log"), []byte("12:00:00 Checking\n12:00:09 Installed v0.3.0; restarting into it\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := New(dir, Options{AdminEmail: "admin@test.local", AdminPassword: "password123", MasterKey: key, Version: "v0.3.0"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer s.Close()
|
|
do := apiClient(t, s)
|
|
code, b := do("GET", "/api/admin/update/status", nil)
|
|
var out struct {
|
|
Running bool
|
|
Stage string
|
|
Pct int
|
|
Lines []string
|
|
Version string
|
|
}
|
|
json.Unmarshal(b, &out)
|
|
last := ""
|
|
if len(out.Lines) > 0 {
|
|
last = out.Lines[len(out.Lines)-1]
|
|
}
|
|
if code != 200 || out.Running || out.Stage != "done" || out.Pct != 100 || len(out.Lines) != 3 || !strings.Contains(last, "now running v0.3.0") {
|
|
t.Fatalf("status: %d %s", code, b)
|
|
}
|
|
// starting an update needs auto-update on
|
|
if code, b := do("POST", "/api/admin/update/apply", nil); code != 400 || !strings.Contains(string(b), "HAMMERHEAD_AUTO_UPDATE") {
|
|
t.Fatalf("apply without auto-update: %d %s", code, b)
|
|
}
|
|
}
|