Status: Active | Owner: @roof | Applies to: main (2026-06) | Updated: 2026-06-11
Dev – Testing
Running tests
# Run on: your development machine, from the repo root
make test # pytest unit tests (excludes e2e and integration)
make test-coverage # with coverage; HTML report in htmlcov/
make test-api # API endpoint tests only
All unit tests pass without a running stack. CI (Gitea Actions) runs the unit suite on every push.
Test layout
tests/ Unit and API endpoint tests; no services required
tests/integration/ Require a running PIC stack
tests/e2e/ Playwright UI and WireGuard end-to-end tests
Unit tests
The unit suite covers manager classes, route handlers, and utility functions. Tests use unittest.mock / pytest-mock for all Docker SDK calls, filesystem writes, and subprocess invocations.
Important rule: when testing write-failure paths, mock builtins.open with side_effect=OSError. Do not rely on unwritable host paths — CI may run as root and can create any path.
The unit suite has approximately 3,218 tests as of mid-2026 (run make test to see the current count).
Integration tests
# Run on: your development machine, against a running make start stack
make test-integration # full suite; modifies cell state
make test-integration-readonly # read-only checks; safe to run at any time
These tests create peers, install services, and change configuration. Run them against a development cell, not production.
End-to-end tests
# Run on: your development machine
make test-e2e-deps # install Playwright and browser binaries (run once)
make test-e2e-api # API-level e2e tests
make test-e2e-ui # Browser-level UI tests via Playwright
The Playwright tests drive a real browser against a running stack. test-e2e-ui tests include WireGuard tunnel tests that require actual WireGuard kernel support.
What to test
- Every new API endpoint needs at least one test: happy path, auth failure (401), and the expected error case.
- Every new manager method needs a test that mocks its external dependencies (Docker, filesystem, subprocess).
- Do not test Flask routing boilerplate or trivial getters. Test behaviour and invariants.
- Do not add tests for things that are covered clearly by the code itself — only add tests when the behaviour is non-obvious or the failure mode matters.
CI
Gitea Actions runs the unit suite on every push using the self-hosted runner VMs (gitea-action0 trusted, gitea-action1 sacrificial for untrusted builds). The workflow file calls:
# Run by: Gitea Actions on the gitea-action0 runner
pytest tests/ --ignore=tests/e2e --ignore=tests/integration
Image builds (for the email, calendar, and files service images) run on path-filtered pushes to the pic-services repository.
Webui tests
# Run on: your development machine, from the webui/ directory
cd webui && npm run test # vitest unit tests
The webui unit tests cover React component logic and the Axios client wrapper. They do not require a running API.
Personal Internet Cell
New here?
Users
User – Connect to the VPN User – Use Your Services User – Troubleshooting
Admins
Admin – Overview Admin – Install and First Run Admin – Configure Domains and TLS Admin – Manage Services Admin – Configure Connectivity Admin – Manage Peers Admin – Back Up and Restore Admin – Logging and Audit Admin – Monitor and Troubleshoot
Developers
Dev – Overview Dev – Architecture Dev – Build a Store Service Dev – Service Manifest Reference Dev – API Reference Dev – Testing Dev – Install Internals
Decisions (ADRs)
ADR – 001 Store Images Are Signed and Verified by Cells ADR – 002 Named Connection Instances for Connectivity ADR – 003 All Optional Functionality Ships as Store Services
Meta
Meta – Glossary Meta – Template Runbook Meta – Template ADR
Archive
Archive – User Guide Archive – ADR 004 The Wiki Is the Single Documentation Source