honcho/tests/routes/test_queue_status.py

384 lines
15 KiB
Python

import pytest
from nanoid import generate as generate_nanoid
from src import models
@pytest.mark.asyncio
class TestDeriverStatusEndpoint:
"""Test suite for the /deriver/status endpoint"""
async def test_get_deriver_status_peer_only(self, client, db_session, sample_data):
"""Test getting deriver status filtered by peer only"""
test_workspace, test_peer = sample_data
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}"
)
assert response.status_code == 200
data = response.json()
# Check response structure matches DeriverStatus schema
assert "peer_id" in data
assert "total_work_units" in data
assert "completed_work_units" in data
assert "in_progress_work_units" in data
assert "pending_work_units" in data
assert data["peer_id"] == test_peer.name
assert isinstance(data["total_work_units"], int)
assert isinstance(data["completed_work_units"], int)
assert isinstance(data["in_progress_work_units"], int)
assert isinstance(data["pending_work_units"], int)
async def test_get_deriver_status_session_only(
self, client, db_session, sample_data
):
"""Test getting deriver status filtered by session only"""
test_workspace, test_peer = sample_data
# Create a test session
test_session = models.Session(
workspace_name=test_workspace.name, name=str(generate_nanoid())
)
db_session.add(test_session)
await db_session.commit()
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?session_id={test_session.name}"
)
assert response.status_code == 200
data = response.json()
# Check response structure
assert "session_id" in data
assert "total_work_units" in data
assert "completed_work_units" in data
assert "in_progress_work_units" in data
assert "pending_work_units" in data
assert data["session_id"] == test_session.name
assert isinstance(data["total_work_units"], int)
async def test_get_deriver_status_peer_and_session(
self, client, db_session, sample_data
):
"""Test getting deriver status filtered by both peer and session"""
test_workspace, test_peer = sample_data
# Create a test session
test_session = models.Session(
workspace_name=test_workspace.name, name=str(generate_nanoid())
)
db_session.add(test_session)
await db_session.commit()
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&session_id={test_session.name}"
)
assert response.status_code == 200
data = response.json()
# Should have both peer_id and session_id in response
assert data["peer_id"] == test_peer.name
assert data["session_id"] == test_session.name
assert "total_work_units" in data
assert "completed_work_units" in data
assert "in_progress_work_units" in data
assert "pending_work_units" in data
async def test_get_deriver_status_with_include_sender_true(
self, client, db_session, sample_data
):
"""Test getting deriver status with include_sender=True"""
test_workspace, test_peer = sample_data
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&include_sender=true"
)
assert response.status_code == 200
data = response.json()
assert data["peer_id"] == test_peer.name
assert "total_work_units" in data
async def test_get_deriver_status_with_include_sender_false(
self, client, db_session, sample_data
):
"""Test getting deriver status with include_sender=False (default)"""
test_workspace, test_peer = sample_data
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&include_sender=false"
)
assert response.status_code == 200
data = response.json()
assert data["peer_id"] == test_peer.name
assert "total_work_units" in data
async def test_get_deriver_status_no_parameters(self, client, sample_data):
"""Test getting deriver status without required parameters returns 400"""
test_workspace, _ = sample_data
response = client.get(f"/v2/workspaces/{test_workspace.name}/deriver/status")
assert response.status_code == 400
data = response.json()
assert "detail" in data
assert (
"At least one of 'peer_id' or 'session_id' must be provided"
in data["detail"]
)
async def test_get_deriver_status_nonexistent_peer(self, client, sample_data):
"""Test getting deriver status for nonexistent peer returns empty result"""
test_workspace, _ = sample_data
nonexistent_peer = str(generate_nanoid())
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={nonexistent_peer}"
)
assert response.status_code == 200
data = response.json()
assert data["peer_id"] == nonexistent_peer
assert data["total_work_units"] == 0
assert data["completed_work_units"] == 0
assert data["in_progress_work_units"] == 0
assert data["pending_work_units"] == 0
async def test_get_deriver_status_nonexistent_session(self, client, sample_data):
"""Test getting deriver status for nonexistent session returns empty result"""
test_workspace, _ = sample_data
nonexistent_session = str(generate_nanoid())
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?session_id={nonexistent_session}"
)
assert response.status_code == 200
data = response.json()
assert data["session_id"] == nonexistent_session
assert data["total_work_units"] == 0
assert data["completed_work_units"] == 0
assert data["in_progress_work_units"] == 0
assert data["pending_work_units"] == 0
async def test_get_deriver_status_nonexistent_workspace(self, client):
"""Test getting deriver status for nonexistent workspace returns empty result"""
nonexistent_workspace = str(generate_nanoid())
fake_peer = str(generate_nanoid())
response = client.get(
f"/v2/workspaces/{nonexistent_workspace}/deriver/status?peer_id={fake_peer}"
)
# This should return empty result since workspace/peer doesn't exist
assert response.status_code == 200
data = response.json()
assert data["peer_id"] == fake_peer
assert data["total_work_units"] == 0
assert data["completed_work_units"] == 0
assert data["in_progress_work_units"] == 0
assert data["pending_work_units"] == 0
async def test_get_deriver_status_with_queue_items(
self, client, db_session, sample_data
):
"""Test getting deriver status when there are actual queue items"""
test_workspace, test_peer = sample_data
# Create a test session
test_session = models.Session(
workspace_name=test_workspace.name, name=str(generate_nanoid())
)
db_session.add(test_session)
await db_session.flush()
# Create some queue items to test with
queue_items = [
models.QueueItem(
session_id=test_session.id,
processed=False,
payload={
"task_type": "representation",
"sender_name": test_peer.name,
"target_name": test_peer.name,
"workspace_name": test_workspace.name,
"session_name": test_session.name,
},
),
models.QueueItem(
session_id=test_session.id,
processed=True,
payload={
"task_type": "representation",
"sender_name": test_peer.name,
"target_name": test_peer.name,
"workspace_name": test_workspace.name,
"session_name": test_session.name,
},
),
]
db_session.add_all(queue_items)
await db_session.commit()
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&session_id={test_session.name}"
)
assert response.status_code == 200
data = response.json()
# Should have some work units
assert data["total_work_units"] >= 2
assert data["completed_work_units"] >= 1
assert data["pending_work_units"] >= 1
async def test_get_deriver_status_with_sessions_breakdown(
self, client, db_session, sample_data
):
"""Test getting deriver status shows sessions breakdown when appropriate"""
test_workspace, test_peer = sample_data
# Create multiple test sessions
test_session1 = models.Session(
workspace_name=test_workspace.name, name=str(generate_nanoid())
)
test_session2 = models.Session(
workspace_name=test_workspace.name, name=str(generate_nanoid())
)
db_session.add_all([test_session1, test_session2])
await db_session.flush()
# Create queue items for different sessions
queue_items = [
models.QueueItem(
session_id=test_session1.id,
processed=False,
payload={
"task_type": "representation",
"sender_name": test_peer.name,
"target_name": test_peer.name,
"workspace_name": test_workspace.name,
},
),
models.QueueItem(
session_id=test_session2.id,
processed=True,
payload={
"task_type": "representation",
"sender_name": test_peer.name,
"target_name": test_peer.name,
"workspace_name": test_workspace.name,
},
),
]
db_session.add_all(queue_items)
await db_session.commit()
# Get status for peer only (should include sessions breakdown)
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}"
)
assert response.status_code == 200
data = response.json()
# Should have sessions breakdown when querying by peer only
if "sessions" in data and data["sessions"]:
assert isinstance(data["sessions"], dict)
# Each session should have its own status
for _, session_data in data["sessions"].items():
assert "total_work_units" in session_data
assert "completed_work_units" in session_data
assert "in_progress_work_units" in session_data
assert "pending_work_units" in session_data
async def test_get_deriver_status_empty_parameters(self, client, sample_data):
"""Test various edge cases with empty or invalid parameters"""
test_workspace, _ = sample_data
# Test with empty peer_id
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id="
)
assert response.status_code == 400
# Test with empty session_id
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?session_id="
)
assert response.status_code == 400
async def test_get_deriver_status_boolean_parameter_variations(
self, client, sample_data
):
"""Test different boolean parameter formats for include_sender"""
test_workspace, test_peer = sample_data
# Test with string 'true'
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&include_sender=true"
)
assert response.status_code == 200
# Test with string 'false'
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&include_sender=false"
)
assert response.status_code == 200
# Test with boolean True
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&include_sender=True"
)
assert response.status_code == 200
# Test with boolean False
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status?peer_id={test_peer.name}&include_sender=False"
)
assert response.status_code == 200
async def test_get_deriver_status_response_consistency(
self, client, db_session, sample_data
):
"""Test that response structure is consistent across different parameter combinations"""
test_workspace, test_peer = sample_data
# Create a test session
test_session = models.Session(
workspace_name=test_workspace.name, name=str(generate_nanoid())
)
db_session.add(test_session)
await db_session.commit()
# Test different parameter combinations and ensure consistent response structure
test_cases = [
f"?peer_id={test_peer.name}",
f"?session_id={test_session.name}",
f"?peer_id={test_peer.name}&session_id={test_session.name}",
f"?peer_id={test_peer.name}&include_sender=true",
f"?session_id={test_session.name}&include_sender=false",
]
for params in test_cases:
response = client.get(
f"/v2/workspaces/{test_workspace.name}/deriver/status{params}"
)
assert response.status_code == 200
data = response.json()
# All responses should have these base fields
assert "total_work_units" in data
assert "completed_work_units" in data
assert "in_progress_work_units" in data
assert "pending_work_units" in data
# Verify counts are non-negative integers
assert data["total_work_units"] >= 0
assert data["completed_work_units"] >= 0
assert data["in_progress_work_units"] >= 0
assert data["pending_work_units"] >= 0
# Verify total equals sum of components
assert data["total_work_units"] == (
data["completed_work_units"]
+ data["in_progress_work_units"]
+ data["pending_work_units"]
)