Tests¶
python tests/run.py # everything
python tests/run.py multiuser # one suite
1,250 assertions across twenty-two suites, each in its own process against its
own throwaway database. Sample comics are generated on first run into
tests/.fixtures/.
Nothing reaches the network. The OAuth suite runs a fake provider, and the
Comic Vine and provider suites stub the API. A suite also blanks every
LONGBOX_* variable and the provider credential names before the application
is imported, including any a .env beside the repository would supply — so
running the tests on a configured host cannot reach that host's library or
spend its API keys. That was not always true: run on a deployment host, the
suites once wrote sample comics into a real upload folder and called Comic
Vine for real with the host's key.
requirements-dev.txt adds jsonschema, which validates the OPDS 2.0 output
and the Divina manifests against the published schemas vendored under
tests/schemas/. The suites run without it, and say on their first line what
stopped running rather than skipping quietly.
| Suite | Covers |
|---|---|
import |
filename parsing, every archive format, the import pipeline, the HTTP surface, uploads |
multiuser |
cross-account access on every route, browse permissions, admin boundaries, sessions, CSRF |
admin |
account setup links, password reset (admin link, self-service, CLI), token expiry/replay/supersession, account-enumeration resistance, every admin action and its permission boundary, the audit trail |
reader |
the manifest carrying URLs rather than bytes, page caching and eviction, progress, reading direction, and that one account cannot fetch another's pages |
convert |
metadata surviving a write-and-reimport round trip, pages compared byte for byte across containers, and a failed rewrite leaving the original intact |
identity |
every ComicInfo field surviving parse, import, storage and editing; portable ids including the migration backfill; integrity hashing catching a byte flipped deep inside a file |
backup |
snapshots taken while another connection is committing, verification, rotation, scheduling, and that backups are not downloadable |
migration |
upgrading a real single-user database, with the v1 schema pinned in tests/schema_v1.sql |
oauth |
the full authorization-code flow against a fake OIDC provider, including PKCE, replay, forged state, wrong audience, wrong issuer and expired tokens |
comicvine |
matching a series to a volume and a file to the right issue, that ambiguity is reported rather than guessed at, and that the issue picker never filters away the issue you are trying to correct to |
routes |
the same match routes answering for either metadata source, the legacy Comic Vine paths redirecting rather than breaking, and cross-account isolation on every one of them |
providers |
the source interface itself: Metron behind it end to end, per-account source order, and falling through sources with gaps filled from a later confident one without ever overwriting the primary's own fields |
skins |
the WCAG AA contrast check refusing a bad palette with the failing pairs named, the lifecycle rules (active/default cannot be deleted), and that the active skin reaches a signed-out page exactly as it reaches a signed-in one |
diskusage |
two configured paths on one physical device collapsing into a single reported figure, a missing or unreadable path failing on its own rather than the whole report, a slow lookup timing out rather than hanging, and both the admin and settings pages showing it |
opds |
Basic and per-account-token authentication answering 401 with a challenge rather than a redirect, token issue/revoke/reissue and their admin_log entries, throttling of guessed tokens, and that each account sees only its own root feed |
opds-catalogue |
the version-agnostic feed model and the query layer under it: pagination edges, a series listing sorting by issue rather than import order, facet active-marking and filter composition, and per-account isolation |
opds-atom |
the OPDS 1.2 serialiser checked by an internal conformance validator that is itself shown to catch broken feeds, and the real /opds routes over HTTP -- filters, search, pagination, the OpenSearch document, and cross-account 404s on the file and cover routes |
opds-json |
the OPDS 2.0 serialiser and the Divina manifests, validated against the published JSON schemas vendored under tests/schemas/ -- including the one deliberate deviation, a feed with no results, asserted as the schema's only complaint so it cannot hide a second bug |
formats |
every page image format IMAGE_EXTENSIONS accepts -- PNG, GIF, BMP, WebP, AVIF, JPEG XL -- reaching the cache under its own extension and being served as its own type, plus covers and thumbnails where a decoder exists, and PDF where pymupdf installs |
opds-pse |
page streaming: the {pageNumber} template counting from 0 while pse:lastRead counts from 1, progress clamped to a re-counted file, and the page route warming the cache once per comic rather than once per page turn |
proxy |
who Longbox believes the caller is behind a reverse proxy, against a real run.py process: a forged X-Forwarded-For ignored from anything but a configured proxy, and a client-prepended entry never outranking the one the proxy appended |
collected |
the two shapes a provider files a collected edition under, and what a volume marker in a filename gets matched to -- including the assertions that record a defect still to be fixed, and the issue rules a fix must not undo |
The isolation suite is the one to keep green: it asserts that a second account cannot read another's comic, cover, download, page image, job or search results, and cannot edit, delete or refresh them either.
What the suites cannot do¶
They import the code they are testing, so they prove the application correct
and say nothing about a deployment. tests/live_check.py walks a deployed
server's OPDS feed the way a client does, and is hand-run rather than a suite
because it is one of only two things under tests/ that touch the network
(the other is tests/schemas/update.py).
LONGBOX_CHECK_PASSWORD='...' python tests/live_check.py https://comics.example.com -u reader
A feed whose links all point at http://127.0.0.1:8080 validates perfectly
and is useless on a phone. Only this catches that. It also caught a server
running last release's code from a current checkout, because install.sh had
copied the files without restarting the service.