fix(tests): repair stale pins surfaced by the Phase 6 full-suite run

Two suite failures, neither caused by scanner code (the Phase 6 diff
touches no handler):

- search_test invalid_library_id expected the pre-family-lens 404;
  7e586df4 shipped the AGENTS-mandated 403 for every out-of-set id
  (existence must not be enumerable) and docs/contract_pins.md:195
  documented it — this one subtest's expectation was missed. Pin
  widened to the shipped 403.
- TestWebSocketPingPong deleted: it asserted a text-level ping→pong
  exchange no server code has ever implemented and no client has ever
  sent; it passed vacuously through its read-timeout path until
  interleaved scan_progress broadcasts from the live server's scans
  reached the socket first. Keepalive is the standard protocol-level
  ping the hub already sends. Never-built behavior is not a pinnable
  contract.

Both recorded in docs/contract_pins.md. Full container suite is green
except the documented pre-existing TestAdminCreateUser red.
This commit is contained in:
John O'Keefe committed 2026-10-19 22:33:08 -04:00
1 parent 2c5ad014c0
commit 6152137156
3 files changed
+37 -35

No files matched your search

+9 -4
View File
@@ -413,10 +413,15 @@ func TestCollectionSearchLibraryFilter(t *testing.T) {
shouldContain: book2ID, shouldContain: book2ID,
}, },
{ {
name: "invalid library_id", name: "invalid library_id",
query: "Harry", query: "Harry",
libraryID: "00000000-0000-0000-0000-000000000000", libraryID: "00000000-0000-0000-0000-000000000000",
expectedStatus: http.StatusNotFound, // Family-lens standing rule (AGENTS.md): an explicit
// library_id outside the visible set is a 403, never a
// silent pass — and a nonexistent id is out-of-set too,
// so existence is not enumerable. Behavior shipped in
// 7e586df4 (Phase 1); this pin update was missed then.
expectedStatus: http.StatusForbidden,
}, },
} }
+8 -31
View File
@@ -157,37 +157,14 @@ func TestWebSocketProgressBroadcast(t *testing.T) {
assert.Equal(t, "web", sourceDevice["type"]) assert.Equal(t, "web", sourceDevice["type"])
} }
// TestWebSocketPingPong tests that ping/pong messages work correctly // TestWebSocketPingPong was deleted (2026-10-20, Phase 6 full-suite
func TestWebSocketPingPong(t *testing.T) { // repair): it asserted a TEXT-level {"type":"ping"} → {"type":"pong"}
setup := setupTestServer(t) // exchange that no server code has ever implemented and no client
// (web/src or Android) has ever sent — it passed vacuously through its
token := setup.Token // read-timeout path until interleaved scan_progress broadcasts started
// failing the assert. Keepalive is the standard protocol-level ping the
wsURL := strings.Replace(setup.Server.URL, "http", "ws", 1) + "/ws/sync?token=" + token // hub already sends (websocket.go's ticker); if a text-level app ping
ws, _, err := websocket.DefaultDialer.Dial(wsURL, nil) // is ever wanted, build it server-side first, then re-pin it.
require.NoError(t, err)
defer ws.Close()
// Read initial message
ws.SetReadDeadline(time.Now().Add(5 * time.Second))
_, _, _ = ws.ReadMessage()
// Send a ping message (as a text message for testing)
err = ws.WriteMessage(websocket.TextMessage, []byte(`{"type":"ping"}`))
require.NoError(t, err)
// Server should respond with pong
ws.SetReadDeadline(time.Now().Add(2 * time.Second))
_, msg, err := ws.ReadMessage()
if err == nil {
var pongMsg map[string]interface{}
err = json.Unmarshal(msg, &pongMsg)
if err == nil {
// Server might respond with pong
assert.Equal(t, "pong", pongMsg["type"])
}
}
}
// TestWebSocketConnectionLimit tests that the server handles multiple connections // TestWebSocketConnectionLimit tests that the server handles multiple connections
func TestWebSocketConnectionLimit(t *testing.T) { func TestWebSocketConnectionLimit(t *testing.T) {
+20
View File
@@ -237,3 +237,23 @@ cover_image_path, has_conflict, format_group, badge`.
- Watcher: a failed capability probe (one `Add` on a root folder) - Watcher: a failed capability probe (one `Add` on a root folder)
disables the watcher with ONE startup line instead of per-directory disables the watcher with ONE startup line instead of per-directory
warning spam. warning spam.
## 2026-10-20 — Stale pin repair (behavior shipped in 7e586df4)
- `GET /api/media-items/search` with an explicit `library_id` outside
the requesting user's visible set — INCLUDING a nonexistent id —
answers **403** (`library not accessible`), not 404. The family-lens
standing rule (AGENTS.md) mandates 403 for every out-of-set id so
library existence is not enumerable; Phase 1 (7e586df4) shipped it
and documented it here, but the `invalid library_id` subtest in
search_test.go still pinned the pre-family-lens 404. Pin widened to
the shipped 403; no server change (discovered during the Phase 6
full-suite run; the Phase 6 diff touches no handler code).
- `TestWebSocketPingPong` DELETED: it asserted a text-level
`{"type":"ping"}` → `{"type":"pong"}` exchange that no server code
has ever implemented and no client (web/src, Android) has ever sent.
It passed vacuously through its read-timeout path (deadline error
skipped the asserts) until interleaved `scan_progress` broadcasts
from the live server's scans started reaching the socket first.
Keepalive is the standard protocol-level ping the hub already sends.
Never-built behavior is not a pinnable contract.