diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 1f46756d..19583e16 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -7,34 +7,55 @@ on: - ".github/workflows/test-backend.yml" jobs: - build: + container-job: runs-on: ubuntu-latest + + container: python:3.12-slim-bullseye + + services: + postgres: + image: postgres:16.3-alpine3.20 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: - - uses: actions/checkout@v4 + - name: Checkout repo code + uses: actions/checkout@v4 + - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.12" cache: "pip" + - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt --no-cache-dir working-directory: backend + - name: Lint with Ruff run: | pip install ruff ruff --output-format=github . continue-on-error: true working-directory: backend - - name: Create docker network - run: docker network create test_network - - name: Start MongoDB - run: docker run -d --network test_network --name mongo -p 27017:27017 mongo:latest - - name: Start Postgres - run: docker run -d --network test_network --name postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p 5432:5432 postgres:16.3-alpine3.20 - - name: Build app image - run: cp .env.dev .env && docker build -t districtr . + + - name: Run migrations and test + run: alembic upgrade head && ./test.sh working-directory: backend - - name: Test - run: docker run --network test_network -e MONGODB_SERVER=mongo --rm districtr ./test.sh + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + POSTGRES_HOST: postgres + ENVIRONMENT: test diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 72a01c45..ba03d024 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -32,7 +32,7 @@ class Settings(BaseSettings): # 60 minutes * 24 hours * 8 days = 8 days ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 8 DOMAIN: str = "localhost" - ENVIRONMENT: Literal["local", "staging", "production"] = "local" + ENVIRONMENT: Literal["local", "staging", "production", "test"] = "local" @computed_field # type: ignore[misc] @property diff --git a/backend/app/test_main.py b/backend/app/test_main.py index ddb39de6..09129307 100644 --- a/backend/app/test_main.py +++ b/backend/app/test_main.py @@ -14,25 +14,23 @@ client = TestClient(app) +ENVIRONMENT = os.environ.get("ENVIRONMENT") POSTGRES_TEST_DB = "districtr_test" -POSTGRES_TEST_SCHEME = "postgresql+psycopg" -POSTGRES_TEST_USER = "postgres" -POSTGRES_TEST_HOST = "localhost" -POSTGRES_TEST_PORT = 5432 +POSTGRES_SCHEME = "postgresql+psycopg" +POSTGRES_USER = os.environ.get("POSTGRES_USER", "postgres") +POSTGRES_PASSWORD = os.environ.get("POSTGRES_PASSWORD", "postgres") +POSTGRES_HOST = os.environ.get("POSTGRES_HOST", "localhost") +POSTGRES_PORT = os.environ.get("POSTGRES_PORT", 5432) my_env = os.environ.copy() my_env["POSTGRES_DB"] = POSTGRES_TEST_DB -my_env["POSTGRES_SCHEME"] = POSTGRES_TEST_SCHEME -my_env["POSTGRES_USER"] = POSTGRES_TEST_USER -my_env["POSTGRES_SERVER"] = POSTGRES_TEST_HOST -my_env["POSTGRES_PORT"] = str(POSTGRES_TEST_PORT) TEST_SQLALCHEMY_DATABASE_URI = MultiHostUrl.build( - scheme=POSTGRES_TEST_SCHEME, - username=POSTGRES_TEST_USER, - host=POSTGRES_TEST_HOST, - port=POSTGRES_TEST_PORT, + scheme=POSTGRES_SCHEME, + username=POSTGRES_USER, + host=POSTGRES_HOST, + port=int(POSTGRES_PORT), path=POSTGRES_TEST_DB, ) @@ -55,15 +53,21 @@ def test_get_session(): @pytest.fixture(scope="session", autouse=True, name="engine") def engine_fixture(request): - _engine = create_engine("postgresql://postgres@/postgres") + url = f"{POSTGRES_SCHEME}://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}/postgres" + _engine = create_engine(url) conn = _engine.connect() conn.execute(text("commit")) try: - conn.execute(text(f"CREATE DATABASE {POSTGRES_TEST_DB}")) + if conn.in_transaction(): + conn.rollback() + conn.execution_options(isolation_level="AUTOCOMMIT").execute( + text(f"CREATE DATABASE {POSTGRES_TEST_DB}") + ) except (OperationalError, ProgrammingError): pass - subprocess.run(["alembic", "upgrade", "head"], check=True, env=my_env) + if ENVIRONMENT != "test": + subprocess.run(["alembic", "upgrade", "head"], check=True, env=my_env) def teardown(): conn.execute(text(f"DROP DATABASE {POSTGRES_TEST_DB}")) diff --git a/backend/test.sh b/backend/test.sh index 90c65a27..64c311ce 100755 --- a/backend/test.sh +++ b/backend/test.sh @@ -1,3 +1,4 @@ #!/bin/bash +alembic upgrade head python -c 'from app.core.db import create_collections; create_collections()' pytest -v