Skip to content

Commit 0570ed5

Browse files
Copilotwey-gu
andcommitted
Fix CI failures: Handle optional dependencies and SSL in tests
- Add proper optional import handling for psycopg2, psycopg, and asyncpg - Fix asyncpg SSL connection issue by explicitly disabling SSL - Make multiple clients test handle missing dependencies gracefully - Fix trailing whitespace in config.py - Update test logic to work with any combination of available drivers Co-authored-by: wey-gu <1651790+wey-gu@users.noreply.github.com>
1 parent c24285c commit 0570ed5

File tree

2 files changed

+82
-37
lines changed

2 files changed

+82
-37
lines changed

src/py_pglite/config.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def get_connection_string(self) -> str:
9191
if self.use_tcp:
9292
# TCP connection string
9393
return f"postgresql+psycopg://postgres:postgres@{self.tcp_host}:{self.tcp_port}/postgres?sslmode=disable"
94-
94+
9595
# For SQLAlchemy with Unix domain sockets, we need to specify the directory
9696
# and use the standard PostgreSQL socket naming convention
9797
socket_dir = str(Path(self.socket_path).parent)
@@ -108,7 +108,7 @@ def get_psycopg_uri(self) -> str:
108108
if self.use_tcp:
109109
# TCP URI
110110
return f"postgresql://postgres:postgres@{self.tcp_host}:{self.tcp_port}/postgres?sslmode=disable"
111-
111+
112112
socket_dir = str(Path(self.socket_path).parent)
113113
# Use standard PostgreSQL URI format for psycopg
114114
return f"postgresql://postgres:postgres@/postgres?host={socket_dir}"
@@ -118,21 +118,21 @@ def get_dsn(self) -> str:
118118
if self.use_tcp:
119119
# TCP DSN
120120
return f"host={self.tcp_host} port={self.tcp_port} dbname=postgres user=postgres password=postgres sslmode=disable"
121-
121+
122122
socket_dir = str(Path(self.socket_path).parent)
123123
# Use key-value format for psycopg DSN, including password
124124
return f"host={socket_dir} dbname=postgres user=postgres password=postgres"
125125

126126
def get_asyncpg_uri(self) -> str:
127127
"""Get PostgreSQL URI for asyncpg usage.
128-
128+
129129
Returns:
130130
PostgreSQL URI string compatible with asyncpg.connect()
131131
"""
132132
if self.use_tcp:
133133
# TCP URI (asyncpg doesn't support sslmode parameter)
134134
return f"postgresql://postgres:postgres@{self.tcp_host}:{self.tcp_port}/postgres"
135-
135+
136136
# Unix socket URI
137137
socket_dir = str(Path(self.socket_path).parent)
138138
return f"postgresql://postgres:postgres@/postgres?host={socket_dir}"

tests/test_tcp_socket_support.py

Lines changed: 77 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,36 @@
22

33
import asyncio
44
import json
5+
56
from io import StringIO
67

7-
import asyncpg
8-
import psycopg
98
import pytest
10-
from sqlalchemy import create_engine, text
9+
10+
from sqlalchemy import create_engine
11+
from sqlalchemy import text
1112
from sqlalchemy.pool import StaticPool
1213

1314
from py_pglite import PGliteConfig
1415
from py_pglite import PGliteManager
1516

1617

18+
# Optional dependencies - only import if available
19+
try:
20+
import asyncpg
21+
except ImportError:
22+
asyncpg = None
23+
24+
try:
25+
import psycopg
26+
except ImportError:
27+
psycopg = None
28+
29+
try:
30+
import psycopg2
31+
except ImportError:
32+
psycopg2 = None
33+
34+
1735
class TestTCPSocketConfiguration:
1836
"""Test TCP socket configuration and validation."""
1937

@@ -337,7 +355,7 @@ def test_sqlalchemy_tcp_mode(self):
337355

338356
conn.commit()
339357

340-
358+
@pytest.mark.skipif(asyncpg is None, reason="asyncpg not available")
341359
def test_asyncpg_tcp_mode(self):
342360
"""Test asyncpg connectivity in TCP mode."""
343361

@@ -352,8 +370,8 @@ async def run_asyncpg_test():
352370
assert "127.0.0.1:15443" in uri
353371
assert "postgresql://postgres:postgres@" in uri
354372

355-
# Connect with asyncpg
356-
conn = await asyncpg.connect(uri)
373+
# Connect with asyncpg - disable SSL since PGlite doesn't support it
374+
conn = await asyncpg.connect(uri, ssl=False)
357375
try:
358376
# Test SELECT
359377
result = await conn.fetchval("SELECT 1")
@@ -423,37 +441,64 @@ def test_multiple_clients_tcp_mode(self):
423441
config = PGliteConfig(use_tcp=True, tcp_port=15444)
424442

425443
with PGliteManager(config) as manager:
426-
# Test psycopg2
427-
conn2 = psycopg2.connect(manager.get_dsn())
428-
cur2 = conn2.cursor()
429-
cur2.execute("CREATE TABLE multi_client (id INT, client TEXT)")
430-
cur2.execute("INSERT INTO multi_client VALUES (1, 'psycopg2')")
431-
conn2.commit()
432-
cur2.close()
433-
conn2.close()
434-
435-
# Test psycopg3
436-
with psycopg.connect(manager.get_dsn()) as conn3:
437-
with conn3.cursor() as cur3:
438-
cur3.execute("INSERT INTO multi_client VALUES (2, 'psycopg3')")
439-
conn3.commit()
440-
441-
# Test SQLAlchemy
444+
clients_tested = []
445+
446+
# Test psycopg2 (if available)
447+
if psycopg2 is not None:
448+
conn2 = psycopg2.connect(manager.get_dsn())
449+
cur2 = conn2.cursor()
450+
cur2.execute("CREATE TABLE multi_client (id INT, client TEXT)")
451+
cur2.execute("INSERT INTO multi_client VALUES (1, 'psycopg2')")
452+
conn2.commit()
453+
cur2.close()
454+
conn2.close()
455+
clients_tested.append("psycopg2")
456+
457+
# Test psycopg3 (if available)
458+
if psycopg is not None:
459+
with psycopg.connect(manager.get_dsn()) as conn3:
460+
with conn3.cursor() as cur3:
461+
# Create table if it doesn't exist (in case psycopg2 wasn't available)
462+
if not clients_tested:
463+
cur3.execute(
464+
"CREATE TABLE multi_client (id INT, client TEXT)"
465+
)
466+
cur3.execute("INSERT INTO multi_client VALUES (2, 'psycopg3')")
467+
conn3.commit()
468+
clients_tested.append("psycopg3")
469+
470+
# Test SQLAlchemy (always available since it's imported directly)
442471
engine = create_engine(
443472
manager.get_connection_string(), poolclass=StaticPool
444473
)
445474
with engine.connect() as conn_sa:
475+
# Create table if it doesn't exist (in case no psycopg was available)
476+
if not clients_tested:
477+
conn_sa.execute(
478+
text("CREATE TABLE multi_client (id INT, client TEXT)")
479+
)
446480
conn_sa.execute(
447481
text("INSERT INTO multi_client VALUES (3, 'sqlalchemy')")
448482
)
449483
conn_sa.commit()
450-
451-
# Verify all inserts with psycopg3
452-
with psycopg.connect(manager.get_dsn()) as conn:
453-
with conn.cursor() as cur:
454-
cur.execute("SELECT COUNT(*) FROM multi_client")
455-
assert cur.fetchone()[0] == 3
456-
457-
cur.execute("SELECT client FROM multi_client ORDER BY id")
458-
clients = [row[0] for row in cur.fetchall()]
459-
assert clients == ["psycopg2", "psycopg3", "sqlalchemy"]
484+
clients_tested.append("sqlalchemy")
485+
486+
# Verify inserts (use psycopg3 if available, otherwise SQLAlchemy)
487+
if psycopg is not None:
488+
with psycopg.connect(manager.get_dsn()) as conn:
489+
with conn.cursor() as cur:
490+
cur.execute("SELECT COUNT(*) FROM multi_client")
491+
expected_count = len(clients_tested)
492+
assert cur.fetchone()[0] == expected_count
493+
494+
cur.execute("SELECT client FROM multi_client ORDER BY id")
495+
actual_clients = [row[0] for row in cur.fetchall()]
496+
# Check that all expected clients were tested
497+
for client in clients_tested:
498+
assert client in actual_clients
499+
else:
500+
# Fallback to SQLAlchemy for verification
501+
with engine.connect() as conn_sa:
502+
result = conn_sa.execute(text("SELECT COUNT(*) FROM multi_client"))
503+
expected_count = len(clients_tested)
504+
assert result.scalar() == expected_count

0 commit comments

Comments
 (0)