#910: the header's Update sheet said "Update to v0.1.1020" with v0.1.1024 out. The sheet shows the update the updater downloaded at its last look at the feed, which is every six hours by default (Settings' UpdateEvery), and releases come several a day; usemagpie.ai's feed was current (it answers v0.1.1031 now). The restart itself already asked the feed again (recheck), so only the sheet was behind. Now GET /api/update/notes first asks the feed again, as the restart does, when a version is downloaded and waiting and the feed was last asked over five minutes ago; a newer release starts downloading and the restart waits for it, as one after a recheck does. The answer carries latest, and the sheet retitles itself "Update to v<newest>" with every release's notes up to it. TestUpdateNotesAskTheFeedAgain (a download of 0.1.1020 three hours old, a feed at 0.1.1024: the answer names 0.1.1024 with both releases' notes; asked a moment ago, the feed isn't asked) and update-notes-ask.test.cjs' new case (the sheet names v0.1.403 and lists three releases when the notes name it) fail without the change. #868 (Hu9956): once Names & levels was open (to set Provider in model names) it couldn't be closed: the only way was its button under the list, out of sight below it, and naming is page state, so it stayed open in every provider editor after until magpie restarted. Now the open list has a quiet title (Names & levels) and Fold at its top, held there while its rows scroll; Fold folds it, the button under the list reads off again and takes the focus, nothing scrolls. An editor opened afresh (no draft yet) has it folded; one redrawn keeps it as it was. en/zh/ja/de ("Fold", "Fold Names & levels"). names-fold.test.cjs (WebKit, en/zh/ja/de: opens folded, the title and Fold, Fold stays at the top while the rows scroll, picking Not on names I set leaves it open and foldable, Fold folds it and turns the button off without scrolling, no left border, a fresh editor opens folded, no select) fails on the old code; name-suffix-where-named, model-price-edit, provider-levels-save, provider-same-as, provider-detect, provider-detect-models, readable-focus and click-scroll pass in WebKit; model-api-preset and provider-levels-scroll fail the same on origin/main. The editor's other fields aren't regrouped. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass (TestUserPath and TestClaudeSignedOut timed out once under load and pass alone).
138 lines
5.1 KiB
Go
138 lines
5.1 KiB
Go
package gui
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/yetone/magpie/internal/update"
|
|
)
|
|
|
|
// Before an update is put in, the page asks what changed (Hu9956, #844):
|
|
// every release after this one up to the update's, newest first, without
|
|
// their Install sections; the site's list out of reach, the update's own
|
|
// notes; no update, none.
|
|
func TestUpdateNotesRoute(t *testing.T) {
|
|
feed := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Query().Get("after") != "0.1.604" || r.URL.Query().Get("upto") != "0.1.607" {
|
|
t.Errorf("asked %s", r.URL.RawQuery)
|
|
}
|
|
json.NewEncoder(w).Encode(map[string]any{"releases": []update.Note{
|
|
{Version: "0.1.607", Notes: "- seven\n\n### Install\n\nlinks"},
|
|
{Version: "0.1.606", Notes: "- six"},
|
|
{Version: "0.1.605", Notes: "- five"},
|
|
{Version: "0.1.604", Notes: "- four"},
|
|
}})
|
|
}))
|
|
defer feed.Close()
|
|
t.Setenv("MAGPIE_NOTES_FEED", feed.URL)
|
|
t.Setenv("MAGPIE_UPDATE_FEED", "http://127.0.0.1:1/")
|
|
oldV, oldState, oldLatest, oldIn := Version, updates.state, updates.latest, updates.notesIn
|
|
defer func() { Version, updates.state, updates.latest, updates.notesIn = oldV, oldState, oldLatest, oldIn }()
|
|
Version = "0.1.604"
|
|
updates.mu.Lock()
|
|
updates.state, updates.latest, updates.notesIn = "ready", &update.Release{Version: "0.1.607", Notes: "- seven only"}, "en"
|
|
updates.mu.Unlock()
|
|
mux := http.NewServeMux()
|
|
updateRoutes(mux, nil)
|
|
get := func() (out struct {
|
|
Releases []update.Note `json:"releases"`
|
|
Error string `json:"error"`
|
|
}) {
|
|
rw := httptest.NewRecorder()
|
|
mux.ServeHTTP(rw, httptest.NewRequest("GET", "/api/update/notes?lang=en", nil))
|
|
if rw.Code != 200 {
|
|
t.Fatalf("%d %s", rw.Code, rw.Body)
|
|
}
|
|
json.Unmarshal(rw.Body.Bytes(), &out)
|
|
return out
|
|
}
|
|
j := get()
|
|
var vs []string
|
|
for _, n := range j.Releases {
|
|
vs = append(vs, n.Version)
|
|
}
|
|
if len(vs) != 3 || vs[0] != "0.1.607" || vs[2] != "0.1.605" || j.Releases[0].Notes != "- seven" {
|
|
t.Fatalf("between: %+v", j)
|
|
}
|
|
|
|
// the site's list out of reach: the update's own notes
|
|
t.Setenv("MAGPIE_NOTES_FEED", "http://127.0.0.1:1/")
|
|
if j := get(); len(j.Releases) != 1 || j.Releases[0].Version != "0.1.607" || j.Releases[0].Notes != "- seven only" {
|
|
t.Fatalf("fallback: %+v", j)
|
|
}
|
|
|
|
// no update: no notes
|
|
updates.mu.Lock()
|
|
updates.state, updates.latest = "latest", nil
|
|
updates.mu.Unlock()
|
|
if j := get(); len(j.Releases) != 0 || j.Error != "" {
|
|
t.Fatalf("none: %+v", j)
|
|
}
|
|
}
|
|
|
|
// The dialog asks the feed again when it was last asked a while ago (#910,
|
|
// Moody-Sin: it stopped at v0.1.1020, downloaded hours before, with
|
|
// v0.1.1024 out): the newest release is the one it names, with the notes
|
|
// of every release up to it.
|
|
func TestUpdateNotesAskTheFeedAgain(t *testing.T) {
|
|
feedAsked := 0
|
|
feed := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
feedAsked++
|
|
json.NewEncoder(w).Encode(update.Release{Version: "0.1.1024", Notes: "- twenty-four"})
|
|
}))
|
|
defer feed.Close()
|
|
notes := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
upto := r.URL.Query().Get("upto")
|
|
all := []update.Note{{Version: "0.1.1024", Notes: "- twenty-four"}, {Version: "0.1.1020", Notes: "- twenty"}}
|
|
if upto == "0.1.1020" {
|
|
all = all[1:]
|
|
}
|
|
json.NewEncoder(w).Encode(map[string]any{"releases": all})
|
|
}))
|
|
defer notes.Close()
|
|
t.Setenv("MAGPIE_UPDATE_FEED", feed.URL)
|
|
t.Setenv("MAGPIE_NOTES_FEED", notes.URL)
|
|
updates.mu.Lock()
|
|
oldState, oldStaged, oldIn, oldLatest, oldAsked, oldV := updates.state, updates.staged, updates.notesIn, updates.latest, updates.asked, Version
|
|
Version = "0.1.1010"
|
|
// downloaded hours ago; this test's updater can't replace the app, so
|
|
// the newer release is left "available" rather than downloaded
|
|
updates.state, updates.staged, updates.notesIn = "ready", filepath.Join(t.TempDir(), "staged"), "en"
|
|
updates.latest, updates.asked = &update.Release{Version: "0.1.1020", Notes: "- twenty"}, time.Now().Add(-3*time.Hour)
|
|
updates.mu.Unlock()
|
|
defer func() {
|
|
updates.mu.Lock()
|
|
updates.state, updates.staged, updates.notesIn, updates.latest, updates.asked, Version = oldState, oldStaged, oldIn, oldLatest, oldAsked, oldV
|
|
updates.mu.Unlock()
|
|
}()
|
|
mux := http.NewServeMux()
|
|
updateRoutes(mux, nil)
|
|
get := func() (out struct {
|
|
Latest string `json:"latest"`
|
|
Releases []update.Note `json:"releases"`
|
|
}) {
|
|
rw := httptest.NewRecorder()
|
|
mux.ServeHTTP(rw, httptest.NewRequest("GET", "/api/update/notes?lang=en", nil))
|
|
json.Unmarshal(rw.Body.Bytes(), &out)
|
|
return out
|
|
}
|
|
if j := get(); j.Latest != "0.1.1024" || len(j.Releases) != 2 || j.Releases[0].Version != "0.1.1024" {
|
|
t.Fatalf("stale: %+v", j)
|
|
}
|
|
|
|
// asked a moment ago: not again
|
|
updates.mu.Lock()
|
|
updates.state, updates.staged = "ready", filepath.Join(t.TempDir(), "staged")
|
|
updates.latest, updates.asked = &update.Release{Version: "0.1.1020", Notes: "- twenty"}, time.Now()
|
|
updates.mu.Unlock()
|
|
feedAsked = 0
|
|
if j := get(); j.Latest != "0.1.1020" || feedAsked != 0 || !strings.Contains(j.Releases[0].Notes, "twenty") {
|
|
t.Fatalf("fresh: %+v, feed asked %d", j, feedAsked)
|
|
}
|
|
}
|