diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 0000000..8c0fd54 --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,23 @@ +name: Integration Tests +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + tests: + strategy: + matrix: + dbtype: ["postgres"] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - uses: isbang/compose-action@v1.4.1 + with: + compose-file: "./tests_integration/docker-compose-${{ matrix.dbtype }}.yml" + up-flags: "--build --abort-on-container-exit" + down-flags: "--volumes" diff --git a/pyproject.toml b/pyproject.toml index df799d1..667b672 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,9 @@ ignore = ["A003", "D101", "D104", "D406", "D407", "S104", "TRY201", "TRY003", "E line-length = 120 target-version = "py39" +[tool.ruff.per-file-ignores] +"tests*/*" = ["ANN201", "S101"] + [tool.black] line-length = 120 target-version = ['py39'] diff --git a/tests_integration/Dockerfile b/tests_integration/Dockerfile new file mode 100644 index 0000000..7939d3e --- /dev/null +++ b/tests_integration/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.11-alpine + +COPY requirements.txt /tester/ + +WORKDIR /tester + +RUN pip install -r requirements.txt + +ENTRYPOINT [ "pytest", "tests" ] diff --git a/tests_integration/docker-compose-postgres.yml b/tests_integration/docker-compose-postgres.yml new file mode 100644 index 0000000..03823c3 --- /dev/null +++ b/tests_integration/docker-compose-postgres.yml @@ -0,0 +1,24 @@ +version: '3.8' +services: + db: + image: postgres:11-alpine + environment: + - POSTGRES_PASSWORD=abc + spoolman: + build: ./../ + environment: + - SPOOLMAN_DB_TYPE=postgres + - SPOOLMAN_DB_HOST=db + - SPOOLMAN_DB_PORT=5432 + - SPOOLMAN_DB_NAME=postgres + - SPOOLMAN_DB_USERNAME=postgres + - SPOOLMAN_DB_PASSWORD=abc + - SPOOLMAN_LOGGING_LEVEL=DEBUG + depends_on: + - db + tester: + build: . + volumes: + - ./tests:/tester/tests + depends_on: + - spoolman diff --git a/tests_integration/requirements.txt b/tests_integration/requirements.txt new file mode 100644 index 0000000..491a32a --- /dev/null +++ b/tests_integration/requirements.txt @@ -0,0 +1,3 @@ +pytest==7.3.1 +pytest-asyncio==0.21.0 +httpx==0.24.0 diff --git a/tests_integration/tests/__init__.py b/tests_integration/tests/__init__.py new file mode 100644 index 0000000..81a11d3 --- /dev/null +++ b/tests_integration/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for the integration of the application.""" diff --git a/tests_integration/tests/conftest.py b/tests_integration/tests/conftest.py new file mode 100644 index 0000000..f076b27 --- /dev/null +++ b/tests_integration/tests/conftest.py @@ -0,0 +1,23 @@ +"""Test fixtures for integration tests.""" + +import time + +import httpx +import pytest + +TIMEOUT = 10 + + +@pytest.fixture(scope="session", autouse=True) +def _wait_for_server(): # noqa: ANN202 + """Wait for the server to start up.""" + start_time = time.time() + while True: + try: + response = httpx.get("http://spoolman:8000") + response.raise_for_status() + except httpx.HTTPError: + if time.time() - start_time > TIMEOUT: + raise + else: + break diff --git a/tests_integration/tests/test_api.py b/tests_integration/tests/test_api.py new file mode 100644 index 0000000..c07538c --- /dev/null +++ b/tests_integration/tests/test_api.py @@ -0,0 +1,47 @@ +"""Integration tests for the API.""" + +import httpx + +URL = "http://spoolman:8000" + + +def test_add_vendor(): + """Test adding a vendor to the database.""" + name = "John" + comment = "abcdefghåäö" + result = httpx.post( + f"{URL}/api/v1/vendor", + json={"name": name, "comment": comment}, + ) + result.raise_for_status() + + vendor = result.json() + assert vendor["name"] == name + assert vendor["comment"] == comment + assert vendor["id"] is not None + assert vendor["registered"] is not None + + +def test_get_vendor(): + """Test getting a vendor from the database.""" + name = "John" + comment = "abcdefghåäö" + result = httpx.post( + f"{URL}/api/v1/vendor", + json={"name": name, "comment": comment}, + ) + result.raise_for_status() + + added_vendor = result.json() + + result = httpx.get( + f"{URL}/api/v1/vendor/{added_vendor['id']}", + ) + result.raise_for_status() + + vendor = result.json() + + assert vendor["name"] == name + assert vendor["comment"] == comment + assert vendor["id"] == added_vendor["id"] + assert vendor["registered"] == added_vendor["registered"]