diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6d17138e..7d704e31 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -104,7 +104,7 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: - python-version: '3.13' + python-version: '3.14' - name: Run Hyperdrive binding tests working-directory: packages/runtime-sdk diff --git a/packages/runtime-sdk/tests/bindings-test/pyproject.toml b/packages/runtime-sdk/tests/bindings-test/pyproject.toml index ef5fbb6e..0db629d3 100644 --- a/packages/runtime-sdk/tests/bindings-test/pyproject.toml +++ b/packages/runtime-sdk/tests/bindings-test/pyproject.toml @@ -2,7 +2,18 @@ name = "bindings-test" version = "0.1.0" requires-python = ">=3.12" -dependencies = ["pytest", "pytest-asyncio<1.2.0", "pg8000", "pymysql", "cryptography", "testlib"] +dependencies = [ + "pytest", + "pytest-asyncio<1.2.0", + # These are for hyperdrive tests + "pg8000", + "pymysql", + "aiomysql", + "psycopg[binary]; python_version >= '3.14'", + "asyncpg; python_version >= '3.14'", + "cryptography", + "testlib", +] [tool.uv.sources] testlib = { path = "../testlib/dist/testlib-0.0.0-py3-none-any.whl" } diff --git a/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_mysql.py b/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_mysql.py index 8a318953..2b9e982d 100644 --- a/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_mysql.py +++ b/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_mysql.py @@ -24,6 +24,7 @@ import sys +import aiomysql import pymysql import pytest from conftest import unique_table_name @@ -58,6 +59,26 @@ async def test_connect(env): conn.close() +@pytest.mark.asyncio +async def test_connect_aiomysql(env): + hd = env.HYPERDRIVE_MYSQL + conn = await aiomysql.connect( + host=hd.host, + port=int(hd.port), + user=hd.user, + password=hd.password, + db=hd.database, + # Hyperdrive terminates TLS to the origin, so this hop is plaintext. + ssl=None, + ) + try: + async with conn.cursor() as cur: + await cur.execute("SELECT %s", (1,)) + assert await cur.fetchone() == (1,) + finally: + await conn.ensure_closed() + + @pytest.mark.asyncio async def test_create_insert_select(env): conn = _connect(env) diff --git a/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_postgresql.py b/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_postgresql.py index 3860aee4..247dd57b 100644 --- a/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_postgresql.py +++ b/packages/runtime-sdk/tests/bindings-test/src/test_hyperdrive_postgresql.py @@ -61,6 +61,71 @@ async def test_connect(env): conn.close() +@pytest.mark.asyncio +async def test_connect_psycopg(env): + import psycopg # noqa: PLC0415 + + assert psycopg.pq.__impl__ == "binary" + hd = env.HYPERDRIVE_PG + with psycopg.connect( + host=hd.host, + port=int(hd.port), + user=hd.user, + password=hd.password, + dbname=hd.database, + # Hyperdrive terminates TLS to the origin, so this hop is plaintext. + sslmode="disable", + ) as conn: + with conn.cursor() as cur: + cur.execute("SELECT %s", (1,)) + assert cur.fetchone() == (1,) + + +@pytest.mark.asyncio +async def test_asyncpg_crud(env): + import asyncpg # noqa: PLC0415 + + hd = env.HYPERDRIVE_PG + conn = await asyncpg.connect( + host=hd.host, + port=int(hd.port), + user=hd.user, + password=hd.password, + database=hd.database, + # Hyperdrive terminates TLS to the origin, so this hop is plaintext. + ssl=False, + ) + table = unique_table_name() + try: + await conn.execute( + f"CREATE TABLE {table} (id SERIAL PRIMARY KEY, name TEXT, value INT)" + ) + await conn.execute( + f"INSERT INTO {table} (name, value) VALUES ($1, $2)", "alpha", 1 + ) + + row = await conn.fetchrow( + f"SELECT name, value FROM {table} WHERE name = $1", "alpha" + ) + assert tuple(row) == ("alpha", 1) + + await conn.execute( + f"UPDATE {table} SET value = $1 WHERE name = $2", 11, "alpha" + ) + assert ( + await conn.fetchval(f"SELECT value FROM {table} WHERE name = $1", "alpha") + == 11 + ) + + await conn.execute(f"DELETE FROM {table} WHERE name = $1", "alpha") + assert await conn.fetchval(f"SELECT COUNT(*) FROM {table}") == 0 + finally: + try: + await conn.execute(f"DROP TABLE IF EXISTS {table}") + finally: + await conn.close() + + @pytest.mark.asyncio async def test_create_insert_select(env): conn = _connect(env)