Skip to content

Commit 051f474

Browse files
authored
Add test path that hits a more traditional local test database instead of Docker (#3)
Here, add a testing path that hits a more traditional local test database URL instead of requiring that the tests go through Docker, and making the suite a little more like other River projects and able to share a test database with them (`river_test` being a common name convention between them all). I've also changed the test code to rollback test transactions after each test case so as to not leave any artifacts in the database that might affect other test suites. I've left the Docker path in as well, and it can be activated by sending the `RIVER_USE_DOCKER` env var when running tests: RIVER_USE_DOCKER=true rye test I also added code so that the tests get type checked as well as the main code, which I found helped detect bugs, and being a Python beginner, help better understand what exactly various fixture functions were supposed to be returning. I didn't type everything, mostly just common fixture functions. To make this possible I had to make a few changes like having the main package declare itself as typed by exporting a `py.typed` file, and also making `tests` a module with `__init__.py` so MyPy could resolve common utilities in it like `SimpleArgs`.
1 parent 992dff7 commit 051f474

File tree

11 files changed

+73
-24
lines changed

11 files changed

+73
-24
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ jobs:
1111
runs-on: ubuntu-latest
1212

1313
steps:
14-
- uses: actions/checkout@v4
14+
- name: Checkout
15+
uses: actions/checkout@v4
1516

1617
- name: Install the latest version of rye
1718
uses: eifinger/setup-rye@v3
@@ -32,4 +33,4 @@ jobs:
3233
run: rye build
3334

3435
- name: Test
35-
run: rye test
36+
run: RIVER_USE_DOCKER=true rye test

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ test:
1212

1313
.PHONY: typecheck
1414
typecheck:
15-
rye run mypy -p src.riverqueue
15+
rye run mypy -p riverqueue -p tests

docs/development.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,32 @@ $ rye sync
2222

2323
## Run tests
2424

25+
Create a test database and migrate with River's CLI:
26+
27+
```shell
28+
$ go install github.com/riverqueue/river/cmd/river
29+
$ createdb river_test
30+
$ river migrate-up --database-url "postgres://localhost/river_test"
31+
```
32+
33+
Run all tests:
34+
2535
```shell
2636
$ rye test
2737
```
2838

39+
_Or_, using a Docker test Postgres container instead of a test database:
40+
41+
```shell
42+
RIVER_USE_DOCKER=true rye test
43+
```
44+
45+
Run a specific test (or without `-k` option for all tests in a single file):
46+
47+
```shell
48+
rye test -- tests/driver/sqlalchemy/sqlalchemy_driver_test.py -k test_insert_with_unique_opts_by_queue
49+
```
50+
2951
## Run lint
3052

3153
```shell
@@ -44,4 +66,4 @@ $ make typecheck
4466
$ rye fmt
4567
```
4668

47-
Rye uses [Ruff](https://github.com/astral-sh/ruff) under the hood for code formatting.
69+
Rye uses [Ruff](https://github.com/astral-sh/ruff) under the hood for code formatting.

mypy.ini

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
[mypy]
22

3-
[mypy-riverqueue.sqlcdb]
4-
ignore_errors = True
3+
# testcontainers is typed, but it doesn't correctly declare itself as such.
4+
# Hopefully it can be fixed one day:
5+
#
6+
# https://github.com/testcontainers/testcontainers-python/issues/305
7+
[mypy-testcontainers.*]
8+
ignore_missing_imports = True

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ dev-dependencies = [
2828
allow-direct-references = true
2929

3030
[tool.hatch.build.targets.wheel]
31-
packages = ["src/riverqueue"]
31+
packages = ["src/riverqueue"]

src/riverqueue/py.typed

Whitespace-only changes.

tests/__init__.py

Whitespace-only changes.

tests/client_test.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import json
2-
from dataclasses import dataclass
31
from datetime import datetime, timezone
42
from unittest.mock import MagicMock, patch
53

@@ -8,6 +6,8 @@
86
from riverqueue.client import Client
97
from riverqueue.models import InsertOpts, UniqueOpts
108

9+
from tests.simple_args import SimpleArgs
10+
1111

1212
@pytest.fixture
1313
def mock_driver():
@@ -19,15 +19,6 @@ def client(mock_driver):
1919
return Client(mock_driver)
2020

2121

22-
@dataclass
23-
class SimpleArgs:
24-
kind: str = "simple"
25-
26-
@staticmethod
27-
def to_json() -> str:
28-
return json.dumps({"job_num": 1})
29-
30-
3122
@patch("datetime.datetime")
3223
def test_insert_with_proto_args(mock_datetime, client, mock_driver):
3324
mock_datetime.now.return_value = datetime(2024, 6, 1, 12, 0, 0, tzinfo=timezone.utc)

tests/conftest.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
import os
2+
from typing import Iterator
23

34
import pytest
45
from testcontainers.postgres import PostgresContainer
56
import sqlalchemy
6-
from sqlalchemy import text
7+
from sqlalchemy import Engine, text
78

89

910
@pytest.fixture(scope="session")
10-
def engine():
11+
def engine() -> Iterator[Engine]:
12+
if os.getenv("RIVER_USE_DOCKER"):
13+
yield from engine_with_docker()
14+
else:
15+
yield from engine_with_database_url()
16+
17+
18+
def engine_with_database_url() -> Iterator[Engine]:
19+
database_url = os.getenv("TEST_DATABASE_URL", "postgres://localhost/river_test")
20+
21+
# sqlalchemy removed support for postgres:// for reasons beyond comprehension
22+
database_url = database_url.replace("postgres://", "postgresql://")
23+
24+
yield sqlalchemy.create_engine(database_url)
25+
26+
27+
def engine_with_docker() -> Iterator[Engine]:
1128
with PostgresContainer("postgres:16") as postgres:
1229
engine = sqlalchemy.create_engine(postgres.get_connection_url())
1330
with engine.connect() as conn:

tests/driver/sqlalchemy/sqlalchemy_driver_test.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
from datetime import datetime, timezone
2+
from typing import Iterator
23
from unittest.mock import patch
34

45
import pytest
56

67
from riverqueue.client import Client
78
from riverqueue.models import InsertOpts, UniqueOpts
89
from riverqueue.drivers.sqlalchemy.sqlalchemy_driver import SqlAlchemyDriver
9-
from client_test import SimpleArgs
10-
from sqlalchemy import text
10+
from sqlalchemy import Engine, text
11+
12+
from tests.simple_args import SimpleArgs
1113

1214

1315
@pytest.fixture
14-
def driver(engine):
16+
def driver(engine: Engine) -> Iterator[SqlAlchemyDriver]:
1517
with engine.begin() as conn:
1618
conn.execute(text("SET search_path TO public"))
1719
yield SqlAlchemyDriver(conn)
20+
conn.rollback()
1821

1922

2023
@pytest.fixture
21-
def client(driver):
24+
def client(driver: SqlAlchemyDriver) -> Client:
2225
return Client(driver)
2326

2427

0 commit comments

Comments
 (0)