diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..9a0674c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,64 @@ +name: Tests + +# Both events, deliberately: a branch pushed here often has no pull request yet, +# because the usual workflow is to push a SWEET_python branch alongside a +# same-named WasteMAP branch (WasteMAP's CI installs the matching branch) and open +# the PRs later. `pull_request` on top of that covers forks. The cost is that a +# branch with an open PR in this repo runs the suite twice for the same commit, +# which is cheap here — the whole suite is a few seconds. +on: [push, pull_request] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + fast: + name: Fast tests + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Setup Python + uses: actions/setup-python@v7 + with: + # 3.12 is what WasteMAP's CI and deploy images run, which is where this + # package actually executes. The code itself needs 3.10+ (PEP 604 `X | Y` + # annotations), so it is not a floor imposed by this workflow. + python-version: "3.12" + cache: pip + cache-dependency-path: requirements.txt + + - name: Install libpq headers + # psycopg2 (not psycopg2-binary) publishes no manylinux wheel, so pip + # builds it from source and needs pg_config, which libpq-dev provides. + run: | + sudo apt-get update + sudo apt-get install -y libpq-dev + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + # The pinned lockfile — reproducible installs are what requirements.txt + # exists for; requirements.in holds the abstract deps consumers get. + pip install -r requirements.txt + # Bounded rather than pinned: minor/patch pytest releases are welcome, + # a major one should not break CI on a day nobody touched the model. + pip install "pytest>=8,<10" + # Editable, --no-deps: makes `import SWEET_python` resolve to this + # checkout without re-resolving what requirements.txt just pinned, and + # exercises setup.py's packaging on the way. + pip install --no-deps -e . + + - name: Run fast tests + # Tests needing a live database or the network are marked `integration` + # and excluded here, mirroring how WasteMAP splits backend/tests/fast from + # backend/tests/integration. This repo has none yet: the whole suite is + # hermetic. When the first one lands, give it a job of its own instead of + # attaching a database to this one. + run: pytest -m "not integration" --verbose diff --git a/README.md b/README.md index b8aee8d..0155f1c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,34 @@ After following these steps, SWEET_python can be imported: 3) cd into the SWEET_python directory, then write `pip install -e .` to install in editable mode, which allows editing the code. Updates to the code in the repo should be automatically reflected in the installed package. If they are not, reinstall it. +# Tests + +The test suite lives in `tests/` and runs with pytest: + +``` +pip install -r requirements.txt "pytest>=8,<10" +pip install -e . +pytest +``` + +Every test in the suite is hermetic — no database, no network, no environment +variables — and the whole thing takes a few seconds. + +CI (`.github/workflows/tests.yml`) runs `pytest -m "not integration"` on Python +3.12 for every push and pull request. If you add a test that does need a live +database or network access, mark it `@pytest.mark.integration` so it stays out of +that job, following the same fast/integration split as WasteMAP's +`backend/tests/fast` and `backend/tests/integration`. There are no such tests +today; the first one should get a CI job of its own rather than a database being +bolted onto the fast job. + +This is complementary to WasteMAP's CI, not a replacement for it: WasteMAP +installs a SWEET_python branch with the same name as the WasteMAP branch under +test, so a model change here and its WasteMAP consumer are already exercised as a +pair over there. What that pairing does *not* do is run this repo's own tests — +that is the gap this workflow fills. Tests of this package's internals belong +here, in the repo that owns them. + # Usage You will have to write your own code to import your data files. Examples are in SWEET_python/sweet_tools_obj.py—the load_from_database method illustrates the many different parameters that can be specified. For many parameters, default values are available. These are stored in the defaults_2019.py file, and the sweet_tools_obj.py file contains many examples of accessing them. The code for the model itself is in model.py. Models are generally run as part of a Landfill instance—the Landfill class is defined at the bottom of sweet_tools_obj.py diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..b2ffdcd --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +testpaths = tests +# --strict-markers so a mistyped marker (@pytest.mark.integraton) is an error +# rather than a test that silently keeps running in the fast job. +addopts = --strict-markers +markers = + integration: needs a live database or network access; excluded from the fast CI job. Run these with `pytest -m integration`.