Skip to content

Commit c3c2324

Browse files
author
Will Flores
committed
test: Add database operations and app lifecycle tests
- Add test_database_extended.py: execute, fetch, fetchrow, fetchval, connect, disconnect - Add test_lifecycle.py: startup/shutdown sequence, app metadata, OpenAPI tags - Database coverage: 53% → 88% - Overall coverage: 48% → 67% - 39/39 tests passing
1 parent e07c889 commit c3c2324

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

tests/test_database_extended.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""Extended database pool tests for coverage improvement."""
2+
import pytest
3+
from unittest.mock import AsyncMock, patch, MagicMock
4+
from core.database import DatabasePool
5+
6+
7+
@pytest.fixture
8+
def db():
9+
return DatabasePool()
10+
11+
12+
@pytest.fixture
13+
def mock_pool():
14+
pool = MagicMock()
15+
conn = AsyncMock()
16+
cm = AsyncMock()
17+
cm.__aenter__.return_value = conn
18+
cm.__aexit__.return_value = False
19+
pool.acquire.return_value = cm
20+
return pool, conn
21+
22+
23+
class TestDatabasePoolOperations:
24+
@pytest.mark.asyncio
25+
async def test_execute(self, db, mock_pool):
26+
pool, conn = mock_pool
27+
conn.execute.return_value = "INSERT 1"
28+
db.pool = pool
29+
result = await db.execute("INSERT INTO test VALUES ($1)", "val")
30+
conn.execute.assert_called_once_with("INSERT INTO test VALUES ($1)", "val")
31+
assert result == "INSERT 1"
32+
33+
@pytest.mark.asyncio
34+
async def test_fetch(self, db, mock_pool):
35+
pool, conn = mock_pool
36+
conn.fetch.return_value = [{"id": 1}, {"id": 2}]
37+
db.pool = pool
38+
result = await db.fetch("SELECT * FROM test")
39+
conn.fetch.assert_called_once()
40+
assert len(result) == 2
41+
42+
@pytest.mark.asyncio
43+
async def test_fetchrow(self, db, mock_pool):
44+
pool, conn = mock_pool
45+
conn.fetchrow.return_value = {"id": 1, "name": "test"}
46+
db.pool = pool
47+
result = await db.fetchrow("SELECT * FROM test WHERE id=$1", 1)
48+
conn.fetchrow.assert_called_once()
49+
assert result["name"] == "test"
50+
51+
@pytest.mark.asyncio
52+
async def test_fetchval(self, db, mock_pool):
53+
pool, conn = mock_pool
54+
conn.fetchval.return_value = 42
55+
db.pool = pool
56+
result = await db.fetchval("SELECT COUNT(*) FROM test")
57+
conn.fetchval.assert_called_once()
58+
assert result == 42
59+
60+
@pytest.mark.asyncio
61+
async def test_connect(self, db):
62+
with patch("asyncpg.create_pool", new_callable=AsyncMock) as mock_create:
63+
mock_create.return_value = AsyncMock()
64+
await db.connect()
65+
mock_create.assert_called_once()
66+
assert db.pool is not None
67+
68+
@pytest.mark.asyncio
69+
async def test_disconnect(self, db):
70+
mock_pool = AsyncMock()
71+
db.pool = mock_pool
72+
await db.disconnect()
73+
mock_pool.close.assert_called_once()
74+
75+
@pytest.mark.asyncio
76+
async def test_disconnect_no_pool(self, db):
77+
db.pool = None
78+
await db.disconnect()

tests/test_lifecycle.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""App lifecycle and startup/shutdown tests."""
2+
import pytest
3+
from unittest.mock import AsyncMock, patch, MagicMock
4+
5+
6+
class TestAppLifecycle:
7+
"""Test application startup and shutdown sequences."""
8+
9+
@pytest.mark.asyncio
10+
async def test_startup_sequence(self):
11+
with patch("main.startup_database", new_callable=AsyncMock) as mock_db, \
12+
patch("main.startup_xrpl", new_callable=AsyncMock) as mock_xrpl, \
13+
patch("main.log_auth_configuration") as mock_auth, \
14+
patch("main.log_rate_limit_config") as mock_rate, \
15+
patch("main.log_security_headers_config") as mock_sec:
16+
from main import app
17+
for handler in app.router.on_startup:
18+
await handler()
19+
mock_db.assert_called_once()
20+
mock_xrpl.assert_called_once()
21+
mock_auth.assert_called_once()
22+
mock_rate.assert_called_once()
23+
mock_sec.assert_called_once()
24+
25+
@pytest.mark.asyncio
26+
async def test_shutdown_sequence(self):
27+
with patch("main.shutdown_xrpl", new_callable=AsyncMock) as mock_xrpl, \
28+
patch("main.shutdown_database", new_callable=AsyncMock) as mock_db:
29+
from main import app
30+
for handler in app.router.on_shutdown:
31+
await handler()
32+
mock_xrpl.assert_called_once()
33+
mock_db.assert_called_once()
34+
35+
def test_app_metadata(self):
36+
from main import app
37+
assert app.title == "Ward Protocol API"
38+
assert app.version == "0.1.0"
39+
assert app.docs_url == "/docs"
40+
assert app.redoc_url == "/redoc"
41+
42+
def test_openapi_tags(self):
43+
from main import app
44+
tags = app.openapi_tags
45+
tag_names = [t["name"] for t in tags]
46+
assert "Public" in tag_names
47+
assert "Permissioned Domains" in tag_names
48+
assert "Admin" in tag_names
49+
assert "Monitoring" in tag_names
50+
51+
def test_docs_description(self):
52+
from main import app
53+
assert "XLS-80" in app.description
54+
assert "Ward Protocol" in app.description

0 commit comments

Comments
 (0)