| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "net/http" |
| 6 | "net/http/httptest" |
| 7 | "sync/atomic" |
| 8 | "testing" |
| 9 | |
| 10 | "reasonix/internal/servecontract" |
| 11 | "reasonix/internal/session" |
| 12 | ) |
| 13 | |
| 14 | func TestRemoteHistoryOutlineCapabilityCutAndFailure(t *testing.T) { |
| 15 | var reads atomic.Int32 |
| 16 | var fail atomic.Bool |
| 17 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 18 | reads.Add(1) |
| 19 | q := r.URL.Query() |
| 20 | if r.URL.Path != "/session-history/outline" || q.Get("sessionId") != "canonical" || q.Get("generation") != "cut" || q.Get("snapshotSequence") != "9" || q.Get("startTurn") != "129" || q.Get("limit") != "128" { |
| 21 | t.Errorf("unexpected outline request: %s", r.URL) |
| 22 | } |
| 23 | if fail.Load() { |
| 24 | http.Error(w, "offline", http.StatusServiceUnavailable) |
| 25 | return |
| 26 | } |
| 27 | _ = json.NewEncoder(w).Encode(session.HistoryOutlinePage{Status: "ready", Generation: "cut", SnapshotSequence: 9, TotalTurns: 200}) |
| 28 | })) |
| 29 | defer server.Close() |
| 30 | app, tab := historyWindowFixture(server) |
| 31 | cut := uint64(9) |
| 32 | req := session.HistoryOutlineRequest{Generation: "cut", SnapshotSequence: &cut, StartTurn: 129, Limit: 128} |
| 33 | page, err := app.RemoteSessionHistoryOutlineForTab(tab.id, req) |
| 34 | if err != nil || page.Status != "unsupported" || reads.Load() != 0 { |
| 35 | t.Fatalf("capability: %+v %v reads=%d", page, err, reads.Load()) |
| 36 | } |
| 37 | tab.capabilities[servecontract.HistoryOutlineV1] = true |
| 38 | page, err = app.RemoteSessionHistoryOutlineForTab(tab.id, req) |
| 39 | if err != nil || page.Status != "ready" || page.Entries == nil { |
| 40 | t.Fatalf("ready: %+v %v", page, err) |
| 41 | } |
| 42 | fail.Store(true) |
| 43 | if _, err := app.RemoteSessionHistoryOutlineForTab(tab.id, req); err == nil { |
| 44 | t.Fatal("network failure must remain retryable") |
| 45 | } |
| 46 | if reads.Load() != 2 { |
| 47 | t.Fatalf("unexpected fallback: %d reads", reads.Load()) |
| 48 | } |
| 49 | } |
| 50 |