From 82bcbeac07ecab01ebf9c6ede37598ce98d3c926 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 21 Jan 2026 17:42:05 +0000 Subject: [PATCH 1/3] ci: Add GitHub Actions workflow and example test - Add test.yml workflow that runs on push/PR to main - Uses PostgreSQL 17 service container - Runs ruff linting, mypy type checking, and pytest - Add simple example test demonstrating framework usage - Example shows transaction isolation between tests --- .github/workflows/test.yml | 58 +++++++++++++++++++++++++++++++ tests/test_example.py | 71 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 .github/workflows/test.yml create mode 100644 tests/test_example.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..8cd8ca5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,58 @@ +name: Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:17 + 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: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: latest + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Install dependencies + run: poetry install + + - name: Run linting + run: poetry run ruff check . + + - name: Run type checking + run: poetry run mypy src --ignore-missing-imports + + - name: Run tests + env: + PGHOST: localhost + PGPORT: 5432 + PGUSER: postgres + PGPASSWORD: postgres + run: poetry run pytest -v diff --git a/tests/test_example.py b/tests/test_example.py new file mode 100644 index 0000000..5467b16 --- /dev/null +++ b/tests/test_example.py @@ -0,0 +1,71 @@ +""" +Simple example test demonstrating pysql-test usage. + +This is a minimal example showing how to use the testing framework +for PostgreSQL integration tests with automatic database isolation. +""" + +import pytest + +from pysql_test import get_connections, seed + + +@pytest.fixture +def db(): + """ + Create an isolated test database with sample schema. + + Each test gets a fresh database that is automatically + cleaned up after the test completes. + """ + conn = get_connections( + seed_adapters=[ + seed.fn(lambda ctx: ctx["pg"].query(""" + CREATE TABLE users ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + email TEXT UNIQUE + ) + """)) + ] + ) + db = conn.db + db.before_each() + yield db + db.after_each() + conn.teardown() + + +def test_insert_and_query_user(db): + """Test inserting and querying a user.""" + # Insert a user + db.execute( + "INSERT INTO users (name, email) VALUES (%s, %s)", + ("Alice", "alice@example.com"), + ) + + # Query the user + user = db.one("SELECT * FROM users WHERE name = %s", ("Alice",)) + + assert user["name"] == "Alice" + assert user["email"] == "alice@example.com" + + +def test_transaction_isolation(db): + """Test that changes are rolled back between tests.""" + # This insert will be rolled back after the test + db.execute( + "INSERT INTO users (name, email) VALUES (%s, %s)", + ("Bob", "bob@example.com"), + ) + + # Verify the user exists within this test + count = db.one("SELECT COUNT(*) as count FROM users") + assert count["count"] == 1 + + +def test_empty_table_after_rollback(db): + """Verify previous test's data was rolled back.""" + # Table should be empty because previous test's insert was rolled back + count = db.one("SELECT COUNT(*) as count FROM users") + assert count["count"] == 0 From 4478ba50fe413c3b8ed2a3abdb1953e93b70fcd5 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 21 Jan 2026 17:44:28 +0000 Subject: [PATCH 2/3] fix: Remove trailing whitespace in test docstring --- tests/test_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_example.py b/tests/test_example.py index 5467b16..c639bd2 100644 --- a/tests/test_example.py +++ b/tests/test_example.py @@ -14,7 +14,7 @@ def db(): """ Create an isolated test database with sample schema. - + Each test gets a fresh database that is automatically cleaned up after the test completes. """ From 570db4df2a9ffeaf224be8b5d03965b52f80c997 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Wed, 21 Jan 2026 17:55:35 +0000 Subject: [PATCH 3/3] ci: Use postgres-plus:17 image and follow constructive pattern - Switch to ghcr.io/constructive-io/docker/postgres-plus:17 image - Add concurrency settings to cancel in-progress runs - Add workflow_dispatch for manual triggers - Add develop branch to triggers - Update password to match constructive pattern - Move env vars to job level --- .github/workflows/test.yml | 40 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8cd8ca5..f6e70fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,32 +1,47 @@ -name: Tests +name: pysql-test CI on: push: - branches: [main] + branches: + - main + - develop pull_request: - branches: [main] + branches: + - main + - develop + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-run-tests + cancel-in-progress: true jobs: test: runs-on: ubuntu-latest + env: + PGHOST: localhost + PGPORT: 5432 + PGUSER: postgres + PGPASSWORD: password + services: - postgres: - image: postgres:17 + pg_db: + image: ghcr.io/constructive-io/docker/postgres-plus:17 env: POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres - ports: - - 5432:5432 + POSTGRES_PASSWORD: password options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + ports: + - 5432:5432 steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 @@ -50,9 +65,4 @@ jobs: run: poetry run mypy src --ignore-missing-imports - name: Run tests - env: - PGHOST: localhost - PGPORT: 5432 - PGUSER: postgres - PGPASSWORD: postgres run: poetry run pytest -v