- AttributeError: OSTemplate has no 'template_vmid' field; the actual column is 'vmid'. - Use OSTemplate.get_vmid_for_node() to support cross-node replicated templates, falling back to source_node/vmid otherwise. - VMInstance.memory is stored in bytes, but Proxmox config expects MB.
88 lines
2.8 KiB
Markdown
88 lines
2.8 KiB
Markdown
# Backend Tests
|
|
|
|
Smoke / unit tests for the FastAPI backend, focused on the security-critical
|
|
modules: `app.crypto`, `app.auth`, `app.rbac`.
|
|
|
|
## Layout
|
|
|
|
```
|
|
backend/
|
|
├── pytest.ini # pytest config (testpaths=tests, markers, addopts)
|
|
├── requirements-dev.txt # test deps (-r requirements.txt + pytest …)
|
|
└── tests/
|
|
├── conftest.py # env setup + reusable fixtures
|
|
├── test_crypto.py # Fernet field-encryption helpers
|
|
├── test_auth.py # password hashing, JWT, IP parsing, perm helpers
|
|
└── test_rbac.py # PermissionEngine + registry
|
|
```
|
|
|
|
## How `conftest.py` keeps tests hermetic
|
|
|
|
The application reads configuration at import time:
|
|
|
|
- `app.config.Settings` is a `pydantic-settings` model that auto-loads `.env`
|
|
from the current working directory.
|
|
- `app.db` constructs the SQLAlchemy engine on import.
|
|
|
|
`tests/conftest.py` therefore, **before any `app.*` import**:
|
|
|
|
1. Sets `DATABASE_URL`, `SECRET_KEY`, `ADMIN_PASSWORD`, `LOG_LEVEL` to safe
|
|
test values via `os.environ.setdefault`.
|
|
2. Generates a fresh `FERNET_KEY` so encrypt/decrypt round-trips succeed.
|
|
3. Adds `backend/` to `sys.path`.
|
|
4. `chdir`s to a temp directory so the developer's local `.env` (which contains
|
|
keys not declared on `Settings`) is **not** picked up. Without this step
|
|
pydantic raises `extra_forbidden`.
|
|
|
|
No real Postgres connection is opened — SQLAlchemy connects lazily, and these
|
|
tests never issue a query.
|
|
|
|
## Running locally
|
|
|
|
There is no system-wide Python on this host, so use the same Python image as CI:
|
|
|
|
```bash
|
|
docker run --rm -v "$PWD/backend:/app" -w /app python:3.12-slim bash -c '
|
|
pip install -r requirements-dev.txt &&
|
|
python -m pytest -p no:warnings
|
|
'
|
|
```
|
|
|
|
Run a single test:
|
|
|
|
```bash
|
|
python -m pytest tests/test_auth.py::TestJWT -v
|
|
```
|
|
|
|
## CI
|
|
|
|
GitHub Actions runs the suite on every push / PR to `main` that touches
|
|
`backend/**` — see [.github/workflows/backend-tests.yml](../.github/workflows/backend-tests.yml).
|
|
Coverage is reported to the job log and uploaded as an artifact.
|
|
|
|
## Adding more tests
|
|
|
|
- **Pure / domain logic** (no DB): use the `fake_user_factory` /
|
|
`fake_role_factory` fixtures in `conftest.py`. They produce
|
|
`SimpleNamespace` objects that satisfy duck-typed access in `auth.py` and
|
|
`rbac/engine.py`.
|
|
- **Touches the DB**: build out a SQLite-backed fixture (override
|
|
`app.db.engine` with `sqlite:///:memory:` and `Base.metadata.create_all`).
|
|
Not required for the current smoke layer.
|
|
- **API endpoints**: spin up `TestClient(app)` once `get_db` and any external
|
|
Proxmox / SSH dependencies are dependency-overridden.
|
|
|
|
## Markers
|
|
|
|
Defined in `pytest.ini`:
|
|
|
|
- `@pytest.mark.smoke` — quickest sanity checks.
|
|
- `@pytest.mark.unit` — pure unit tests.
|
|
- `@pytest.mark.integration` — multi-module integration.
|
|
|
|
Run only smoke tests:
|
|
|
|
```bash
|
|
python -m pytest -m smoke
|
|
```
|