test(bruno): sweep the collection against the actual route table

Audited every request (247 .yml files) against the routes the server
actually registers (extracted from internal/router, group prefixes
resolved). Results:

- 44 stale requests: deleted where the endpoint no longer exists
  (universal-progress GET/PUT /api/progress/:id — routes never existed,
  the handlers were deleted in H1; queue stats/clear-failed/process;
  admin profile page; auth/account) and FIXED where the endpoint exists
  under a different path (kobo token-in-path scheme: every
  /api/sync/kobo/<seg> and /api/v1/kobo/<seg> URL now carries
  {{kobo_device_token}}; /sync/* missing their /api prefix; koreader
  /api/v1/koreader/sync/* -> /api/sync/koreader/*; link-book and
  unlinked-books moved to /api/devices/:id/sync/*).
- koreader Sync Highlights/Sync Notes pointed at endpoints that never
  existed with a body shape to match — rewritten against POST
  /api/sync/koreader/bookmarks (the annotations funnel carries
  highlights and notes arrays).
- 9 files the GUI refused to load: 4 had bruno-invalid script type
  "tests" (converted to after-response), 4 were info/type:collection
  doc files with bogus http blocks (converted to folder.yml folder
  docs), 1 had a dead pre-YAML schema and no route (deleted).
- devices/koreader requests now carry request-level bearer auth
  ({{koreader_device_token}}) — they inherited the collection's user-JWT
  bearer, which device endpoints rightly reject — and their bodies
  reference {{media_item_id}} instead of dead placeholder uuids.
- environments: opds_base_url was empty (every OPDS request missed the
  /opds prefix); set to http://localhost:8765/opds and un-doubled the
  prefix in opds/scenarios.

Known limitation, for the handoff: bru CLI cannot execute .yml request
bodies (the collection is GUI OpenCollection format; the CLI runner
reads bodies from .bru files only). A .bru migration is the remaining
bruno work if CLI runs are wanted.
This commit is contained in:
John O'Keefe committed 2026-10-17 11:49:28 -04:00
1 parent 6808c1babb
commit a85bc8af9b
65 files changed
+409 -2127

No files matched your search

@@ -8,40 +8,9 @@ http:
auth: inherit
body:
type: json
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"name\": \"My Favorites\"\
,\n \"icon\": \"⭐\",\n \"description\": \"My favorite books\",\n \"show_on_dashboard\"\
: true,\n \"auto_assign_rules\": \"\",\n \"manual_book_ids\": [\"{{media_item_id}}\"\
],\n \"match_type\": \"all\"\n}"
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"name\": \"My Favorites\",\n \"icon\": \"⭐\",\n \"description\": \"My favorite books\",\n \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"\",\n \"manual_book_ids\": [\"{{media_item_id}}\"],\n \"match_type\": \"all\"\n}"
runtime:
scripts:
- type: tests
code: "test(\"status must be 201 with valid request\", function() {\n expect(res.status).to.eql(201);\n\
});\n\ntest(\"response contains collection id\", function() {\n expect(res.body.id).to.exist;\n\
expect(res.body.id).to.be.a('string');\n });\n\ntest(\"response contains\
\ collection name\", function() {\n expect(res.body.name).to.eql(\"My Favorites\"\
);\n });"
docs: |-
Create a custom collection with manually selected books.
**Endpoint**: POST /api/collections
**Auth**: Required (Bearer token)
## Example Request
```json
{
"library_id": "cc23c3a7-f8fb-451a-a78d-2a16df1b725a",
"name": "My Favorites",
"icon": "⭐",
"description": "My favorite books",
"show_on_dashboard": true,
"auto_assign_rules": "",
"manual_book_ids": ["book-id-1", "book-id-2"],
"match_type": "all"
}
```
## Response
Returns the created collection with generated ID.
- type: after-response
code: "function onResponse(res) {\ntest(\"status must be 201 with valid request\", function() {\n expect(res.status).to.eql(201);\n});\n\ntest(\"response contains collection id\", function() {\n expect(res.body.id).to.exist;\nexpect(res.body.id).to.be.a('string');\n });\n\ntest(\"response contains collection name\", function() {\n expect(res.body.name).to.eql(\"My Favorites\");\n });\n}"
docs: "Create a custom collection with manually selected books.\n\n**Endpoint**: POST /api/collections\n**Auth**: Required (Bearer token)\n\n## Example Request\n\n```json\n{\n \"library_id\": \"cc23c3a7-f8fb-451a-a78d-2a16df1b725a\",\n \"name\": \"My Favorites\",\n \"icon\": \"⭐\",\n \"description\": \"My favorite books\",\n \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"\",\n \"manual_book_ids\": [\"book-id-1\", \"book-id-2\"],\n \"match_type\": \"all\"\n}\n```\n\n## Response\n\nReturns the created collection with generated ID."