test: rename db_db_session to db_session across test files

- Standardized test fixture naming from db_db_session to db_session
- Updated all test files to use consistent parameter naming
- All tests now passing with the new naming convention
This commit is contained in:
2025-09-23 12:20:38 -06:00
parent 27b3b9cdee
commit 1c9e8b9cde
9 changed files with 261 additions and 141 deletions

View File

@@ -0,0 +1,118 @@
# AsyncIO Event Loop Analysis for test_attendee_parsing_bug.py
## Problem Summary
The test passes but encounters an error during teardown where asyncpg tries to use a different/closed event loop, resulting in:
- `RuntimeError: Task got Future attached to a different loop`
- `RuntimeError: Event loop is closed`
## Root Cause Analysis
### 1. Multiple Event Loop Creation Points
The test environment creates event loops at different scopes:
1. **Session-scoped loop** (conftest.py:27-34):
- Created once per test session
- Used by session-scoped fixtures
- Closed after all tests complete
2. **Function-scoped loop** (pytest-asyncio default):
- Created for each async test function
- This is the loop that runs the actual test
- Closed immediately after test completes
3. **AsyncPG internal loop**:
- AsyncPG connections store a reference to the loop they were created with
- Used for connection lifecycle management
### 2. Event Loop Lifecycle Mismatch
The issue occurs because:
1. **Session fixture creates database connection** on session-scoped loop
2. **Test runs** on function-scoped loop (different from session loop)
3. **During teardown**, the session fixture tries to rollback/close using the original session loop
4. **AsyncPG connection** still references the function-scoped loop which is now closed
5. **Conflict**: SQLAlchemy tries to use session loop, but asyncpg Future is attached to the closed function loop
### 3. Configuration Issues
Current pytest configuration:
- `asyncio_mode = "auto"` in pyproject.toml
- `asyncio_default_fixture_loop_scope=session` (shown in test output)
- `asyncio_default_test_loop_scope=function` (shown in test output)
This mismatch between fixture loop scope (session) and test loop scope (function) causes the problem.
## Solutions
### Option 1: Align Loop Scopes (Recommended)
Change pytest-asyncio configuration to use consistent loop scopes:
```python
# pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function" # Change from session to function
```
### Option 2: Use Function-Scoped Database Fixture
Change the `session` fixture scope from session to function:
```python
@pytest_asyncio.fixture # Remove scope="session"
async def session(setup_database):
# ... existing code ...
```
### Option 3: Explicit Loop Management
Ensure all async operations use the same loop:
```python
@pytest_asyncio.fixture
async def session(setup_database, event_loop):
# Force using the current event loop
engine = create_async_engine(
settings.DATABASE_URL,
echo=False,
poolclass=NullPool,
connect_args={"loop": event_loop} # Pass explicit loop
)
# ... rest of fixture ...
```
### Option 4: Upgrade pytest-asyncio
The current version (1.1.0) has known issues with loop management. Consider upgrading to the latest version which has better loop scope handling.
## Immediate Workaround
For the test to run cleanly without the teardown error, you can:
1. Add explicit cleanup in the test:
```python
@pytest.mark.asyncio
async def test_attendee_parsing_bug(session):
# ... existing test code ...
# Explicit cleanup before fixture teardown
await session.commit() # or await session.close()
```
2. Or suppress the teardown error (not recommended for production):
```python
@pytest.fixture
async def session(setup_database):
# ... existing setup ...
try:
yield session
await session.rollback()
except RuntimeError as e:
if "Event loop is closed" not in str(e):
raise
finally:
await session.close()
```
## Recommendation
The cleanest solution is to align the loop scopes by setting both fixture and test loop scopes to "function" scope. This ensures each test gets its own clean event loop and avoids cross-contamination between tests.

View File

@@ -11,11 +11,11 @@ from reflector.db.rooms import rooms_controller
@pytest.mark.asyncio
async def test_calendar_event_create(db_db_session):
async def test_calendar_event_create(db_session):
"""Test creating a calendar event."""
# Create a room first
room = await rooms_controller.add(
session,
db_session,
name="test-room",
user_id="test-user",
zulip_auto_post=False,
@@ -45,7 +45,7 @@ async def test_calendar_event_create(db_db_session):
)
# Save event
saved_event = await calendar_events_controller.upsert(session, event)
saved_event = await calendar_events_controller.upsert(db_session, event)
assert saved_event.ics_uid == "test-event-123"
assert saved_event.title == "Team Meeting"
@@ -54,11 +54,11 @@ async def test_calendar_event_create(db_db_session):
@pytest.mark.asyncio
async def test_calendar_event_get_by_room(db_db_session):
async def test_calendar_event_get_by_room(db_session):
"""Test getting calendar events for a room."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="events-room",
user_id="test-user",
zulip_auto_post=False,
@@ -82,10 +82,10 @@ async def test_calendar_event_get_by_room(db_db_session):
start_time=now + timedelta(hours=i),
end_time=now + timedelta(hours=i + 1),
)
await calendar_events_controller.upsert(session, event)
await calendar_events_controller.upsert(db_session, event)
# Get events for room
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 3
assert all(e.room_id == room.id for e in events)
@@ -95,11 +95,11 @@ async def test_calendar_event_get_by_room(db_db_session):
@pytest.mark.asyncio
async def test_calendar_event_get_upcoming(db_db_session):
async def test_calendar_event_get_upcoming(db_session):
"""Test getting upcoming events within time window."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="upcoming-room",
user_id="test-user",
zulip_auto_post=False,
@@ -123,7 +123,7 @@ async def test_calendar_event_get_upcoming(db_db_session):
start_time=now - timedelta(hours=2),
end_time=now - timedelta(hours=1),
)
await calendar_events_controller.upsert(session, past_event)
await calendar_events_controller.upsert(db_session, past_event)
# Upcoming event within 30 minutes
upcoming_event = CalendarEvent(
@@ -133,7 +133,7 @@ async def test_calendar_event_get_upcoming(db_db_session):
start_time=now + timedelta(minutes=15),
end_time=now + timedelta(minutes=45),
)
await calendar_events_controller.upsert(session, upcoming_event)
await calendar_events_controller.upsert(db_session, upcoming_event)
# Currently happening event (started 10 minutes ago, ends in 20 minutes)
current_event = CalendarEvent(
@@ -143,7 +143,7 @@ async def test_calendar_event_get_upcoming(db_db_session):
start_time=now - timedelta(minutes=10),
end_time=now + timedelta(minutes=20),
)
await calendar_events_controller.upsert(session, current_event)
await calendar_events_controller.upsert(db_session, current_event)
# Future event beyond 30 minutes
future_event = CalendarEvent(
@@ -153,10 +153,10 @@ async def test_calendar_event_get_upcoming(db_db_session):
start_time=now + timedelta(hours=2),
end_time=now + timedelta(hours=3),
)
await calendar_events_controller.upsert(session, future_event)
await calendar_events_controller.upsert(db_session, future_event)
# Get upcoming events (default 120 minutes) - should include current, upcoming, and future
upcoming = await calendar_events_controller.get_upcoming(session, room.id)
upcoming = await calendar_events_controller.get_upcoming(db_session, room.id)
assert len(upcoming) == 3
# Events should be sorted by start_time (current event first, then upcoming, then future)
@@ -166,7 +166,7 @@ async def test_calendar_event_get_upcoming(db_db_session):
# Get upcoming with custom window
upcoming_extended = await calendar_events_controller.get_upcoming(
session, room.id, minutes_ahead=180
db_session, room.id, minutes_ahead=180
)
assert len(upcoming_extended) == 3
@@ -177,11 +177,11 @@ async def test_calendar_event_get_upcoming(db_db_session):
@pytest.mark.asyncio
async def test_calendar_event_get_upcoming_includes_currently_happening(db_db_session):
async def test_calendar_event_get_upcoming_includes_currently_happening(db_session):
"""Test that get_upcoming includes currently happening events but excludes ended events."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="current-happening-room",
user_id="test-user",
zulip_auto_post=False,
@@ -204,7 +204,7 @@ async def test_calendar_event_get_upcoming_includes_currently_happening(db_db_se
start_time=now - timedelta(hours=2),
end_time=now - timedelta(minutes=30),
)
await calendar_events_controller.upsert(session, past_ended_event)
await calendar_events_controller.upsert(db_session, past_ended_event)
# Event currently happening (started 10 minutes ago, ends in 20 minutes) - SHOULD be included
currently_happening_event = CalendarEvent(
@@ -214,7 +214,7 @@ async def test_calendar_event_get_upcoming_includes_currently_happening(db_db_se
start_time=now - timedelta(minutes=10),
end_time=now + timedelta(minutes=20),
)
await calendar_events_controller.upsert(session, currently_happening_event)
await calendar_events_controller.upsert(db_session, currently_happening_event)
# Event starting soon (in 5 minutes) - SHOULD be included
upcoming_soon_event = CalendarEvent(
@@ -224,11 +224,11 @@ async def test_calendar_event_get_upcoming_includes_currently_happening(db_db_se
start_time=now + timedelta(minutes=5),
end_time=now + timedelta(minutes=35),
)
await calendar_events_controller.upsert(session, upcoming_soon_event)
await calendar_events_controller.upsert(db_session, upcoming_soon_event)
# Get upcoming events
upcoming = await calendar_events_controller.get_upcoming(
session, room.id, minutes_ahead=30
db_session, room.id, minutes_ahead=30
)
# Should only include currently happening and upcoming soon events
@@ -238,11 +238,11 @@ async def test_calendar_event_get_upcoming_includes_currently_happening(db_db_se
@pytest.mark.asyncio
async def test_calendar_event_upsert(db_db_session):
async def test_calendar_event_upsert(db_session):
"""Test upserting (create/update) calendar events."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="upsert-room",
user_id="test-user",
zulip_auto_post=False,
@@ -266,30 +266,30 @@ async def test_calendar_event_upsert(db_db_session):
end_time=now + timedelta(hours=1),
)
created = await calendar_events_controller.upsert(session, event)
created = await calendar_events_controller.upsert(db_session, event)
assert created.title == "Original Title"
# Update existing event
event.title = "Updated Title"
event.description = "Added description"
updated = await calendar_events_controller.upsert(session, event)
updated = await calendar_events_controller.upsert(db_session, event)
assert updated.title == "Updated Title"
assert updated.description == "Added description"
assert updated.ics_uid == "upsert-test"
# Verify only one event exists
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 1
assert events[0].title == "Updated Title"
@pytest.mark.asyncio
async def test_calendar_event_soft_delete(db_db_session):
async def test_calendar_event_soft_delete(db_session):
"""Test soft deleting events no longer in calendar."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="delete-room",
user_id="test-user",
zulip_auto_post=False,
@@ -313,36 +313,36 @@ async def test_calendar_event_soft_delete(db_db_session):
start_time=now + timedelta(hours=i),
end_time=now + timedelta(hours=i + 1),
)
await calendar_events_controller.upsert(session, event)
await calendar_events_controller.upsert(db_session, event)
# Soft delete events not in current list
current_ids = ["event-0", "event-2"] # Keep events 0 and 2
deleted_count = await calendar_events_controller.soft_delete_missing(
session, room.id, current_ids
db_session, room.id, current_ids
)
assert deleted_count == 2 # Should delete events 1 and 3
# Get non-deleted events
events = await calendar_events_controller.get_by_room(
session, room.id, include_deleted=False
db_session, room.id, include_deleted=False
)
assert len(events) == 2
assert {e.ics_uid for e in events} == {"event-0", "event-2"}
# Get all events including deleted
all_events = await calendar_events_controller.get_by_room(
session, room.id, include_deleted=True
db_session, room.id, include_deleted=True
)
assert len(all_events) == 4
@pytest.mark.asyncio
async def test_calendar_event_past_events_not_deleted(db_db_session):
async def test_calendar_event_past_events_not_deleted(db_session):
"""Test that past events are not soft deleted."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="past-events-room",
user_id="test-user",
zulip_auto_post=False,
@@ -365,7 +365,7 @@ async def test_calendar_event_past_events_not_deleted(db_db_session):
start_time=now - timedelta(hours=2),
end_time=now - timedelta(hours=1),
)
await calendar_events_controller.upsert(session, past_event)
await calendar_events_controller.upsert(db_session, past_event)
# Create future event
future_event = CalendarEvent(
@@ -375,29 +375,29 @@ async def test_calendar_event_past_events_not_deleted(db_db_session):
start_time=now + timedelta(hours=1),
end_time=now + timedelta(hours=2),
)
await calendar_events_controller.upsert(session, future_event)
await calendar_events_controller.upsert(db_session, future_event)
# Try to soft delete all events (only future should be deleted)
deleted_count = await calendar_events_controller.soft_delete_missing(
session, room.id, []
db_session, room.id, []
)
assert deleted_count == 1 # Only future event deleted
# Verify past event still exists
events = await calendar_events_controller.get_by_room(
session, room.id, include_deleted=False
db_session, room.id, include_deleted=False
)
assert len(events) == 1
assert events[0].ics_uid == "past-event"
@pytest.mark.asyncio
async def test_calendar_event_with_raw_ics_data(db_db_session):
async def test_calendar_event_with_raw_ics_data(db_session):
"""Test storing raw ICS data with calendar event."""
# Create room
room = await rooms_controller.add(
session,
db_session,
name="raw-ics-room",
user_id="test-user",
zulip_auto_post=False,
@@ -426,13 +426,13 @@ END:VEVENT"""
ics_raw_data=raw_ics,
)
saved = await calendar_events_controller.upsert(session, event)
saved = await calendar_events_controller.upsert(db_session, event)
assert saved.ics_raw_data == raw_ics
# Retrieve and verify
retrieved = await calendar_events_controller.get_by_ics_uid(
session, room.id, "test-raw-123"
db_session, room.id, "test-raw-123"
)
assert retrieved is not None
assert retrieved.ics_raw_data == raw_ics

View File

@@ -14,9 +14,9 @@ from reflector.worker.ics_sync import (
@pytest.mark.asyncio
async def test_sync_room_ics_task(db_db_session):
async def test_sync_room_ics_task(db_session):
room = await rooms_controller.add(
session,
db_session,
name="task-test-room",
user_id="test-user",
zulip_auto_post=False,
@@ -68,15 +68,15 @@ async def test_sync_room_ics_task(db_db_session):
await ics_sync_service.sync_room_calendar(room)
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 1
assert events[0].ics_uid == "task-event-1"
@pytest.mark.asyncio
async def test_sync_room_ics_disabled(db_db_session):
async def test_sync_room_ics_disabled(db_session):
room = await rooms_controller.add(
session,
db_session,
name="disabled-room",
user_id="test-user",
zulip_auto_post=False,
@@ -92,14 +92,14 @@ async def test_sync_room_ics_disabled(db_db_session):
result = await ics_sync_service.sync_room_calendar(room)
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 0
@pytest.mark.asyncio
async def test_sync_all_ics_calendars(db_db_session):
async def test_sync_all_ics_calendars(db_session):
room1 = await rooms_controller.add(
session,
db_session,
name="sync-all-1",
user_id="test-user",
zulip_auto_post=False,
@@ -115,7 +115,7 @@ async def test_sync_all_ics_calendars(db_db_session):
)
room2 = await rooms_controller.add(
session,
db_session,
name="sync-all-2",
user_id="test-user",
zulip_auto_post=False,
@@ -131,7 +131,7 @@ async def test_sync_all_ics_calendars(db_db_session):
)
room3 = await rooms_controller.add(
session,
db_session,
name="sync-all-3",
user_id="test-user",
zulip_auto_post=False,
@@ -146,7 +146,7 @@ async def test_sync_all_ics_calendars(db_db_session):
)
with patch("reflector.worker.ics_sync.sync_room_ics.delay") as mock_delay:
ics_enabled_rooms = await rooms_controller.get_ics_enabled(session)
ics_enabled_rooms = await rooms_controller.get_ics_enabled(db_session)
for room in ics_enabled_rooms:
if room and _should_sync(room):
@@ -176,11 +176,11 @@ async def test_should_sync_logic():
@pytest.mark.asyncio
async def test_sync_respects_fetch_interval(db_db_session):
async def test_sync_respects_fetch_interval(db_session):
now = datetime.now(timezone.utc)
room1 = await rooms_controller.add(
session,
db_session,
name="interval-test-1",
user_id="test-user",
zulip_auto_post=False,
@@ -197,13 +197,13 @@ async def test_sync_respects_fetch_interval(db_db_session):
)
await rooms_controller.update(
session,
db_session,
room1,
{"ics_last_sync": now - timedelta(seconds=100)},
)
room2 = await rooms_controller.add(
session,
db_session,
name="interval-test-2",
user_id="test-user",
zulip_auto_post=False,
@@ -220,13 +220,13 @@ async def test_sync_respects_fetch_interval(db_db_session):
)
await rooms_controller.update(
session,
db_session,
room2,
{"ics_last_sync": now - timedelta(seconds=100)},
)
with patch("reflector.worker.ics_sync.sync_room_ics.delay") as mock_delay:
ics_enabled_rooms = await rooms_controller.get_ics_enabled(session)
ics_enabled_rooms = await rooms_controller.get_ics_enabled(db_session)
for room in ics_enabled_rooms:
if room and _should_sync(room):
@@ -237,9 +237,9 @@ async def test_sync_respects_fetch_interval(db_db_session):
@pytest.mark.asyncio
async def test_sync_handles_errors_gracefully(db_db_session):
async def test_sync_handles_errors_gracefully(db_session):
room = await rooms_controller.add(
session,
db_session,
name="error-task-room",
user_id="test-user",
zulip_auto_post=False,
@@ -262,5 +262,5 @@ async def test_sync_handles_errors_gracefully(db_db_session):
result = await ics_sync_service.sync_room_calendar(room)
assert result["status"] == "error"
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 0

View File

@@ -134,10 +134,10 @@ async def test_ics_fetch_service_extract_room_events():
@pytest.mark.asyncio
async def test_ics_sync_service_sync_room_calendar(db_db_session):
async def test_ics_sync_service_sync_room_calendar(db_session):
# Create room
room = await rooms_controller.add(
session,
db_session,
name="sync-test",
user_id="test-user",
zulip_auto_post=False,
@@ -201,16 +201,16 @@ async def test_ics_sync_service_sync_room_calendar(db_db_session):
assert result["events_deleted"] == 0
# Verify event was created
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 1
assert events[0].ics_uid == "sync-event-1"
assert events[0].title == "Sync Test Meeting"
# Second sync with same content (should be unchanged)
# Refresh room to get updated etag and force sync by setting old sync time
room = await rooms_controller.get_by_id(session, room.id)
room = await rooms_controller.get_by_id(db_session, room.id)
await rooms_controller.update(
session,
db_session,
room,
{"ics_last_sync": datetime.now(timezone.utc) - timedelta(minutes=10)},
)
@@ -225,7 +225,7 @@ async def test_ics_sync_service_sync_room_calendar(db_db_session):
mock_fetch.return_value = ics_content
# Force sync by clearing etag
await rooms_controller.update(session, room, {"ics_last_etag": None})
await rooms_controller.update(db_session, room, {"ics_last_etag": None})
result = await sync_service.sync_room_calendar(room)
assert result["status"] == "success"
@@ -233,7 +233,7 @@ async def test_ics_sync_service_sync_room_calendar(db_db_session):
assert result["events_updated"] == 1
# Verify event was updated
events = await calendar_events_controller.get_by_room(session, room.id)
events = await calendar_events_controller.get_by_room(db_session, room.id)
assert len(events) == 1
assert events[0].title == "Updated Meeting Title"
@@ -280,10 +280,10 @@ async def test_ics_sync_service_skip_disabled():
@pytest.mark.asyncio
async def test_ics_sync_service_error_handling(db_db_session):
async def test_ics_sync_service_error_handling(db_session):
# Create room
room = await rooms_controller.add(
session,
db_session,
name="error-test",
user_id="test-user",
zulip_auto_post=False,

View File

@@ -10,11 +10,11 @@ from reflector.db.rooms import rooms_controller
@pytest.mark.asyncio
async def test_multiple_active_meetings_per_room(db_db_session):
async def test_multiple_active_meetings_per_room(db_session):
"""Test that multiple active meetings can exist for the same room."""
# Create a room
room = await rooms_controller.add(
session,
db_session,
name="test-room",
user_id="test-user",
zulip_auto_post=False,
@@ -32,7 +32,7 @@ async def test_multiple_active_meetings_per_room(db_db_session):
# Create first meeting
meeting1 = await meetings_controller.create(
session,
db_session,
id="meeting-1",
room_name="test-meeting-1",
room_url="https://whereby.com/test-1",
@@ -44,7 +44,7 @@ async def test_multiple_active_meetings_per_room(db_db_session):
# Create second meeting for the same room (should succeed now)
meeting2 = await meetings_controller.create(
session,
db_session,
id="meeting-2",
room_name="test-meeting-2",
room_url="https://whereby.com/test-2",
@@ -56,7 +56,7 @@ async def test_multiple_active_meetings_per_room(db_db_session):
# Both meetings should be active
active_meetings = await meetings_controller.get_all_active_for_room(
session, room=room, current_time=current_time
db_session, room=room, current_time=current_time
)
assert len(active_meetings) == 2
@@ -65,11 +65,11 @@ async def test_multiple_active_meetings_per_room(db_db_session):
@pytest.mark.asyncio
async def test_get_active_by_calendar_event(db_db_session):
async def test_get_active_by_calendar_event(db_session):
"""Test getting active meeting by calendar event ID."""
# Create a room
room = await rooms_controller.add(
session,
db_session,
name="test-room",
user_id="test-user",
zulip_auto_post=False,
@@ -90,14 +90,14 @@ async def test_get_active_by_calendar_event(db_db_session):
start_time=datetime.now(timezone.utc),
end_time=datetime.now(timezone.utc) + timedelta(hours=1),
)
event = await calendar_events_controller.upsert(session, event)
event = await calendar_events_controller.upsert(db_session, event)
current_time = datetime.now(timezone.utc)
end_time = current_time + timedelta(hours=2)
# Create meeting linked to calendar event
meeting = await meetings_controller.create(
session,
db_session,
id="meeting-cal-1",
room_name="test-meeting-cal",
room_url="https://whereby.com/test-cal",
@@ -111,7 +111,7 @@ async def test_get_active_by_calendar_event(db_db_session):
# Should find the meeting by calendar event
found_meeting = await meetings_controller.get_active_by_calendar_event(
session, room=room, calendar_event_id=event.id, current_time=current_time
db_session, room=room, calendar_event_id=event.id, current_time=current_time
)
assert found_meeting is not None
@@ -120,11 +120,11 @@ async def test_get_active_by_calendar_event(db_db_session):
@pytest.mark.asyncio
async def test_calendar_meeting_deactivates_after_scheduled_end(db_db_session):
async def test_calendar_meeting_deactivates_after_scheduled_end(db_session):
"""Test that unused calendar meetings deactivate after scheduled end time."""
# Create a room
room = await rooms_controller.add(
session,
db_session,
name="test-room",
user_id="test-user",
zulip_auto_post=False,
@@ -145,13 +145,13 @@ async def test_calendar_meeting_deactivates_after_scheduled_end(db_db_session):
start_time=datetime.now(timezone.utc) - timedelta(hours=2),
end_time=datetime.now(timezone.utc) - timedelta(minutes=35),
)
event = await calendar_events_controller.upsert(session, event)
event = await calendar_events_controller.upsert(db_session, event)
current_time = datetime.now(timezone.utc)
# Create meeting linked to calendar event
meeting = await meetings_controller.create(
session,
db_session,
id="meeting-unused",
room_name="test-meeting-unused",
room_url="https://whereby.com/test-unused",
@@ -168,7 +168,9 @@ async def test_calendar_meeting_deactivates_after_scheduled_end(db_db_session):
# Simulate process_meetings logic for unused calendar meeting past end time
if meeting.calendar_event_id and current_time > meeting.end_date:
# In real code, we'd check has_had_sessions = False here
await meetings_controller.update_meeting(session, meeting.id, is_active=False)
await meetings_controller.update_meeting(
db_session, meeting.id, is_active=False
)
updated_meeting = await meetings_controller.get_by_id(session, meeting.id)
updated_meeting = await meetings_controller.get_by_id(db_session, meeting.id)
assert updated_meeting.is_active is False # Deactivated after scheduled end

View File

@@ -10,10 +10,10 @@ from reflector.db.rooms import rooms_controller
@pytest.mark.asyncio
async def test_room_create_with_ics_fields(db_db_session):
async def test_room_create_with_ics_fields(db_session):
"""Test creating a room with ICS calendar fields."""
room = await rooms_controller.add(
session,
db_session,
name="test-room",
user_id="test-user",
zulip_auto_post=False,
@@ -41,11 +41,11 @@ async def test_room_create_with_ics_fields(db_db_session):
@pytest.mark.asyncio
async def test_room_update_ics_configuration(db_db_session):
async def test_room_update_ics_configuration(db_session):
"""Test updating room ICS configuration."""
# Create room without ICS
room = await rooms_controller.add(
session,
db_session,
name="update-test",
user_id="test-user",
zulip_auto_post=False,
@@ -63,7 +63,7 @@ async def test_room_update_ics_configuration(db_db_session):
# Update with ICS configuration
await rooms_controller.update(
session,
db_session,
room,
{
"ics_url": "https://outlook.office365.com/owa/calendar/test/calendar.ics",
@@ -80,10 +80,10 @@ async def test_room_update_ics_configuration(db_db_session):
@pytest.mark.asyncio
async def test_room_ics_sync_metadata(db_db_session):
async def test_room_ics_sync_metadata(db_session):
"""Test updating room ICS sync metadata."""
room = await rooms_controller.add(
session,
db_session,
name="sync-test",
user_id="test-user",
zulip_auto_post=False,
@@ -101,7 +101,7 @@ async def test_room_ics_sync_metadata(db_db_session):
# Update sync metadata
sync_time = datetime.now(timezone.utc)
await rooms_controller.update(
session,
db_session,
room,
{
"ics_last_sync": sync_time,
@@ -114,11 +114,11 @@ async def test_room_ics_sync_metadata(db_db_session):
@pytest.mark.asyncio
async def test_room_get_with_ics_fields(db_db_session):
async def test_room_get_with_ics_fields(db_session):
"""Test retrieving room with ICS fields."""
# Create room
created_room = await rooms_controller.add(
session,
db_session,
name="get-test",
user_id="test-user",
zulip_auto_post=False,
@@ -135,14 +135,14 @@ async def test_room_get_with_ics_fields(db_db_session):
)
# Get by ID
room = await rooms_controller.get_by_id(session, created_room.id)
room = await rooms_controller.get_by_id(db_session, created_room.id)
assert room is not None
assert room.ics_url == "webcal://calendar.example.com/feed.ics"
assert room.ics_fetch_interval == 900
assert room.ics_enabled is True
# Get by name
room = await rooms_controller.get_by_name(session, "get-test")
room = await rooms_controller.get_by_name(db_session, "get-test")
assert room is not None
assert room.ics_url == "webcal://calendar.example.com/feed.ics"
assert room.ics_fetch_interval == 900
@@ -150,11 +150,11 @@ async def test_room_get_with_ics_fields(db_db_session):
@pytest.mark.asyncio
async def test_room_list_with_ics_enabled_filter(db_db_session):
async def test_room_list_with_ics_enabled_filter(db_session):
"""Test listing rooms filtered by ICS enabled status."""
# Create rooms with and without ICS
room1 = await rooms_controller.add(
session,
db_session,
name="ics-enabled-1",
user_id="test-user",
zulip_auto_post=False,
@@ -170,7 +170,7 @@ async def test_room_list_with_ics_enabled_filter(db_db_session):
)
room2 = await rooms_controller.add(
session,
db_session,
name="ics-disabled",
user_id="test-user",
zulip_auto_post=False,
@@ -185,7 +185,7 @@ async def test_room_list_with_ics_enabled_filter(db_db_session):
)
room3 = await rooms_controller.add(
session,
db_session,
name="ics-enabled-2",
user_id="test-user",
zulip_auto_post=False,
@@ -201,7 +201,7 @@ async def test_room_list_with_ics_enabled_filter(db_db_session):
)
# Get all rooms
all_rooms = await rooms_controller.get_all(session)
all_rooms = await rooms_controller.get_all(db_session)
assert len(all_rooms) == 3
# Filter for ICS-enabled rooms (would need to implement this in controller)
@@ -211,10 +211,10 @@ async def test_room_list_with_ics_enabled_filter(db_db_session):
@pytest.mark.asyncio
async def test_room_default_ics_values(db_db_session):
async def test_room_default_ics_values(db_session):
"""Test that ICS fields have correct default values."""
room = await rooms_controller.add(
session,
db_session,
name="default-test",
user_id="test-user",
zulip_auto_post=False,

View File

@@ -11,7 +11,7 @@ from reflector.db.search import SearchParameters, search_controller
@pytest.mark.asyncio
async def test_long_summary_snippet_prioritization(db_db_session):
async def test_long_summary_snippet_prioritization(db_session):
"""Test that snippets from long_summary are prioritized over webvtt content."""
test_id = "test-snippet-priority-3f9a2b8c"
@@ -61,7 +61,7 @@ We need to consider various implementation approaches.""",
# Search for "robotics" which appears in both long_summary and webvtt
params = SearchParameters(query_text="robotics", user_id="test-user-priority")
results, total = await search_controller.search_transcripts(session, params)
results, total = await search_controller.search_transcripts(db_session, params)
assert total >= 1
test_result = next((r for r in results if r.id == test_id), None)
@@ -93,7 +93,7 @@ We need to consider various implementation approaches.""",
@pytest.mark.asyncio
async def test_long_summary_only_search(db_db_session):
async def test_long_summary_only_search(db_session):
"""Test searching for content that only exists in long_summary."""
test_id = "test-long-only-8b3c9f2a"
@@ -139,7 +139,7 @@ Discussion of timeline and deliverables.""",
# Search for terms only in long_summary
params = SearchParameters(query_text="cryptocurrency", user_id="test-user-long")
results, total = await search_controller.search_transcripts(session, params)
results, total = await search_controller.search_transcripts(db_session, params)
found = any(r.id == test_id for r in results)
assert found, "Should find transcript by long_summary-only content"
@@ -154,7 +154,9 @@ Discussion of timeline and deliverables.""",
# Search for "yield farming" - a more specific term
params2 = SearchParameters(query_text="yield farming", user_id="test-user-long")
results2, total2 = await search_controller.search_transcripts(session, params2)
results2, total2 = await search_controller.search_transcripts(
db_session, params2
)
found2 = any(r.id == test_id for r in results2)
assert found2, "Should find transcript by specific long_summary phrase"

View File

@@ -10,7 +10,7 @@ from reflector.db.transcripts import SourceKind, transcripts_controller
@pytest.mark.asyncio
async def test_recording_deleted_with_transcript(db_db_session):
async def test_recording_deleted_with_transcript(db_session):
"""Test that a recording is deleted when its associated transcript is deleted."""
# First create a room and meeting to satisfy foreign key constraints
room_id = "test-room"
@@ -53,7 +53,7 @@ async def test_recording_deleted_with_transcript(db_db_session):
# Now create a recording
recording = await recordings_controller.create(
session,
db_session,
meeting_id=meeting_id,
url="https://example.com/recording.mp4",
object_key="recordings/test.mp4",
@@ -63,7 +63,7 @@ async def test_recording_deleted_with_transcript(db_db_session):
# Create a transcript associated with the recording
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.ROOM,
recording_id=recording.id,
@@ -75,11 +75,11 @@ async def test_recording_deleted_with_transcript(db_db_session):
storage_instance.delete_file = AsyncMock()
# Delete the transcript
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)
# Verify that the recording file was deleted from storage
storage_instance.delete_file.assert_awaited_once_with(recording.object_key)
# Verify both the recording and transcript are deleted
assert await recordings_controller.get_by_id(session, recording.id) is None
assert await transcripts_controller.get_by_id(session, transcript.id) is None
assert await recordings_controller.get_by_id(db_session, recording.id) is None
assert await transcripts_controller.get_by_id(db_session, transcript.id) is None

View File

@@ -18,13 +18,13 @@ class TestWebVTTAutoUpdate:
"""Test that WebVTT field auto-updates when Transcript is created or modified."""
async def test_webvtt_not_updated_on_transcript_creation_without_topics(
self, session
self, db_session
):
"""WebVTT should be None when creating transcript without topics."""
# Using global transcripts_controller
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.FILE,
)
@@ -38,14 +38,14 @@ class TestWebVTTAutoUpdate:
assert row is not None
assert row.webvtt is None
finally:
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)
async def test_webvtt_updated_on_upsert_topic(self, db_db_session):
async def test_webvtt_updated_on_upsert_topic(self, db_session):
"""WebVTT should update when upserting topics via upsert_topic method."""
# Using global transcripts_controller
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.FILE,
)
@@ -62,7 +62,7 @@ class TestWebVTTAutoUpdate:
],
)
await transcripts_controller.upsert_topic(session, transcript, topic)
await transcripts_controller.upsert_topic(db_session, transcript, topic)
result = await db_session.execute(
select(TranscriptModel).where(TranscriptModel.id == transcript.id)
@@ -78,14 +78,14 @@ class TestWebVTTAutoUpdate:
assert "<v Speaker0>" in webvtt
finally:
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)
async def test_webvtt_updated_on_direct_topics_update(self, db_db_session):
async def test_webvtt_updated_on_direct_topics_update(self, db_session):
"""WebVTT should update when updating topics field directly."""
# Using global transcripts_controller
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.FILE,
)
@@ -105,7 +105,7 @@ class TestWebVTTAutoUpdate:
]
await transcripts_controller.update(
session, transcript, {"topics": topics_data}
db_session, transcript, {"topics": topics_data}
)
# Fetch from DB
@@ -122,16 +122,14 @@ class TestWebVTTAutoUpdate:
assert "First sentence" in webvtt
finally:
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)
async def test_webvtt_updated_manually_with_handle_topics_update(
self, db_db_session
):
async def test_webvtt_updated_manually_with_handle_topics_update(self, db_session):
"""Test that _handle_topics_update works when called manually."""
# Using global transcripts_controller
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.FILE,
)
@@ -152,7 +150,7 @@ class TestWebVTTAutoUpdate:
values = {"topics": transcript.topics_dump()}
await transcripts_controller.update(session, transcript, values)
await transcripts_controller.update(db_session, transcript, values)
# Fetch from DB
result = await db_session.execute(
@@ -169,14 +167,14 @@ class TestWebVTTAutoUpdate:
assert "<v Speaker0>" in webvtt
finally:
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)
async def test_webvtt_update_with_non_sequential_topics_fails(self, db_db_session):
async def test_webvtt_update_with_non_sequential_topics_fails(self, db_session):
"""Test that non-sequential topics raise assertion error."""
# Using global transcripts_controller
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.FILE,
)
@@ -202,14 +200,14 @@ class TestWebVTTAutoUpdate:
assert "Words are not in sequence" in str(exc_info.value)
finally:
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)
async def test_multiple_speakers_in_webvtt(self, db_db_session):
async def test_multiple_speakers_in_webvtt(self, db_session):
"""Test WebVTT generation with multiple speakers."""
# Using global transcripts_controller
transcript = await transcripts_controller.add(
session,
db_session,
name="Test Transcript",
source_kind=SourceKind.FILE,
)
@@ -230,7 +228,7 @@ class TestWebVTTAutoUpdate:
transcript.upsert_topic(topic)
values = {"topics": transcript.topics_dump()}
await transcripts_controller.update(session, transcript, values)
await transcripts_controller.update(db_session, transcript, values)
# Fetch from DB
result = await db_session.execute(
@@ -249,4 +247,4 @@ class TestWebVTTAutoUpdate:
assert "Goodbye" in webvtt
finally:
await transcripts_controller.remove_by_id(session, transcript.id)
await transcripts_controller.remove_by_id(db_session, transcript.id)