Skip to content

Commit 20f617d

Browse files
authored
Ci cd runs (#2)
* feat: testing out cicd workflow * feat: testing out cicd workflow * test 2 * yeet * yeet * yeet * working postgres runs * working mysql test * working? * fix cicd
1 parent afc0666 commit 20f617d

File tree

7 files changed

+299
-5
lines changed

7 files changed

+299
-5
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: DB Provider Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request_review:
7+
types: [submitted]
8+
branches: [main]
9+
10+
jobs:
11+
test:
12+
if: github.event.review.state == 'approved' || github.event_name == 'push'
13+
runs-on: ubuntu-latest
14+
15+
services:
16+
postgres:
17+
image: postgres:latest
18+
env:
19+
POSTGRES_USER: test
20+
POSTGRES_PASSWORD: test
21+
POSTGRES_DB: test
22+
ports:
23+
- 5432:5432
24+
options: >-
25+
--health-cmd pg_isready
26+
--health-interval 10s
27+
--health-timeout 5s
28+
--health-retries 5
29+
30+
mysql:
31+
image: mysql:latest
32+
env:
33+
MYSQL_ROOT_PASSWORD: test
34+
MYSQL_DATABASE: test
35+
ports:
36+
- 3306:3306
37+
options: >-
38+
--health-cmd="mysqladmin ping"
39+
--health-interval=10s
40+
--health-timeout=5s
41+
--health-retries=3
42+
43+
steps:
44+
- uses: actions/checkout@v3
45+
- uses: actions/setup-python@v4
46+
with:
47+
python-version: '3.11'
48+
- name: Install dependencies
49+
run: |
50+
pip install -r requirements-dev.txt
51+
pip install -e .
52+
- name: Run tests
53+
run: pytest

requirements-dev.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ anthropic
88
click
99
flask
1010
pytest
11+
pytest-postgresql
12+
psycopg2-binary

tabletalk/factories.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ def get_db_provider(config: Dict[str, Any]) -> DatabaseProvider:
5555
elif provider_type == "postgres":
5656
return PostgresProvider(
5757
host=config["host"],
58-
database=config["database"],
58+
port=int(config.get("port", 5432)),
59+
dbname=config["database"],
5960
user=config["user"],
6061
password=config["password"],
6162
)

tabletalk/providers/postgres_provider.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,26 @@
77

88

99
class PostgresProvider(DatabaseProvider):
10-
def __init__(self, host: str, database: str, user: str, password: str):
10+
def __init__(self, host: str, port: int, dbname: str, user: str, password: str):
1111
"""
1212
Initialize PostgreSQL provider with connection string.
1313
1414
Args:
1515
host (str): PostgreSQL host
16-
database (str): PostgreSQL database name
16+
port (int): PostgreSQL port
17+
dbname (str): PostgreSQL database name
1718
user (str): PostgreSQL user
1819
password (str): PostgreSQL password
1920
"""
2021
self.host = host
21-
self.database = database
22+
self.port = port
23+
self.dbname = dbname
2224
self.user = user
2325
self.password = password
2426
self.connection = psycopg2.connect(
2527
host=self.host,
26-
database=self.database,
28+
port=self.port,
29+
dbname=self.dbname,
2730
user=self.user,
2831
password=self.password,
2932
)
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
from typing import Any, Dict, Generator, Union
2+
3+
import mysql.connector
4+
import pytest
5+
from mysql.connector.abstracts import MySQLConnectionAbstract
6+
from mysql.connector.pooling import PooledMySQLConnection
7+
8+
from tabletalk.providers.mysql_provider import MySQLProvider
9+
10+
TEST_CONFIG = {
11+
"host": "localhost",
12+
"port": 3306,
13+
"database": "test",
14+
"user": "root",
15+
"password": "test",
16+
}
17+
18+
ConnectionType = Union[PooledMySQLConnection, MySQLConnectionAbstract]
19+
20+
21+
@pytest.fixture(scope="function")
22+
def mysql_db() -> Generator[Dict[str, Any], None, None]:
23+
"""Set up a simple test database"""
24+
conn: ConnectionType = mysql.connector.connect(
25+
host=TEST_CONFIG["host"],
26+
port=TEST_CONFIG["port"],
27+
user=TEST_CONFIG["user"],
28+
password=TEST_CONFIG["password"],
29+
)
30+
31+
# Handle autocommit based on connection type
32+
if isinstance(conn, PooledMySQLConnection):
33+
real_conn = conn.get_connection()
34+
real_conn.autocommit = True
35+
else:
36+
conn.autocommit = True
37+
38+
with conn.cursor() as cur:
39+
cur.execute(f"DROP DATABASE IF EXISTS {TEST_CONFIG['database']}")
40+
cur.execute(f"CREATE DATABASE {TEST_CONFIG['database']}")
41+
42+
conn.close()
43+
conn = mysql.connector.connect(
44+
host=TEST_CONFIG["host"],
45+
port=TEST_CONFIG["port"],
46+
user=TEST_CONFIG["user"],
47+
password=TEST_CONFIG["password"],
48+
database=TEST_CONFIG["database"],
49+
)
50+
51+
# Handle autocommit again for the new connection
52+
if isinstance(conn, PooledMySQLConnection):
53+
real_conn = conn.get_connection()
54+
real_conn.autocommit = True
55+
else:
56+
conn.autocommit = True
57+
58+
with conn.cursor() as cur:
59+
cur.execute(
60+
"""
61+
CREATE TABLE users (
62+
id INT AUTO_INCREMENT PRIMARY KEY,
63+
name TEXT,
64+
age INTEGER
65+
)
66+
"""
67+
)
68+
cur.execute(
69+
"""
70+
INSERT INTO users (name, age)
71+
VALUES ('Alice', 30), ('Bob', 25)
72+
"""
73+
)
74+
cur.execute(
75+
"""
76+
CREATE VIEW adult_users AS
77+
SELECT name, age FROM users WHERE age >= 18
78+
"""
79+
)
80+
conn.commit()
81+
conn.close()
82+
83+
yield TEST_CONFIG
84+
85+
86+
@pytest.fixture
87+
def mysql_provider(
88+
mysql_db: Dict[str, Any],
89+
) -> Generator[MySQLProvider, None, None]:
90+
provider = MySQLProvider(
91+
host=mysql_db["host"],
92+
port=mysql_db["port"],
93+
database=mysql_db["database"],
94+
user=mysql_db["user"],
95+
password=mysql_db["password"],
96+
)
97+
yield provider
98+
provider.connection.close()
99+
100+
101+
def test_basic_query(mysql_provider: MySQLProvider) -> None:
102+
results = mysql_provider.execute_query("SELECT * FROM users ORDER BY id")
103+
assert len(results) == 2
104+
assert results[0]["name"] == "Alice"
105+
assert results[1]["name"] == "Bob"
106+
107+
108+
def test_table_and_view_schema(mysql_provider: MySQLProvider) -> None:
109+
schemas = mysql_provider.get_compact_tables()
110+
assert len(schemas) == 2
111+
table_schema = next(s for s in schemas if s["t"] == "users")
112+
view_schema = next(s for s in schemas if s["t"] == "adult_users")
113+
assert len(table_schema["f"]) == 3
114+
assert [f["n"] for f in table_schema["f"]] == ["id", "name", "age"]
115+
assert len(view_schema["f"]) == 2
116+
assert [f["n"] for f in view_schema["f"]] == ["name", "age"]
117+
118+
119+
def test_view_query(mysql_provider: MySQLProvider) -> None:
120+
results = mysql_provider.execute_query("SELECT * FROM adult_users ORDER BY name")
121+
assert len(results) == 2
122+
assert results[0]["name"] == "Alice"
123+
assert results[0]["age"] == 30
124+
assert results[1]["name"] == "Bob"
125+
assert results[1]["age"] == 25
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from typing import Any, Dict, Generator
2+
3+
import pytest
4+
from psycopg2 import connect
5+
6+
from tabletalk.providers.postgres_provider import PostgresProvider
7+
8+
TEST_CONFIG = {
9+
"host": "localhost",
10+
"port": 5432,
11+
"dbname": "test_db",
12+
"user": "test",
13+
"password": "test",
14+
}
15+
16+
17+
@pytest.fixture(scope="function")
18+
def postgres_db() -> Generator[Dict[str, Any], None, None]:
19+
"""Set up a simple test database"""
20+
# Create fresh database
21+
admin_conn = connect(
22+
host=TEST_CONFIG["host"],
23+
port=TEST_CONFIG["port"],
24+
user=TEST_CONFIG["user"],
25+
password=TEST_CONFIG["password"],
26+
dbname="postgres",
27+
)
28+
admin_conn.autocommit = True
29+
with admin_conn.cursor() as cur:
30+
cur.execute(f"DROP DATABASE IF EXISTS {TEST_CONFIG['dbname']}")
31+
cur.execute(f"CREATE DATABASE {TEST_CONFIG['dbname']}")
32+
admin_conn.close()
33+
34+
# Set up schema and data
35+
conn = connect(
36+
host=TEST_CONFIG["host"],
37+
port=TEST_CONFIG["port"],
38+
dbname=TEST_CONFIG["dbname"],
39+
user=TEST_CONFIG["user"],
40+
password=TEST_CONFIG["password"],
41+
)
42+
with conn.cursor() as cur:
43+
cur.execute(
44+
"""
45+
CREATE TABLE users (
46+
id SERIAL PRIMARY KEY,
47+
name TEXT,
48+
age INTEGER
49+
)
50+
"""
51+
)
52+
cur.execute(
53+
"""
54+
INSERT INTO users (name, age)
55+
VALUES ('Alice', 30), ('Bob', 25)
56+
"""
57+
)
58+
cur.execute(
59+
"""
60+
CREATE VIEW adult_users AS
61+
SELECT name, age FROM users WHERE age >= 18
62+
"""
63+
)
64+
conn.commit()
65+
conn.close()
66+
67+
yield TEST_CONFIG
68+
69+
70+
# Rest of the code remains unchanged
71+
@pytest.fixture
72+
def postgres_provider(
73+
postgres_db: Dict[str, Any],
74+
) -> Generator[PostgresProvider, None, None]:
75+
provider = PostgresProvider(
76+
host=postgres_db["host"],
77+
port=postgres_db["port"],
78+
dbname=postgres_db["dbname"],
79+
user=postgres_db["user"],
80+
password=postgres_db["password"],
81+
)
82+
yield provider
83+
provider.connection.close()
84+
85+
86+
def test_basic_query(postgres_provider: PostgresProvider) -> None:
87+
results = postgres_provider.execute_query("SELECT * FROM users ORDER BY id")
88+
assert len(results) == 2
89+
assert results[0]["name"] == "Alice"
90+
assert results[1]["name"] == "Bob"
91+
92+
93+
def test_table_and_view_schema(postgres_provider: PostgresProvider) -> None:
94+
schemas = postgres_provider.get_compact_tables()
95+
assert len(schemas) == 2
96+
table_schema = next(s for s in schemas if s["t"] == "users")
97+
view_schema = next(s for s in schemas if s["t"] == "adult_users")
98+
assert len(table_schema["f"]) == 3
99+
assert [f["n"] for f in table_schema["f"]] == ["id", "name", "age"]
100+
assert len(view_schema["f"]) == 2
101+
assert [f["n"] for f in view_schema["f"]] == ["name", "age"]
102+
103+
104+
def test_view_query(postgres_provider: PostgresProvider) -> None:
105+
results = postgres_provider.execute_query("SELECT * FROM adult_users ORDER BY name")
106+
assert len(results) == 2
107+
assert results[0]["name"] == "Alice"
108+
assert results[0]["age"] == 30
109+
assert results[1]["name"] == "Bob"
110+
assert results[1]["age"] == 25
File renamed without changes.

0 commit comments

Comments
 (0)