Files
magpie/internal/sessions/save_test.go
T
yetone 6df6de1010 sessions: the indexing show no longer comes back on every visit — the index is written after the read, in the background, and not counted as indexing (Image #15: 这个还是会出现无数次)
Each visit re-reads the few session files agents appended to since the last
read, which takes milliseconds. But refresh() then saved the whole ~20 MB
~/.cache/magpie/sessions.json before clearing the indexing flag, and that
save took over a second, so /api/sessions/progress said "indexing" past the
0.7s threshold and the hero played every time. The flag now drops as soon as
the parse ends; the index is written from a snapshot (parses are never
changed in place, so a shallow clone is safe) by one background writer that
coalesces saves. Reset and the CLI's exit wait for the write.

Tested: TestSaveBehindTheRead holds the save open and requires List to
return and Indexing to be off meanwhile, then the file to be written (fails
with the synchronous save). Against a copy of the real index (196 sessions)
the flag stayed on at most 22ms per visit. go test -race ./internal/sessions,
go test -tags nogui ./... (TestAddSecondOfPreset flaky, passes alone), go build
-tags nogui (and GOOS=linux, GOOS=windows), go build ./..., and the GUI tests
sessions-overview, old-webkit, menu-scroll, click-scroll pass. Not tried in the
real Wails window.
2026-09-30 02:07:50 +08:00

55 lines
1.3 KiB
Go

package sessions
import (
"encoding/json"
"os"
"sync"
"testing"
"time"
)
// Writing the whole index to disk takes a second or more for a long
// history; a read of a few changed files neither waits on it nor counts it
// as indexing, or the page shows its indexing show for every catch-up read
// (Image #15: the show came back again and again at 3 of 3 files read).
func TestSaveBehindTheRead(t *testing.T) {
setup(t)
release := make(chan struct{})
writing := make(chan struct{}, 8)
var once sync.Once
let := func() { once.Do(func() { close(release) }) }
saveHook = func() { writing <- struct{}{}; <-release }
t.Cleanup(func() { let(); saveHook = nil })
done := make(chan []Session)
go func() { done <- List(0) }()
select {
case <-writing:
case <-time.After(5 * time.Second):
t.Fatal("no save started")
}
var list []Session
select {
case list = <-done:
case <-time.After(5 * time.Second):
t.Fatal("the read waited on the save")
}
if len(list) == 0 {
t.Fatal("no sessions read")
}
if Indexing().Indexing {
t.Fatal("still indexing while the index is saved")
}
// the save lands once let go, and a new load waits for it
let()
Saved()
b, err := os.ReadFile(CachePath())
if err != nil {
t.Fatal(err)
}
var kept cacheFile
if json.Unmarshal(b, &kept) != nil || len(kept.Files) == 0 {
t.Fatalf("cache file: %.200s", b)
}
}