Skip to content

Running the tests

The daemon suite

Pure CPython, no external services, localhost HTTP only.

cd daemon
../.venv/Scripts/python -m unittest discover -s tests -q

On macOS or Linux use ../.venv/bin/python.

Use the repository's .venv, not a global Python: it has the project and its test dependencies installed.

To run one group, one file, or one class (from daemon/):

../.venv/Scripts/python -m unittest discover -s tests/providers -t tests -q
../.venv/Scripts/python -m unittest discover -s tests/providers -t tests -p test_sources.py -v
../.venv/Scripts/python -m unittest discover -s tests/providers -t tests -p test_sources.py -k OllamaTests -v

Keep -t tests when selecting a group so shared fixtures and cross-group imports resolve the same way as the full suite. Add -k test_method_name to select a single method instead of a class.

In VS Code, the Testing view groups the files under the folders below. Use Test: Refresh Tests after pulling the reorganization, then expand or run the area you need. Tasks: Run Task also offers Run all tests and Run test group, which prompts for a group.

What the suite covers

Area Where
Models, storage, quotas, configuration and alert thresholds tests/core/
Accounts, settings, sessions and admin routes tests/admin/
Provider clients, Claude readers, Codex and the source template tests/providers/
Remote ingest, pushed observations and the collector tests/ingest/
Presto UI, gestures, polling, alerts and the device API contract tests/device/
Input hardening, authentication, private files and HTTP boundaries tests/security/
Preview, USB sync, containers, health checks, documentation and licences tests/tooling/

Put new test files in the relevant group. Each group has an __init__.py so standard unittest discovery visits it. Shared helpers envutil.py and presto_path.py, and shared fixtures/, stay at the tests/ root. Import fixtures from other test modules by their group, for example from admin.test_management import ManagementBase.

The device payload guard

tests/device/test_device_payload.py is the test that keeps the device and the daemon honest about the payload. It proves:

  • the device draws exactly the same screens from the slim payload as from the full one,
  • the payload stays inside the size budget,
  • a quota report is sent once,
  • the admin-only fields never reach the device,
  • every key the device code reads is on the whitelist.

The whitelist scan parses the device's own source with ast and looks for the keys it reads. If you add a key to the device, add it to the DEVICE_*_KEYS constants in dashboard.py, or this test fails.

The size budget is 5000 bytes for one poll response and 1000 bytes per account within it (card detail has its own 8 KiB limit per request). It is a hard limit: the test fails the build when it is exceeded, and tests/core/test_demo.py holds every message the demo sends to the same limits.

The Presto tests

The Presto logic runs on the host too. Only presto/main.py needs real hardware. tests/device/test_presto_structure.py enforces the layering: only main.py and ui.py may import presto, machine, picographics or picovector.

The drawing tests use a stand-in display and check that text fits and does not overlap, in the firmware's own bitmap fonts.

The documentation site

The site is built with MkDocs and the Material theme, in its own virtual environment so the project environment is untouched:

python -m venv .venv-docs
.venv-docs/Scripts/python -m pip install -r docs/requirements.txt
.venv-docs/Scripts/mkdocs build --strict

On macOS or Linux use .venv-docs/bin/ in place of .venv-docs/Scripts/.

The strict build fails on a broken internal link, a page that is not in the navigation, or any warning at all. The site is written from docs/user/; the rest of docs/ is internal and is never published.

The external links are checked by lychee in CI. Locally, if lychee is installed:

lychee --no-progress --timeout 20 --max-retries 1 --exclude-loopback "docs/user/**/*.md"

After a build, tools/check_doc_anchors.py checks that every help link of the admin page points at an anchor that exists in the built site:

.venv/Scripts/python tools/check_doc_anchors.py

The demo checks

The documentation site's demo has two generated parts, and neither is committed: build them first.

.venv/Scripts/python tools/build_demo_site.py
node tools/check_demo_wasm.mjs

The first writes docs/user/demo/app/. The second loads the vendored MicroPython WebAssembly runtime in Node, checks that every app module imports, that Home and every card at every scene draw exactly the pixels CPython drew, and that a swipe and the Stale switch work. It fails, and does not skip, if the runtime cannot load. tests/tooling/test_demo_page.py runs it against a good build and against deliberately broken ones when Node is installed, and tests/core/test_demo.py fails when a registered source type has no demo account (see Demo data). In CI the Ubuntu Python 3.13 job builds and checks the demo, and the docs workflow builds it before mkdocs build --strict.

The browser checks

tools/check_admin_help_browser.py opens the admin page in a real browser, against a throwaway daemon on a temporary database, and checks the help links, the keyboard, the phone-width layout and the alert settings. The browser checks need Playwright, which is NOT needed for the test suite and is not a dependency of the project. Install it into a throwaway environment rather than into .venv:

python -m venv .venv-browser
.venv-browser/Scripts/python -m pip install playwright
.venv-browser/Scripts/python -m playwright install chromium
.venv-browser/Scripts/python tools/check_admin_help_browser.py
.venv-browser/Scripts/python tools/check_demo_browser.py

The throwaway daemon itself still runs with the repository's .venv; only the checker needs Playwright. Delete .venv-browser when you are done.

The demo checker verifies that two admin tabs follow the demo switch, that an old background response cannot undo a new setting, and that the browser demo loads, navigates, updates Home after a bell tap and recovers from a lost connection. It also runs the real Presto preview against sample data. Its screenshots are saved under .preview/demo-browser/; no live configuration or provider is used.

Before you call the work done

cd daemon && ../.venv/Scripts/python -m unittest discover -s tests -q

And, if you touched the Presto app, the device sync in the preview and the device sync.