ComfyUI/tests-unit/assets_test
Matt Miller 33109e0a04
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
feat(jobs): cursor-based pagination on GET /api/jobs (BE-943) (#14363)
* refactor(pagination): hoist cursor codec to utils/ for cross-domain reuse

The keyset cursor codec was asset-namespaced (app/assets/services/cursor.py)
but the wire format and encode/decode logic are domain-agnostic. Move it to
utils/cursor.py so the jobs endpoint can share one codec instead of importing
across domains or duplicating it.

* feat(jobs): cursor-based pagination on GET /api/jobs (BE-943)

Mirror the cloud jobs cursor (BE-885) on the OSS Python server so the
frontend sees one contract across runtimes.

- apply_sorting now appends the job id as a tiebreaker, making (create_time,
  id) a stable keyset; without it, ties could reorder between pages.
- get_all_jobs accepts an opaque 'after' cursor (honored only for created_at
  sort, like cloud), keyset-filters the sorted in-memory list, and returns
  has_more + a next_cursor. Minted in offset mode too so a client can bootstrap
  into keyset pagination.
- server.py /api/jobs parses 'after', returns next_cursor in the pagination
  object, and maps a malformed cursor to 400 INVALID_CURSOR.
- Reuses the shared utils.cursor codec (base64url JSON {s,v,id,o}) so the wire
  format matches cloud and assets exactly.

Tests: asc/desc multi-page round-trip, same-create_time tiebreaker, last-page
no-cursor, offset-mode bootstrap, execution_duration ignores cursor, malformed
cursor raises.

* refactor(jobs): return NamedTuple page, early-out on empty job set

Review feedback on the jobs cursor pagination:
- get_all_jobs now returns JobsPage, a NamedTuple, instead of a bare
  4-tuple (callers unpack positionally either way).
- Early-out when the filtered job set is empty so paging code never has
  to reason about indexing into an empty list. A malformed 'after'
  cursor is still decoded first and rejected with INVALID_CURSOR.
- Document that job ids are server-assigned UUIDs, always present and
  unique — the empty-string fallback in _job_id_key only shields
  sorted() from a malformed dict, it is not part of the keyset
  contract.
2026-06-09 21:28:25 -07:00
..
queries Merge branch 'master' into matt/be-944-core-cursor-based-pagination-for-get-apiassets 2026-06-09 21:07:47 -07:00
services feat(jobs): cursor-based pagination on GET /api/jobs (BE-943) (#14363) 2026-06-09 21:28:25 -07:00
conftest.py Emit hash alongside asset_hash on all Asset responses (#13739) 2026-05-25 11:21:35 -07:00
helpers.py Emit hash alongside asset_hash on all Asset responses (#13739) 2026-05-25 11:21:35 -07:00
test_assets_missing_sync.py Emit hash alongside asset_hash on all Asset responses (#13739) 2026-05-25 11:21:35 -07:00
test_crud.py Emit hash alongside asset_hash on all Asset responses (#13739) 2026-05-25 11:21:35 -07:00
test_downloads.py refactor(assets): modular architecture + async two-phase scanner & background seeder (#12621) 2026-03-07 20:37:25 -05:00
test_file_utils.py refactor(assets): modular architecture + async two-phase scanner & background seeder (#12621) 2026-03-07 20:37:25 -05:00
test_list_cursor.py fix(assets): address ultrareview findings on cursor pagination 2026-05-21 14:29:27 -07:00
test_list_filter.py Emit hash alongside asset_hash on all Asset responses (#13739) 2026-05-25 11:21:35 -07:00
test_metadata_filters.py Assets Part 2 - add more endpoints (#12125) 2026-01-31 02:22:05 -05:00
test_prune_orphaned_assets.py refactor(assets): modular architecture + async two-phase scanner & background seeder (#12621) 2026-03-07 20:37:25 -05:00
test_sync_references.py chore(assets): drop vestigial tags.tag_type column (#14248) 2026-06-09 21:07:10 -07:00
test_tags_api.py refactor(assets): modular architecture + async two-phase scanner & background seeder (#12621) 2026-03-07 20:37:25 -05:00
test_uploads.py Emit hash alongside asset_hash on all Asset responses (#13739) 2026-05-25 11:21:35 -07:00