test(backend): add comprehensive tests for OAuth and agent endpoints

- Added tests for OAuth provider admin and consent endpoints covering edge cases.
- Extended agent-related tests to handle incorrect project associations and lifecycle state transitions.
- Introduced tests for sprint status transitions and validation checks.
- Improved multiline formatting consistency across all test functions.
This commit is contained in:
2026-01-03 01:44:11 +01:00
parent acd18ff694
commit 664415111a
28 changed files with 1530 additions and 216 deletions

View File

@@ -48,7 +48,9 @@ class TestAgentInstanceModel:
db_session.add(instance)
db_session.commit()
retrieved = db_session.query(AgentInstance).filter_by(project_id=project.id).first()
retrieved = (
db_session.query(AgentInstance).filter_by(project_id=project.id).first()
)
assert retrieved is not None
assert retrieved.agent_type_id == agent_type.id
@@ -92,7 +94,10 @@ class TestAgentInstanceModel:
name="Bob",
status=AgentStatus.WORKING,
current_task="Implementing user authentication",
short_term_memory={"context": "Working on auth", "recent_files": ["auth.py"]},
short_term_memory={
"context": "Working on auth",
"recent_files": ["auth.py"],
},
long_term_memory_ref="project-123/agent-456",
session_id="session-abc-123",
last_activity_at=now,
@@ -107,7 +112,10 @@ class TestAgentInstanceModel:
assert retrieved.status == AgentStatus.WORKING
assert retrieved.current_task == "Implementing user authentication"
assert retrieved.short_term_memory == {"context": "Working on auth", "recent_files": ["auth.py"]}
assert retrieved.short_term_memory == {
"context": "Working on auth",
"recent_files": ["auth.py"],
}
assert retrieved.long_term_memory_ref == "project-123/agent-456"
assert retrieved.session_id == "session-abc-123"
assert retrieved.tasks_completed == 5
@@ -116,7 +124,9 @@ class TestAgentInstanceModel:
def test_agent_instance_timestamps(self, db_session):
"""Test that timestamps are automatically set."""
project = Project(id=uuid.uuid4(), name="Timestamp Project", slug="timestamp-project-ai")
project = Project(
id=uuid.uuid4(), name="Timestamp Project", slug="timestamp-project-ai"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Timestamp Agent",
@@ -176,7 +186,9 @@ class TestAgentInstanceStatus:
def test_all_agent_statuses(self, db_session):
"""Test that all agent statuses can be stored."""
project = Project(id=uuid.uuid4(), name="Status Project", slug="status-project-ai")
project = Project(
id=uuid.uuid4(), name="Status Project", slug="status-project-ai"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Status Agent",
@@ -199,12 +211,18 @@ class TestAgentInstanceStatus:
db_session.add(instance)
db_session.commit()
retrieved = db_session.query(AgentInstance).filter_by(id=instance.id).first()
retrieved = (
db_session.query(AgentInstance).filter_by(id=instance.id).first()
)
assert retrieved.status == status
def test_status_update(self, db_session):
"""Test updating agent instance status."""
project = Project(id=uuid.uuid4(), name="Update Status Project", slug="update-status-project-ai")
project = Project(
id=uuid.uuid4(),
name="Update Status Project",
slug="update-status-project-ai",
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Update Status Agent",
@@ -237,7 +255,9 @@ class TestAgentInstanceStatus:
def test_terminate_agent_instance(self, db_session):
"""Test terminating an agent instance."""
project = Project(id=uuid.uuid4(), name="Terminate Project", slug="terminate-project-ai")
project = Project(
id=uuid.uuid4(), name="Terminate Project", slug="terminate-project-ai"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Terminate Agent",
@@ -281,7 +301,9 @@ class TestAgentInstanceMetrics:
def test_increment_metrics(self, db_session):
"""Test incrementing usage metrics."""
project = Project(id=uuid.uuid4(), name="Metrics Project", slug="metrics-project-ai")
project = Project(
id=uuid.uuid4(), name="Metrics Project", slug="metrics-project-ai"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Metrics Agent",
@@ -326,7 +348,9 @@ class TestAgentInstanceMetrics:
def test_large_token_count(self, db_session):
"""Test handling large token counts."""
project = Project(id=uuid.uuid4(), name="Large Tokens Project", slug="large-tokens-project-ai")
project = Project(
id=uuid.uuid4(), name="Large Tokens Project", slug="large-tokens-project-ai"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Large Tokens Agent",
@@ -359,7 +383,9 @@ class TestAgentInstanceShortTermMemory:
def test_store_complex_memory(self, db_session):
"""Test storing complex short-term memory."""
project = Project(id=uuid.uuid4(), name="Memory Project", slug="memory-project-ai")
project = Project(
id=uuid.uuid4(), name="Memory Project", slug="memory-project-ai"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Memory Agent",
@@ -402,7 +428,11 @@ class TestAgentInstanceShortTermMemory:
def test_update_memory(self, db_session):
"""Test updating short-term memory."""
project = Project(id=uuid.uuid4(), name="Update Memory Project", slug="update-memory-project-ai")
project = Project(
id=uuid.uuid4(),
name="Update Memory Project",
slug="update-memory-project-ai",
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Update Memory Agent",

View File

@@ -70,7 +70,10 @@ class TestAgentTypeModel:
assert retrieved.fallback_models == ["claude-sonnet-4-20250514", "gpt-4o"]
assert retrieved.model_params == {"temperature": 0.7, "max_tokens": 4096}
assert retrieved.mcp_servers == ["gitea", "file-system", "slack"]
assert retrieved.tool_permissions == {"allowed": ["*"], "denied": ["dangerous_tool"]}
assert retrieved.tool_permissions == {
"allowed": ["*"],
"denied": ["dangerous_tool"],
}
assert retrieved.is_active is True
def test_agent_type_unique_slug_constraint(self, db_session):
@@ -111,7 +114,9 @@ class TestAgentTypeModel:
db_session.add(agent_type)
db_session.commit()
retrieved = db_session.query(AgentType).filter_by(slug="timestamp-agent").first()
retrieved = (
db_session.query(AgentType).filter_by(slug="timestamp-agent").first()
)
assert isinstance(retrieved.created_at, datetime)
assert isinstance(retrieved.updated_at, datetime)
@@ -252,7 +257,9 @@ class TestAgentTypeJsonFields:
db_session.add(agent_type)
db_session.commit()
retrieved = db_session.query(AgentType).filter_by(slug="permissions-agent").first()
retrieved = (
db_session.query(AgentType).filter_by(slug="permissions-agent").first()
)
assert retrieved.tool_permissions == tool_permissions
assert "file:read" in retrieved.tool_permissions["allowed"]
assert retrieved.tool_permissions["limits"]["file:write"]["max_size_mb"] == 10
@@ -269,7 +276,9 @@ class TestAgentTypeJsonFields:
db_session.add(agent_type)
db_session.commit()
retrieved = db_session.query(AgentType).filter_by(slug="empty-json-agent").first()
retrieved = (
db_session.query(AgentType).filter_by(slug="empty-json-agent").first()
)
assert retrieved.expertise == []
assert retrieved.fallback_models == []
assert retrieved.model_params == {}

View File

@@ -107,7 +107,11 @@ class TestIssueModel:
def test_issue_timestamps(self, db_session):
"""Test that timestamps are automatically set."""
project = Project(id=uuid.uuid4(), name="Timestamp Issue Project", slug="timestamp-issue-project")
project = Project(
id=uuid.uuid4(),
name="Timestamp Issue Project",
slug="timestamp-issue-project",
)
db_session.add(project)
db_session.commit()
@@ -124,7 +128,9 @@ class TestIssueModel:
def test_issue_string_representation(self, db_session):
"""Test the string representation of an issue."""
project = Project(id=uuid.uuid4(), name="Repr Issue Project", slug="repr-issue-project")
project = Project(
id=uuid.uuid4(), name="Repr Issue Project", slug="repr-issue-project"
)
db_session.add(project)
db_session.commit()
@@ -147,7 +153,9 @@ class TestIssueStatus:
def test_all_issue_statuses(self, db_session):
"""Test that all issue statuses can be stored."""
project = Project(id=uuid.uuid4(), name="Status Issue Project", slug="status-issue-project")
project = Project(
id=uuid.uuid4(), name="Status Issue Project", slug="status-issue-project"
)
db_session.add(project)
db_session.commit()
@@ -170,7 +178,11 @@ class TestIssuePriority:
def test_all_issue_priorities(self, db_session):
"""Test that all issue priorities can be stored."""
project = Project(id=uuid.uuid4(), name="Priority Issue Project", slug="priority-issue-project")
project = Project(
id=uuid.uuid4(),
name="Priority Issue Project",
slug="priority-issue-project",
)
db_session.add(project)
db_session.commit()
@@ -193,7 +205,9 @@ class TestIssueSyncStatus:
def test_all_sync_statuses(self, db_session):
"""Test that all sync statuses can be stored."""
project = Project(id=uuid.uuid4(), name="Sync Issue Project", slug="sync-issue-project")
project = Project(
id=uuid.uuid4(), name="Sync Issue Project", slug="sync-issue-project"
)
db_session.add(project)
db_session.commit()
@@ -218,7 +232,9 @@ class TestIssueLabels:
def test_store_labels(self, db_session):
"""Test storing labels list."""
project = Project(id=uuid.uuid4(), name="Labels Issue Project", slug="labels-issue-project")
project = Project(
id=uuid.uuid4(), name="Labels Issue Project", slug="labels-issue-project"
)
db_session.add(project)
db_session.commit()
@@ -239,7 +255,9 @@ class TestIssueLabels:
def test_update_labels(self, db_session):
"""Test updating labels."""
project = Project(id=uuid.uuid4(), name="Update Labels Project", slug="update-labels-project")
project = Project(
id=uuid.uuid4(), name="Update Labels Project", slug="update-labels-project"
)
db_session.add(project)
db_session.commit()
@@ -255,7 +273,9 @@ class TestIssueLabels:
issue.labels = ["updated", "new-label"]
db_session.commit()
retrieved = db_session.query(Issue).filter_by(title="Update Labels Issue").first()
retrieved = (
db_session.query(Issue).filter_by(title="Update Labels Issue").first()
)
assert "initial" not in retrieved.labels
assert "updated" in retrieved.labels
@@ -265,7 +285,9 @@ class TestIssueAssignment:
def test_assign_to_agent(self, db_session):
"""Test assigning an issue to an agent."""
project = Project(id=uuid.uuid4(), name="Agent Assign Project", slug="agent-assign-project")
project = Project(
id=uuid.uuid4(), name="Agent Assign Project", slug="agent-assign-project"
)
agent_type = AgentType(
id=uuid.uuid4(),
name="Test Agent Type",
@@ -295,13 +317,17 @@ class TestIssueAssignment:
db_session.add(issue)
db_session.commit()
retrieved = db_session.query(Issue).filter_by(title="Agent Assignment Issue").first()
retrieved = (
db_session.query(Issue).filter_by(title="Agent Assignment Issue").first()
)
assert retrieved.assigned_agent_id == agent_instance.id
assert retrieved.human_assignee is None
def test_assign_to_human(self, db_session):
"""Test assigning an issue to a human."""
project = Project(id=uuid.uuid4(), name="Human Assign Project", slug="human-assign-project")
project = Project(
id=uuid.uuid4(), name="Human Assign Project", slug="human-assign-project"
)
db_session.add(project)
db_session.commit()
@@ -314,7 +340,9 @@ class TestIssueAssignment:
db_session.add(issue)
db_session.commit()
retrieved = db_session.query(Issue).filter_by(title="Human Assignment Issue").first()
retrieved = (
db_session.query(Issue).filter_by(title="Human Assignment Issue").first()
)
assert retrieved.human_assignee == "developer@example.com"
assert retrieved.assigned_agent_id is None
@@ -324,7 +352,9 @@ class TestIssueSprintAssociation:
def test_assign_issue_to_sprint(self, db_session):
"""Test assigning an issue to a sprint."""
project = Project(id=uuid.uuid4(), name="Sprint Assign Project", slug="sprint-assign-project")
project = Project(
id=uuid.uuid4(), name="Sprint Assign Project", slug="sprint-assign-project"
)
db_session.add(project)
db_session.commit()
@@ -381,7 +411,9 @@ class TestIssueExternalTracker:
db_session.add(issue)
db_session.commit()
retrieved = db_session.query(Issue).filter_by(title="Gitea Synced Issue").first()
retrieved = (
db_session.query(Issue).filter_by(title="Gitea Synced Issue").first()
)
assert retrieved.external_tracker_type == "gitea"
assert retrieved.external_issue_id == "abc123xyz"
assert retrieved.external_issue_number == 42
@@ -405,7 +437,9 @@ class TestIssueExternalTracker:
db_session.add(issue)
db_session.commit()
retrieved = db_session.query(Issue).filter_by(title="GitHub Synced Issue").first()
retrieved = (
db_session.query(Issue).filter_by(title="GitHub Synced Issue").first()
)
assert retrieved.external_tracker_type == "github"
assert retrieved.external_issue_number == 100
@@ -415,7 +449,9 @@ class TestIssueLifecycle:
def test_close_issue(self, db_session):
"""Test closing an issue."""
project = Project(id=uuid.uuid4(), name="Close Issue Project", slug="close-issue-project")
project = Project(
id=uuid.uuid4(), name="Close Issue Project", slug="close-issue-project"
)
db_session.add(project)
db_session.commit()
@@ -440,7 +476,9 @@ class TestIssueLifecycle:
def test_reopen_issue(self, db_session):
"""Test reopening a closed issue."""
project = Project(id=uuid.uuid4(), name="Reopen Issue Project", slug="reopen-issue-project")
project = Project(
id=uuid.uuid4(), name="Reopen Issue Project", slug="reopen-issue-project"
)
db_session.add(project)
db_session.commit()

View File

@@ -100,7 +100,9 @@ class TestProjectModel:
db_session.add(project)
db_session.commit()
retrieved = db_session.query(Project).filter_by(slug="timestamp-project").first()
retrieved = (
db_session.query(Project).filter_by(slug="timestamp-project").first()
)
assert isinstance(retrieved.created_at, datetime)
assert isinstance(retrieved.updated_at, datetime)
@@ -177,7 +179,11 @@ class TestProjectEnums:
db_session.add(project)
db_session.commit()
retrieved = db_session.query(Project).filter_by(slug=f"project-{level.value}").first()
retrieved = (
db_session.query(Project)
.filter_by(slug=f"project-{level.value}")
.first()
)
assert retrieved.autonomy_level == level
def test_all_project_statuses(self, db_session):
@@ -192,7 +198,11 @@ class TestProjectEnums:
db_session.add(project)
db_session.commit()
retrieved = db_session.query(Project).filter_by(slug=f"project-status-{status.value}").first()
retrieved = (
db_session.query(Project)
.filter_by(slug=f"project-status-{status.value}")
.first()
)
assert retrieved.status == status
@@ -227,7 +237,10 @@ class TestProjectSettings:
assert retrieved.settings == complex_settings
assert retrieved.settings["mcp_servers"] == ["gitea", "slack", "file-system"]
assert retrieved.settings["webhook_urls"]["on_issue_created"] == "https://example.com/issue"
assert (
retrieved.settings["webhook_urls"]["on_issue_created"]
== "https://example.com/issue"
)
assert "important" in retrieved.settings["tags"]
def test_empty_settings(self, db_session):

View File

@@ -91,7 +91,11 @@ class TestSprintModel:
def test_sprint_timestamps(self, db_session):
"""Test that timestamps are automatically set."""
project = Project(id=uuid.uuid4(), name="Timestamp Sprint Project", slug="timestamp-sprint-project")
project = Project(
id=uuid.uuid4(),
name="Timestamp Sprint Project",
slug="timestamp-sprint-project",
)
db_session.add(project)
db_session.commit()
@@ -112,7 +116,9 @@ class TestSprintModel:
def test_sprint_string_representation(self, db_session):
"""Test the string representation of a sprint."""
project = Project(id=uuid.uuid4(), name="Repr Sprint Project", slug="repr-sprint-project")
project = Project(
id=uuid.uuid4(), name="Repr Sprint Project", slug="repr-sprint-project"
)
db_session.add(project)
db_session.commit()
@@ -139,7 +145,9 @@ class TestSprintStatus:
def test_all_sprint_statuses(self, db_session):
"""Test that all sprint statuses can be stored."""
project = Project(id=uuid.uuid4(), name="Status Sprint Project", slug="status-sprint-project")
project = Project(
id=uuid.uuid4(), name="Status Sprint Project", slug="status-sprint-project"
)
db_session.add(project)
db_session.commit()
@@ -166,7 +174,9 @@ class TestSprintLifecycle:
def test_start_sprint(self, db_session):
"""Test starting a planned sprint."""
project = Project(id=uuid.uuid4(), name="Start Sprint Project", slug="start-sprint-project")
project = Project(
id=uuid.uuid4(), name="Start Sprint Project", slug="start-sprint-project"
)
db_session.add(project)
db_session.commit()
@@ -194,7 +204,11 @@ class TestSprintLifecycle:
def test_complete_sprint(self, db_session):
"""Test completing an active sprint."""
project = Project(id=uuid.uuid4(), name="Complete Sprint Project", slug="complete-sprint-project")
project = Project(
id=uuid.uuid4(),
name="Complete Sprint Project",
slug="complete-sprint-project",
)
db_session.add(project)
db_session.commit()
@@ -217,13 +231,17 @@ class TestSprintLifecycle:
sprint.velocity = 18
db_session.commit()
retrieved = db_session.query(Sprint).filter_by(name="Sprint to Complete").first()
retrieved = (
db_session.query(Sprint).filter_by(name="Sprint to Complete").first()
)
assert retrieved.status == SprintStatus.COMPLETED
assert retrieved.velocity == 18
def test_cancel_sprint(self, db_session):
"""Test cancelling a sprint."""
project = Project(id=uuid.uuid4(), name="Cancel Sprint Project", slug="cancel-sprint-project")
project = Project(
id=uuid.uuid4(), name="Cancel Sprint Project", slug="cancel-sprint-project"
)
db_session.add(project)
db_session.commit()
@@ -254,7 +272,9 @@ class TestSprintDates:
def test_sprint_date_range(self, db_session):
"""Test storing sprint date range."""
project = Project(id=uuid.uuid4(), name="Date Range Project", slug="date-range-project")
project = Project(
id=uuid.uuid4(), name="Date Range Project", slug="date-range-project"
)
db_session.add(project)
db_session.commit()
@@ -278,7 +298,9 @@ class TestSprintDates:
def test_one_day_sprint(self, db_session):
"""Test creating a one-day sprint."""
project = Project(id=uuid.uuid4(), name="One Day Project", slug="one-day-project")
project = Project(
id=uuid.uuid4(), name="One Day Project", slug="one-day-project"
)
db_session.add(project)
db_session.commit()
@@ -299,7 +321,9 @@ class TestSprintDates:
def test_long_sprint(self, db_session):
"""Test creating a long sprint (e.g., 4 weeks)."""
project = Project(id=uuid.uuid4(), name="Long Sprint Project", slug="long-sprint-project")
project = Project(
id=uuid.uuid4(), name="Long Sprint Project", slug="long-sprint-project"
)
db_session.add(project)
db_session.commit()
@@ -325,7 +349,9 @@ class TestSprintPoints:
def test_sprint_with_zero_points(self, db_session):
"""Test sprint with zero planned points."""
project = Project(id=uuid.uuid4(), name="Zero Points Project", slug="zero-points-project")
project = Project(
id=uuid.uuid4(), name="Zero Points Project", slug="zero-points-project"
)
db_session.add(project)
db_session.commit()
@@ -343,13 +369,17 @@ class TestSprintPoints:
db_session.add(sprint)
db_session.commit()
retrieved = db_session.query(Sprint).filter_by(name="Zero Points Sprint").first()
retrieved = (
db_session.query(Sprint).filter_by(name="Zero Points Sprint").first()
)
assert retrieved.planned_points == 0
assert retrieved.velocity == 0
def test_sprint_velocity_calculation(self, db_session):
"""Test that we can calculate velocity from points."""
project = Project(id=uuid.uuid4(), name="Velocity Project", slug="velocity-project")
project = Project(
id=uuid.uuid4(), name="Velocity Project", slug="velocity-project"
)
db_session.add(project)
db_session.commit()
@@ -376,7 +406,9 @@ class TestSprintPoints:
def test_sprint_overdelivery(self, db_session):
"""Test sprint where completed > planned (stretch goals)."""
project = Project(id=uuid.uuid4(), name="Overdelivery Project", slug="overdelivery-project")
project = Project(
id=uuid.uuid4(), name="Overdelivery Project", slug="overdelivery-project"
)
db_session.add(project)
db_session.commit()
@@ -395,7 +427,9 @@ class TestSprintPoints:
db_session.add(sprint)
db_session.commit()
retrieved = db_session.query(Sprint).filter_by(name="Overdelivery Sprint").first()
retrieved = (
db_session.query(Sprint).filter_by(name="Overdelivery Sprint").first()
)
assert retrieved.velocity > retrieved.planned_points
@@ -404,7 +438,9 @@ class TestSprintNumber:
def test_sequential_sprint_numbers(self, db_session):
"""Test creating sprints with sequential numbers."""
project = Project(id=uuid.uuid4(), name="Sequential Project", slug="sequential-project")
project = Project(
id=uuid.uuid4(), name="Sequential Project", slug="sequential-project"
)
db_session.add(project)
db_session.commit()
@@ -421,14 +457,21 @@ class TestSprintNumber:
db_session.add(sprint)
db_session.commit()
sprints = db_session.query(Sprint).filter_by(project_id=project.id).order_by(Sprint.number).all()
sprints = (
db_session.query(Sprint)
.filter_by(project_id=project.id)
.order_by(Sprint.number)
.all()
)
assert len(sprints) == 5
for i, sprint in enumerate(sprints, 1):
assert sprint.number == i
def test_large_sprint_number(self, db_session):
"""Test sprint with large number (e.g., long-running project)."""
project = Project(id=uuid.uuid4(), name="Large Number Project", slug="large-number-project")
project = Project(
id=uuid.uuid4(), name="Large Number Project", slug="large-number-project"
)
db_session.add(project)
db_session.commit()
@@ -453,7 +496,9 @@ class TestSprintUpdate:
def test_update_sprint_goal(self, db_session):
"""Test updating sprint goal."""
project = Project(id=uuid.uuid4(), name="Update Goal Project", slug="update-goal-project")
project = Project(
id=uuid.uuid4(), name="Update Goal Project", slug="update-goal-project"
)
db_session.add(project)
db_session.commit()
@@ -475,14 +520,18 @@ class TestSprintUpdate:
sprint.goal = "Updated goal with more detail"
db_session.commit()
retrieved = db_session.query(Sprint).filter_by(name="Update Goal Sprint").first()
retrieved = (
db_session.query(Sprint).filter_by(name="Update Goal Sprint").first()
)
assert retrieved.goal == "Updated goal with more detail"
assert retrieved.created_at == original_created_at
assert retrieved.updated_at > original_created_at
def test_update_sprint_dates(self, db_session):
"""Test updating sprint dates."""
project = Project(id=uuid.uuid4(), name="Update Dates Project", slug="update-dates-project")
project = Project(
id=uuid.uuid4(), name="Update Dates Project", slug="update-dates-project"
)
db_session.add(project)
db_session.commit()
@@ -502,6 +551,8 @@ class TestSprintUpdate:
sprint.end_date = today + timedelta(days=21)
db_session.commit()
retrieved = db_session.query(Sprint).filter_by(name="Update Dates Sprint").first()
retrieved = (
db_session.query(Sprint).filter_by(name="Update Dates Sprint").first()
)
delta = retrieved.end_date - retrieved.start_date
assert delta.days == 21