Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/hyperdrive-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Hyperdrive Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

permissions:
contents: read

jobs:
test:
strategy:
fail-fast: false
matrix:
python-version: ['3.12', '3.13']
# Docker services require Linux runners
runs-on: ubuntu-latest

services:
postgres:
image: postgres:16
env:
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
POSTGRES_HOST_AUTH_METHOD: md5
POSTGRES_INITDB_ARGS: "--auth-host=md5"
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U testuser -d testdb"
--health-interval=10s
--health-timeout=5s
--health-retries=5

mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_USER: testuser
MYSQL_PASSWORD: testpass
MYSQL_DATABASE: testdb
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1"
--health-interval=10s
--health-timeout=5s
--health-retries=5
--default-authentication-plugin=mysql_native_password

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
run: |
pip install uv

- name: Install project
run: |
uv pip install --system -e packages/runtime-sdk -e packages/cli
uv pip install --system --group dev --project packages/cli

- name: Run hyperdrive tests
working-directory: packages/cli
run: |
pytest -v --color=yes tests/test_hyperdrive.py
3 changes: 2 additions & 1 deletion packages/cli/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ lint.flake8-comprehensions.allow-dict-calls-with-keyword-arguments = true
lint.per-file-ignores."tests/**" = ["PLR2004", "PLR0913"]
lint.per-file-ignores."tests/workerd-test/**" = ["C901", "PLR0911", "PLR0912", "PLR2004", "PLW0603"]
lint.per-file-ignores."tests/bindings-test/**" = ["C901", "PLR0911", "PLR0912", "PLR2004", "PLW0603"]
lint.per-file-ignores."tests/hyperdrive-test/**" = ["C901", "PLR0911", "PLR0912", "PLR2004", "PLW0603"]

[tool.pytest.ini_options]
addopts = ["--ignore=tests/workerd-test", "--ignore=tests/bindings-test"]
addopts = ["--ignore=tests/workerd-test", "--ignore=tests/bindings-test", "--ignore=tests/hyperdrive-test"]

[tool.mypy]
packages = ["pywrangler"]
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/tests/hyperdrive-test/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[project]
name = "hyperdrive-test"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["pytest", "pytest-asyncio<1.2.0", "pymysql", "pg8000"]
9 changes: 9 additions & 0 deletions packages/cli/tests/hyperdrive-test/src/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# pyright: reportMissingImports=false

import pytest
from workers import env as _env


@pytest.fixture
def env():
return _env
165 changes: 165 additions & 0 deletions packages/cli/tests/hyperdrive-test/src/test_mysql.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import uuid

import pymysql
import pytest


def _table_name():
return f"test_{uuid.uuid4().hex[:10]}"


def _connect(env):
hd = env.HYPERDRIVE_MYSQL
return pymysql.connect(
host=hd.host,
port=int(hd.port),
user=hd.user,
password=hd.password,
database=hd.database,
unix_socket=False,
)


@pytest.mark.asyncio
async def test_connect(env):
conn = _connect(env)
cur = conn.cursor()
cur.execute("SELECT 1")
assert cur.fetchone() == (1,)
conn.close()


@pytest.mark.asyncio
async def test_create_insert_select(env):
conn = _connect(env)
table = _table_name()
cur = conn.cursor()
try:
cur.execute(f"CREATE TABLE {table} (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), value INT)")
cur.execute(f"INSERT INTO {table} (name, value) VALUES (%s, %s)", ("alpha", 1))
cur.execute(f"INSERT INTO {table} (name, value) VALUES (%s, %s)", ("beta", 2))
conn.commit()

cur.execute(f"SELECT name, value FROM {table} ORDER BY name")
rows = cur.fetchall()
assert rows == (("alpha", 1), ("beta", 2))
finally:
cur.execute(f"DROP TABLE IF EXISTS {table}")
conn.commit()
conn.close()


@pytest.mark.asyncio
async def test_update(env):
conn = _connect(env)
table = _table_name()
cur = conn.cursor()
try:
cur.execute(f"CREATE TABLE {table} (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), value INT)")
cur.execute(f"INSERT INTO {table} (name, value) VALUES (%s, %s)", ("alpha", 1))
conn.commit()

cur.execute(f"UPDATE {table} SET value = value + 10 WHERE name = %s", ("alpha",))
conn.commit()

cur.execute(f"SELECT value FROM {table} WHERE name = %s", ("alpha",))
assert cur.fetchone() == (11,)
finally:
cur.execute(f"DROP TABLE IF EXISTS {table}")
conn.commit()
conn.close()


@pytest.mark.asyncio
async def test_delete(env):
conn = _connect(env)
table = _table_name()
cur = conn.cursor()
try:
cur.execute(f"CREATE TABLE {table} (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))")
cur.execute(f"INSERT INTO {table} (name) VALUES (%s)", ("alpha",))
cur.execute(f"INSERT INTO {table} (name) VALUES (%s)", ("beta",))
conn.commit()

cur.execute(f"DELETE FROM {table} WHERE name = %s", ("alpha",))
conn.commit()

cur.execute(f"SELECT name FROM {table}")
rows = cur.fetchall()
assert rows == (("beta",),)
finally:
cur.execute(f"DROP TABLE IF EXISTS {table}")
conn.commit()
conn.close()


@pytest.mark.asyncio
async def test_transaction_rollback(env):
conn = _connect(env)
table = _table_name()
cur = conn.cursor()
try:
cur.execute(f"CREATE TABLE {table} (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100)) ENGINE=InnoDB")
conn.commit()

cur.execute(f"INSERT INTO {table} (name) VALUES (%s)", ("should_disappear",))
conn.rollback()

cur.execute(f"SELECT COUNT(*) FROM {table}")
assert cur.fetchone() == (0,)
finally:
cur.execute(f"DROP TABLE IF EXISTS {table}")
conn.commit()
conn.close()


@pytest.mark.asyncio
async def test_multiple_data_types(env):
conn = _connect(env)
table = _table_name()
cur = conn.cursor()
try:
cur.execute(
f"CREATE TABLE {table} ("
"id INT AUTO_INCREMENT PRIMARY KEY, "
"text_col VARCHAR(255), "
"int_col INT, "
"float_col DOUBLE, "
"bool_col BOOLEAN)"
)
cur.execute(
f"INSERT INTO {table} (text_col, int_col, float_col, bool_col) "
"VALUES (%s, %s, %s, %s)",
("hello", 42, 3.14, True),
)
conn.commit()

cur.execute(f"SELECT text_col, int_col, float_col, bool_col FROM {table}")
row = cur.fetchone()
assert row[0] == "hello"
assert row[1] == 42
assert abs(row[2] - 3.14) < 0.001
assert row[3] == 1
finally:
cur.execute(f"DROP TABLE IF EXISTS {table}")
conn.commit()
conn.close()


@pytest.mark.asyncio
async def test_executemany(env):
conn = _connect(env)
table = _table_name()
cur = conn.cursor()
try:
cur.execute(f"CREATE TABLE {table} (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))")
cur.executemany(f"INSERT INTO {table} (name) VALUES (%s)", [("a",), ("b",), ("c",)])
conn.commit()

cur.execute(f"SELECT name FROM {table} ORDER BY name")
rows = cur.fetchall()
assert rows == (("a",), ("b",), ("c",))
finally:
cur.execute(f"DROP TABLE IF EXISTS {table}")
conn.commit()
conn.close()
Loading
Loading