Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/instructions/stabilization.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Drive failing work to implementation DoD through controlled iterative fix cycles
## Iteration Loop
1. Reproduce failures and capture the exact failing signature.
2. Apply the smallest targeted fix.
3. Re-run the narrowest relevant tests (`pytest tests/test_<name>.py -k "failing_test"`), then broader tests (`pytest tests/`).
3. Re-run the narrowest relevant tests (`agent-make test-functional`, `agent-make test-qgis`, or `agent-make test-ui`), then broader tests (`agent-make test`).
4. Repeat until green or a stop condition is reached.

## Breakpoints and Stop Conditions
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
name: GitlabSync

on:
- push
- delete
workflow_dispatch:

jobs:
sync:
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: tests

on:
push:
branches:
- dev
- master
pull_request:

jobs:
functional:
name: Functional tier
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run functional tests
run: make test-functional

qgis:
name: QGIS tier
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run qgis tests
run: make test-qgis

ui:
name: UI tier
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ui tests
# No UI tests authored yet — `make test-ui` treats pytest's
# exit-5 (no tests collected) as a pass. Real xvfb / image
# failures still fail the job.
run: make test-ui
23 changes: 14 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
- Use `agent-git` whenever possible for git operations. `agent-git` is expected to be in the "always allowed" command pool, so it should be the default path for agent workflows.
- Use raw `git` only when `agent-git` cannot express the required operation. Such usage is **not recommended** and must be explicitly justified in the command text.

# BUILD COMMAND POLICY FOR AGENTS
- Use `agent-make` instead of plain `make` everywhere.
- Plain `make` is not allowed when `agent-make` can express the same target.

# PROJECT STRUCTURE AND ADDRESSING
- /mapflow: QGIS plugin source code (Python, Qt/PyQGIS)
- /mapflow/dialogs: Qt dialog classes and `.ui` files
Expand Down Expand Up @@ -48,7 +52,7 @@ Execute it every time a session is initiated.
- tests;
- code;
10. stabilization.instructions.md:
- run tests;
- run tests (for example: `agent-make test`);
- if tests pass, continue;
- if tests fail, use delivery.instruction.md to iterate on code changes; and test execution until tests pass or you are blocked (`.github/instructions/stabilization.instructions.md`).
- write discoveries to `WAL_<N>.md`
Expand All @@ -75,8 +79,8 @@ Execute it every time a session is initiated.
- If user merged without prior approval signal: `agent-git checkout dev && agent-git pull --ff-only`, mark WAL step `[v]`, commit and push directly to dev using `agent-git push`.

# IMPLEMENTATION DEFINITION OF DONE (PRE-MERGE)
- tests added/updated according to the feature specification
- `pytest tests/` runs successfully
- tests are written/updated according to the feature specification
- tests are executed locally and pass before moving to review (for example: `agent-make test`)
- branch pushed and `[Draft]` MR created
- WAL step is updated to `[ready-for-review]` with concise motivation

Expand Down Expand Up @@ -110,14 +114,15 @@ limited connections to avoid server DDoS protection, issues can start around 40
```

# COMMANDS TO RUN
`pytest tests/` to run the full test suite
`pytest tests/test_<name>.py` to run a specific test file
`pytest tests/ -k "test_name"` to run a specific test by name
`agent-make test` to run the full test workflow
`agent-make test-functional` to run functional tests
`agent-make test-qgis` to run QGIS-runtime tests
`agent-make test-ui` to run UI tests
`agent-make <target>` to run Makefile targets (instead of plain `make`)

# TEST EXECUTION MODES
- All tests run locally with pytest (no containers).
- QGIS-dependent tests may require a QGIS environment or mocking of `qgis.*` / `PyQt5.*` imports.
- Pure logic tests (data transforms, URL building, schema validation) should not depend on QGIS runtime.
- All tests are run locally via `agent-make`, which executes them in the configured Docker test image.
- Use tiered targets when iterating: `agent-make test-functional`, `agent-make test-qgis`, `agent-make test-ui`.

# TERMINAL COMMAND BATCHING
- Combine commands that both require user approval into a single `&&`-chained invocation to minimize approval prompts.
Expand Down
31 changes: 31 additions & 0 deletions Dockerfile.tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Test runtime for the mapflow-qgis plugin.
#
# Pinned to qgis/qgis:release-3_28 — the LTR release, matches the
# 3.20+ minimum in spec/004_stack.md. Bump only when the plugin's
# minimum target changes.
#
# The repo is bind-mounted at /app at run time (see Makefile); we do
# not COPY sources here so an iteration cycle is just `docker run`,
# not rebuild.
FROM qgis/qgis:release-3_28

# xvfb-run is needed by the UI tier; the base image does not ship it.
# Run apt without recommends to keep the image lean.
RUN apt-get update \
&& apt-get install -y --no-install-recommends xvfb \
&& rm -rf /var/lib/apt/lists/*

# QGIS images ship pytest-qgis hooks already; we only need pytest +
# pytest-qt (the latter for the UI tier). The base image's pip is old
# enough that PEP 668's externally-managed marker is not enforced.
RUN python3 -m pip install --no-cache-dir \
pytest \
pytest-qt

# Run Qt without an X display by default; the UI tier overrides this
# by wrapping pytest in `xvfb-run` (provides a real X server).
ENV QT_QPA_PLATFORM=offscreen \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Test runner for mapflow-qgis.
#
# All targets run inside the qgis/qgis:release-3_28 Docker image so
# host setup is irrelevant. See spec/004_stack.md and tests/README.md
# for tier definitions.

IMAGE ?= mapflow-qgis-tests
DOCKERFILE ?= Dockerfile.tests
DOCKER_RUN = docker run --rm -v "$(CURDIR)":/app -w /app $(IMAGE)

.PHONY: help docker-build test test-functional test-qgis test-ui clean

help:
@echo "Targets:"
@echo " docker-build Build the test image ($(IMAGE))"
@echo " test-functional Run pure-logic tests under tests/functional/"
@echo " test-qgis Run QGIS-runtime tests under tests/qgis/"
@echo " test-ui Run UI tests under tests/ui/ (xvfb-run)"
@echo " test Run all three tiers"
@echo " clean Remove pytest cache + bytecode"

docker-build:
docker build -f $(DOCKERFILE) -t $(IMAGE) .

test-functional: docker-build
$(DOCKER_RUN) pytest tests/functional

test-qgis: docker-build
$(DOCKER_RUN) pytest tests/qgis

test-ui: docker-build
# pytest exits 5 when no tests are collected; the UI tier is an
# empty harness today, so treat that as a pass. Remove this guard
# once the first UI test lands.
$(DOCKER_RUN) bash -c 'xvfb-run -a pytest tests/ui; rc=$$?; [ $$rc -eq 0 ] || [ $$rc -eq 5 ]'

test: test-functional test-qgis test-ui

clean:
find . -type d -name __pycache__ -exec rm -rf {} +
find . -type f -name '*.pyc' -delete
rm -rf .pytest_cache
40 changes: 12 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,23 @@ To learn how to use the plugin, please, follow our [guide](https://docs.mapflow.

### Running tests

Tests run inside the QGIS Python environment. Use the Python bundled with your QGIS installation.

**macOS** (QGIS-LTR):
Automated tests run inside the official `qgis/qgis:release-3_28` Docker
image — no host QGIS install needed, only Docker.

```bash
# Install test dependencies (once)
/Applications/QGIS-LTR.app/Contents/MacOS/bin/python3 -m pip install pytest-qt

# Run tests
/Applications/QGIS-LTR.app/Contents/MacOS/bin/python3 -m pytest tests/
make test-functional # pure-logic tests
make test-qgis # tests that touch real QGIS objects
make test-ui # UI tests under xvfb (harness only — no tests yet)
make test # all three tiers
```

**Linux** (system package, e.g. `apt install qgis`):

```bash
# QGIS Python is typically the system Python with QGIS packages available
python3 -m pip install pytest-qt

python3 -m pytest tests/
```

If you installed QGIS from a non-standard location, use the Python binary bundled with it (e.g. `/usr/bin/qgis_python3` or similar).

**Windows** (OSGeo4W):

```cmd
:: Open the OSGeo4W Shell, then:
pip install pytest-qt

python -m pytest tests/
```
Test layout, fixtures, and the policy for adding a test live in
[`tests/README.md`](tests/README.md).

If using the standalone QGIS installer, open the **OSGeo4W Shell** shortcut that comes with QGIS — it sets up the correct Python environment automatically.
> **Coverage scope.** CI is pinned to **Linux + QGIS 3.28 LTR**. The
> `qgis/qgis` Docker image is Linux-only and we do not run a CI matrix
> across operating systems or QGIS versions. Verify macOS, Windows, and
> non-LTR QGIS versions by manual smoke testing before release.

## License

Expand Down
Loading
Loading