From 5f50976a38e01c9c33fd9bedd612a205679e6fdf Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 22 Sep 2026 16:40:00 +0900 Subject: [PATCH 1/3] test(runtime-sdk): test hyperdrive with django database backends --- ...{test_web_frameworks.py => test_django.py} | 0 .../tests/test_django_databases.py | 37 +++++++ .../django-databases/pyproject.toml | 16 +++ .../django-databases/src/django_db_config.py | 61 +++++++++++ .../django-databases/src/django_db_helpers.py | 100 ++++++++++++++++++ .../django-databases/src/test_mysql.py | 37 +++++++ .../django-databases/src/test_postgresql.py | 36 +++++++ .../django-databases/src/worker.py | 9 ++ .../django-databases/wrangler.jsonc | 18 ++++ 9 files changed, 314 insertions(+) rename packages/runtime-sdk/tests/{test_web_frameworks.py => test_django.py} (100%) create mode 100644 packages/runtime-sdk/tests/test_django_databases.py create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/pyproject.toml create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_config.py create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_helpers.py create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/worker.py create mode 100644 packages/runtime-sdk/tests/web-frameworks-test/django-databases/wrangler.jsonc diff --git a/packages/runtime-sdk/tests/test_web_frameworks.py b/packages/runtime-sdk/tests/test_django.py similarity index 100% rename from packages/runtime-sdk/tests/test_web_frameworks.py rename to packages/runtime-sdk/tests/test_django.py diff --git a/packages/runtime-sdk/tests/test_django_databases.py b/packages/runtime-sdk/tests/test_django_databases.py new file mode 100644 index 00000000..6b118a40 --- /dev/null +++ b/packages/runtime-sdk/tests/test_django_databases.py @@ -0,0 +1,37 @@ +# pyright: reportAttributeAccessIssue=false, reportMissingImports=false + +"""Stock Django database backends running through Hyperdrive in workerd.""" + +from pathlib import Path + +import pytest +from conftest import COMPAT_CONFIGS, CompatConfig, register_in_worker_suites + +DJANGO_DATABASES_DIR: Path = ( + Path(__file__).parent / "web-frameworks-test" / "django-databases" +) +DJANGO_DATABASES_SRC_DIR: Path = DJANGO_DATABASES_DIR / "src" +PYTHON_314_CONFIGS = [ + config for config in COMPAT_CONFIGS if config.python_version == "3.14" +] +SUITE_MARKS: dict[str, pytest.MarkDecorator] = { + "postgresql": pytest.mark.hyperdrive, + "mysql": pytest.mark.hyperdrive, +} + + +@pytest.fixture(scope="module") +def worker_project_dir() -> Path: + return DJANGO_DATABASES_DIR + + +@pytest.fixture( + scope="module", + params=PYTHON_314_CONFIGS, + ids=[config.python_version for config in PYTHON_314_CONFIGS], +) +def compat_config(request: pytest.FixtureRequest) -> CompatConfig: + return request.param + + +register_in_worker_suites(globals(), DJANGO_DATABASES_SRC_DIR, marks=SUITE_MARKS) diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/pyproject.toml b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/pyproject.toml new file mode 100644 index 00000000..4e5751b4 --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/pyproject.toml @@ -0,0 +1,16 @@ +[project] +name = "django-databases-test" +version = "0.1.0" +requires-python = ">=3.14" +dependencies = [ + "django>=5.2.8", + "mysqlclient", + "psycopg[binary]", + "pytest", + "testlib", + "workers-runtime-sdk", +] + +[tool.uv.sources] +testlib = { path = "../packages/testlib" } +workers-runtime-sdk = { path = "../packages/runtime-sdk" } diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_config.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_config.py new file mode 100644 index 00000000..a00aaec1 --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_config.py @@ -0,0 +1,61 @@ +# pyright: reportMissingImports=false + +"""Django settings for stock backends running through Hyperdrive.""" + +import os + +import django +from django.conf import settings + +from workers import env + +os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true") + +HYPERDRIVE_POSTGRESQL = "hyperdrive_postgresql" +HYPERDRIVE_MYSQL = "hyperdrive_mysql" + + +def _postgresql_database() -> dict[str, object]: + hyperdrive = env.HYPERDRIVE_PG + return { + "ENGINE": "django.db.backends.postgresql", + "HOST": hyperdrive.host, + "PORT": str(hyperdrive.port), + "USER": hyperdrive.user, + "PASSWORD": hyperdrive.password, + "NAME": hyperdrive.database, + "CONN_MAX_AGE": 0, + "OPTIONS": {"sslmode": "disable"}, + "DISABLE_SERVER_SIDE_CURSORS": True, + } + + +def _mysql_database() -> dict[str, object]: + hyperdrive = env.HYPERDRIVE_MYSQL + return { + "ENGINE": "django.db.backends.mysql", + "HOST": hyperdrive.host, + "PORT": str(hyperdrive.port), + "USER": hyperdrive.user, + "PASSWORD": hyperdrive.password, + "NAME": hyperdrive.database, + "CONN_MAX_AGE": 0, + "OPTIONS": {"ssl_mode": "DISABLED"}, + } + + +settings.configure( + DEBUG=False, + SECRET_KEY="test-secret-key-for-workers-py", + INSTALLED_APPS=[], + DATABASES={ + "default": {"ENGINE": "django.db.backends.dummy"}, + HYPERDRIVE_POSTGRESQL: _postgresql_database(), + HYPERDRIVE_MYSQL: _mysql_database(), + }, + TIME_ZONE="UTC", + USE_TZ=True, + DEFAULT_AUTO_FIELD="django.db.models.BigAutoField", +) + +django.setup() diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_helpers.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_helpers.py new file mode 100644 index 00000000..ddc3cc45 --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/django_db_helpers.py @@ -0,0 +1,100 @@ +"""ORM assertions shared by the independent Django backend suites.""" + +import uuid +from collections.abc import Iterator +from contextlib import contextmanager + +import pytest +from django.db import connections, models, transaction +from django.test.utils import isolate_apps + + +class Rollback(Exception): + """Raised to roll back an atomic block.""" + + +def _table_name() -> str: + return f"dht_{uuid.uuid4().hex}" + + +@contextmanager +def _temporary_model(alias: str) -> Iterator[type[models.Model]]: + table_name = _table_name() + connection = connections[alias] + + with isolate_apps(): + + class TemporaryModel(models.Model): + name = models.CharField(max_length=100) + value = models.IntegerField() + float_value = models.FloatField(default=0.0) + is_active = models.BooleanField(default=False) + + class Meta: + app_label = "hyperdrive_tests" + db_table = table_name + + created = False + try: + with connection.schema_editor() as schema_editor: + schema_editor.create_model(TemporaryModel) + created = True + yield TemporaryModel + finally: + if created: + with connection.schema_editor() as schema_editor: + schema_editor.delete_model(TemporaryModel) + + +def assert_connectivity(alias: str) -> None: + connection = connections[alias] + connection.ensure_connection() + assert connection.is_usable() + + +def assert_crud(alias: str) -> None: + with _temporary_model(alias) as model: + objects = model.objects.using(alias) + objects.create(name="alpha", value=1) + objects.create(name="beta", value=2) + + assert list( + objects.filter(name__in=["alpha", "beta"]) + .order_by("name") + .values_list("name", "value") + ) == [("alpha", 1), ("beta", 2)] + + assert objects.filter(name="alpha").update(value=11) == 1 + assert objects.get(name="alpha").value == 11 + + assert objects.filter(name="alpha").delete()[0] == 1 + assert objects.count() == 1 + assert objects.get(name="beta").value == 2 + + +def assert_data_types(alias: str) -> None: + with _temporary_model(alias) as model: + objects = model.objects.using(alias) + created = objects.create( + name="hello", + value=42, + float_value=3.14, + is_active=True, + ) + row = objects.get(pk=created.pk) + + assert row.name == "hello" + assert row.value == 42 + assert abs(row.float_value - 3.14) < 0.001 + assert row.is_active is True + + +def assert_transaction_rollback(alias: str) -> None: + with _temporary_model(alias) as model: + objects = model.objects.using(alias) + + with pytest.raises(Rollback), transaction.atomic(using=alias): + objects.create(name="should_disappear", value=1) + raise Rollback + + assert objects.count() == 0 diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py new file mode 100644 index 00000000..11f7b18a --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py @@ -0,0 +1,37 @@ +# pyright: reportMissingImports=false + +"""Stock Django MySQL backend running through the HYPERDRIVE_MYSQL binding.""" + +import MySQLdb +import pytest +from django.db import connections +from django_db_config import HYPERDRIVE_MYSQL +from django_db_helpers import ( + assert_connectivity, + assert_crud, + assert_data_types, + assert_transaction_rollback, +) +from MySQLdb import _mysql + + +@pytest.fixture(autouse=True) +def close_connections(): + yield + connections[HYPERDRIVE_MYSQL].close() + + +def test_connectivity(): + assert_connectivity(HYPERDRIVE_MYSQL) + + +def test_crud(): + assert_crud(HYPERDRIVE_MYSQL) + + +def test_data_types(): + assert_data_types(HYPERDRIVE_MYSQL) + + +def test_transaction_rollback(): + assert_transaction_rollback(HYPERDRIVE_MYSQL) diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py new file mode 100644 index 00000000..7d42b5ca --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py @@ -0,0 +1,36 @@ +# pyright: reportMissingImports=false + +"""Stock Django PostgreSQL backend running through the HYPERDRIVE_PG binding.""" + +import psycopg +import pytest +from django.db import connections +from django_db_config import HYPERDRIVE_POSTGRESQL +from django_db_helpers import ( + assert_connectivity, + assert_crud, + assert_data_types, + assert_transaction_rollback, +) + + +@pytest.fixture(autouse=True) +def close_connections(): + yield + connections[HYPERDRIVE_POSTGRESQL].close() + + +def test_connectivity(): + assert_connectivity(HYPERDRIVE_POSTGRESQL) + + +def test_crud(): + assert_crud(HYPERDRIVE_POSTGRESQL) + + +def test_data_types(): + assert_data_types(HYPERDRIVE_POSTGRESQL) + + +def test_transaction_rollback(): + assert_transaction_rollback(HYPERDRIVE_POSTGRESQL) diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/worker.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/worker.py new file mode 100644 index 00000000..8ceba4d5 --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/worker.py @@ -0,0 +1,9 @@ +# pyright: reportMissingImports=false + +"""Django database backend test worker.""" + +from testlib.entrypoint import TestRunnerEntrypoint + + +class Default(TestRunnerEntrypoint): + pass diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/wrangler.jsonc b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/wrangler.jsonc new file mode 100644 index 00000000..2544e679 --- /dev/null +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/wrangler.jsonc @@ -0,0 +1,18 @@ +{ + "name": "django-databases-test", + "main": "src/worker.py", + "compatibility_date": "%COMPAT_DATE", + "compatibility_flags": ["python_workers"], + "hyperdrive": [ + { + "binding": "HYPERDRIVE_PG", + "id": "00000000-0000-0000-0000-000000000001", + "localConnectionString": "postgres://testuser:testpass@127.0.0.1:5432/testdb" + }, + { + "binding": "HYPERDRIVE_MYSQL", + "id": "00000000-0000-0000-0000-000000000002", + "localConnectionString": "mysql://testuser:testpass@127.0.0.1:3306/testdb" + } + ] +} From 034e9da6c8732da5671e6915b5cd5fa3c5886e5e Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 22 Sep 2026 16:46:09 +0900 Subject: [PATCH 2/3] test(runtime-sdk): lint --- .../web-frameworks-test/django-databases/src/test_mysql.py | 2 -- .../web-frameworks-test/django-databases/src/test_postgresql.py | 1 - 2 files changed, 3 deletions(-) diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py index 11f7b18a..4636de65 100644 --- a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_mysql.py @@ -2,7 +2,6 @@ """Stock Django MySQL backend running through the HYPERDRIVE_MYSQL binding.""" -import MySQLdb import pytest from django.db import connections from django_db_config import HYPERDRIVE_MYSQL @@ -12,7 +11,6 @@ assert_data_types, assert_transaction_rollback, ) -from MySQLdb import _mysql @pytest.fixture(autouse=True) diff --git a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py index 7d42b5ca..c1bcf502 100644 --- a/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py +++ b/packages/runtime-sdk/tests/web-frameworks-test/django-databases/src/test_postgresql.py @@ -2,7 +2,6 @@ """Stock Django PostgreSQL backend running through the HYPERDRIVE_PG binding.""" -import psycopg import pytest from django.db import connections from django_db_config import HYPERDRIVE_POSTGRESQL From 370361b5b33a4274cbf94ed7cb2901d2425c1f94 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 22 Sep 2026 17:35:04 +0900 Subject: [PATCH 3/3] test: rename test in ci --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7d704e31..ce05f41f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -106,7 +106,7 @@ jobs: with: python-version: '3.14' - - name: Run Hyperdrive binding tests + - name: Run Hyperdrive tests working-directory: packages/runtime-sdk run: | uv run --frozen pytest -v --color=yes -m hyperdrive tests