91 lines
5.0 KiB
Markdown
91 lines
5.0 KiB
Markdown
# Live-Gitea integration tests
|
|
|
|
These tests run against a throwaway Gitea 28.1.0 started in Docker. They are
|
|
opt-in: without `AEGIS_INTEGRATION=1` every test here is skipped and Docker is
|
|
never touched, so the default `uv run pytest` stays fast.
|
|
|
|
```bash
|
|
AEGIS_INTEGRATION=1 uv run pytest tests/integration -m integration -v
|
|
```
|
|
|
|
An integration-only run covers little of `src/`, so the unit-test coverage gate
|
|
is lowered to 0 for runs that collect nothing but `tests/integration`. If Docker
|
|
is unavailable while `AEGIS_INTEGRATION=1` is set, the session fails with a clear
|
|
message instead of skipping.
|
|
|
|
## What the harness does
|
|
|
|
- Image: `GITEA_IMAGE` in `harness.py` (digest-pinned, single constant).
|
|
- One container and one network per run, both named `aegis-it-<8 hex>`.
|
|
No host bind mounts, no image builds, no `docker prune`.
|
|
- Gitea is configured through `GITEA__section__KEY` env vars (sqlite3,
|
|
`INSTALL_LOCK`, random `SECRET_KEY`/`INTERNAL_TOKEN`/OAuth2 JWT secret,
|
|
Actions, packages and OAuth2 enabled, mailer off, webhook allowed host list
|
|
`*`, local network migrations allowed so the instance can mirror itself, repository
|
|
hook scripts editable, `MAX_RESPONSE_ITEMS=50`).
|
|
- Readiness: polls `GET /api/v1/version` for up to 90 s. On failure the last 100
|
|
log lines of the container are written to stderr.
|
|
- Seeding: admin `aegis-admin` (random password) via `gitea admin user create`,
|
|
plus a full-scope token. All data is fake and random per run. Passwords and
|
|
tokens are kept out of `repr` and error messages.
|
|
- Cleanup: `docker rm -f -v <container>` and `docker network rm <net>` from the
|
|
session fixture finalizer, an `atexit` hook, and SIGTERM/SIGHUP handlers.
|
|
|
|
## Reachability modes
|
|
|
|
1. Local (default): a free loopback port is chosen, published as
|
|
`127.0.0.1:<port>:3000`, and `ROOT_URL` is set to match. Base URL
|
|
`http://127.0.0.1:<port>`.
|
|
2. CI (`AEGIS_IT_NETWORK_MODE=container`): for test runs inside a job container
|
|
that shares the host Docker socket. No port is published. Gitea joins the
|
|
per-run network, the job container (`$HOSTNAME`) is connected to the same
|
|
network with `docker network connect`, and tests reach Gitea at
|
|
`http://aegis-it-<id>:3000`. On cleanup the job container is disconnected
|
|
again before the network is removed.
|
|
|
|
## Fixtures and helpers
|
|
|
|
- `gitea` (session): a `GiteaInstance` with `base_url`, `admin_login`,
|
|
`admin_token`, `api(method, path, token=None, **kw)` (defaults to the admin
|
|
token, `anonymous=True` sends no credentials), `create_user`, `mint_token`,
|
|
`create_org`, `create_repo`, `unique`.
|
|
- `regular_user` (session): non-admin user with its own full-scope token.
|
|
- `unique_name` (function): a unique name derived from the test name.
|
|
|
|
## The suite
|
|
|
|
Tests call tools through the MCP server (an in-memory `Client` on `build_server`, run as
|
|
the admin of the throwaway instance), so schema validation, the result envelope, the audit
|
|
log and the executor are all exercised. State lives in `tmp_path`.
|
|
|
|
- `test_scenario_*.py`: happy paths with real state changes (org and team, repository
|
|
files, branches and tags, issues, pull requests and reviews, releases and attachments,
|
|
secrets and variables, webhooks, admin and sudo, notifications, current-user features,
|
|
generic packages, and a workflow run on an `act_runner` container).
|
|
- `test_sweep.py`: every one of the 538 tools is called once against a seeded instance
|
|
(`sweep_seed.py` creates the data, `sweep_plan.py` builds arguments and expectations).
|
|
Order: read-only first, then creates, updates and deletes (leaf resources first). A call
|
|
passes with a 2xx, a status the swagger documents for that operation, or an entry of
|
|
`ALLOWANCES` (each with a reason). All failing tools are listed at once.
|
|
`test_sweep_isolated.py` covers the tools the sweep must not call.
|
|
- `test_per_user_oauth.py`: the HTTP app with per-user OAuth, driven in process with a
|
|
seeded OAuth store; calls run as the signed-in user, admin tools and private repositories
|
|
of others are refused by Gitea, the static bearer still runs as admin.
|
|
- `test_setup_live.py`: `aegis-gitea-mcp setup` against the instance (OAuth app, env file
|
|
mode, idempotence, non-admin token).
|
|
- `tests/test_sweep_plan.py` (no Docker) keeps the sweep plan consistent with the catalog.
|
|
|
|
`AEGIS_IT_WRITE_REPORT=1` makes the session write `docs/integration-coverage.md` (per
|
|
domain: tools with a 2xx, documented non-2xx statuses, allowances).
|
|
|
|
### Actions runner
|
|
|
|
`start_runner` starts `gitea/act_runner` (digest-pinned in `ACT_RUNNER_IMAGE`) on the run's
|
|
network, registered with a token from `gitea_actions_repo_create_runner_registration_token`,
|
|
label `aegis-host:host`. Jobs run inside the runner container itself: no Docker socket, no
|
|
bind mounts. The runner reaches Gitea by container name, so it works in both network modes.
|
|
It is removed with the rest of the run. If it cannot start or come online, the test is
|
|
marked xfail with the reason; a failure after the run completed is a real failure.
|
|
|
|
Runtime: about two minutes locally (Gitea start 15 s, sweep 40 s, runner 10 s).
|