Update unit tests

This commit is contained in:
sean-eskerium
2025-10-31 23:22:05 -04:00
parent 068018a6a3
commit d539a05482
5 changed files with 50 additions and 65 deletions

View File

@@ -63,20 +63,17 @@ class RepositoryConfigRepository:
self._logger = logger.bind(table=self.table_name)
self._logger.info("repository_config_repository_initialized")
def _row_to_model(self, row: dict[str, Any]) -> ConfiguredRepository | None:
def _row_to_model(self, row: dict[str, Any]) -> ConfiguredRepository:
"""Convert database row to ConfiguredRepository model
Args:
row: Database row dictionary
Returns:
ConfiguredRepository model instance, or None if row contains invalid enum values
that cannot be converted (allows callers to skip invalid rows)
ConfiguredRepository model instance
Note:
Invalid enum values are logged but do not raise exceptions, allowing operations
to continue with valid data. This prevents the entire table from becoming unreadable
due to schema mismatches or corrupted data.
Raises:
ValueError: If row contains invalid enum values that cannot be converted
"""
repository_id = row.get("id", "unknown")
@@ -90,10 +87,11 @@ class RepositoryConfigRepository:
repository_id=repository_id,
invalid_commands=default_commands_raw,
error=str(e),
exc_info=True,
action="Skipping invalid row - consider running data migration to fix enum values"
exc_info=True
)
return None
raise ValueError(
f"Database contains invalid workflow steps for repository {repository_id}: {default_commands_raw}"
) from e
# Convert default_sandbox_type from string to SandboxType enum
sandbox_type_raw = row.get("default_sandbox_type", "git_worktree")
@@ -105,10 +103,11 @@ class RepositoryConfigRepository:
repository_id=repository_id,
invalid_type=sandbox_type_raw,
error=str(e),
exc_info=True,
action="Skipping invalid row - consider running data migration to fix enum values"
exc_info=True
)
return None
raise ValueError(
f"Database contains invalid sandbox type for repository {repository_id}: {sandbox_type_raw}"
) from e
return ConfiguredRepository(
id=row["id"],
@@ -137,22 +136,7 @@ class RepositoryConfigRepository:
try:
response = self.client.table(self.table_name).select("*").order("created_at", desc=True).execute()
repositories = []
skipped_count = 0
for row in response.data:
repository = self._row_to_model(row)
if repository is not None:
repositories.append(repository)
else:
skipped_count += 1
if skipped_count > 0:
self._logger.warning(
"repositories_skipped_due_to_invalid_data",
skipped_count=skipped_count,
total_rows=len(response.data),
valid_count=len(repositories)
)
repositories = [self._row_to_model(row) for row in response.data]
self._logger.info(
"repositories_listed",
@@ -175,10 +159,11 @@ class RepositoryConfigRepository:
repository_id: UUID of the repository
Returns:
ConfiguredRepository model or None if not found or if data is invalid
ConfiguredRepository model or None if not found
Raises:
Exception: If database query fails
ValueError: If repository data contains invalid enum values
"""
try:
response = self.client.table(self.table_name).select("*").eq("id", repository_id).execute()
@@ -192,15 +177,6 @@ class RepositoryConfigRepository:
repository = self._row_to_model(response.data[0])
if repository is None:
# Invalid enum values in database - treat as not found
self._logger.warning(
"repository_has_invalid_data",
repository_id=repository_id,
message="Repository exists but contains invalid enum values - consider data migration"
)
return None
self._logger.info(
"repository_retrieved",
repository_id=repository_id,
@@ -257,16 +233,6 @@ class RepositoryConfigRepository:
response = self.client.table(self.table_name).insert(data).execute()
repository = self._row_to_model(response.data[0])
if repository is None:
# This should not happen for newly created repositories with valid data
# but handle defensively
error_msg = "Failed to convert newly created repository to model - data corruption detected"
self._logger.error(
"repository_creation_model_conversion_failed",
repository_url=repository_url,
error=error_msg
)
raise ValueError(error_msg)
self._logger.info(
"repository_created",
@@ -331,18 +297,6 @@ class RepositoryConfigRepository:
return None
repository = self._row_to_model(response.data[0])
if repository is None:
# Repository exists but has invalid enum values - cannot update
error_msg = (
f"Repository {repository_id} exists but contains invalid enum values. "
"Cannot update - consider fixing data first via migration."
)
self._logger.error(
"repository_update_failed_invalid_data",
repository_id=repository_id,
error=error_msg
)
raise ValueError(error_msg)
self._logger.info(
"repository_updated",

View File

@@ -1,7 +1,22 @@
"""Pytest configuration for agent_work_orders tests"""
import os
from unittest.mock import MagicMock, patch
import pytest
# Set ENABLE_AGENT_WORK_ORDERS=true for all tests so health endpoint populates dependencies
os.environ.setdefault("ENABLE_AGENT_WORK_ORDERS", "true")
# Mock get_supabase_client before any modules import it
# This prevents Supabase credential validation during test collection
mock_client = MagicMock()
mock_get_client = patch(
"src.agent_work_orders.state_manager.repository_config_repository.get_supabase_client",
return_value=mock_client
)
mock_get_client.start()
@pytest.fixture(autouse=True)
def reset_structlog():

View File

@@ -157,12 +157,15 @@ def test_config_explicit_url_overrides_discovery_mode():
def test_config_state_storage_type():
"""Test STATE_STORAGE_TYPE configuration"""
import os
import importlib
# Temporarily set the environment variable
old_value = os.environ.get("STATE_STORAGE_TYPE")
os.environ["STATE_STORAGE_TYPE"] = "file"
try:
import src.agent_work_orders.config as config_module
importlib.reload(config_module)
from src.agent_work_orders.config import AgentWorkOrdersConfig
config = AgentWorkOrdersConfig()
assert config.STATE_STORAGE_TYPE == "file"

View File

@@ -46,6 +46,7 @@ def test_server_root_endpoint():
@pytest.mark.unit
@patch("src.agent_work_orders.server.subprocess.run")
@patch.dict("os.environ", {"ENABLE_AGENT_WORK_ORDERS": "true"})
def test_health_check_claude_cli_available(mock_run):
"""Test health check detects Claude CLI availability"""
from src.agent_work_orders.server import app
@@ -65,6 +66,7 @@ def test_health_check_claude_cli_available(mock_run):
@pytest.mark.unit
@patch("src.agent_work_orders.server.subprocess.run")
@patch.dict("os.environ", {"ENABLE_AGENT_WORK_ORDERS": "true"})
def test_health_check_claude_cli_unavailable(mock_run):
"""Test health check handles missing Claude CLI"""
from src.agent_work_orders.server import app
@@ -84,6 +86,7 @@ def test_health_check_claude_cli_unavailable(mock_run):
@pytest.mark.unit
@patch("src.agent_work_orders.server.shutil.which")
@patch.dict("os.environ", {"ENABLE_AGENT_WORK_ORDERS": "true"})
def test_health_check_git_availability(mock_which):
"""Test health check detects git availability"""
from src.agent_work_orders.server import app
@@ -102,7 +105,7 @@ def test_health_check_git_availability(mock_which):
@pytest.mark.unit
@patch("src.agent_work_orders.server.httpx.AsyncClient")
@patch.dict("os.environ", {"ARCHON_SERVER_URL": "http://localhost:8181"})
@patch.dict("os.environ", {"ARCHON_SERVER_URL": "http://localhost:8181", "ENABLE_AGENT_WORK_ORDERS": "true"})
async def test_health_check_server_connectivity(mock_client_class):
"""Test health check validates server connectivity"""
from src.agent_work_orders.server import health_check
@@ -121,7 +124,7 @@ async def test_health_check_server_connectivity(mock_client_class):
@pytest.mark.unit
@patch("src.agent_work_orders.server.httpx.AsyncClient")
@patch.dict("os.environ", {"ARCHON_MCP_URL": "http://localhost:8051"})
@patch.dict("os.environ", {"ARCHON_MCP_URL": "http://localhost:8051", "ENABLE_AGENT_WORK_ORDERS": "true"})
async def test_health_check_mcp_connectivity(mock_client_class):
"""Test health check validates MCP connectivity"""
from src.agent_work_orders.server import health_check
@@ -140,7 +143,7 @@ async def test_health_check_mcp_connectivity(mock_client_class):
@pytest.mark.unit
@patch("src.agent_work_orders.server.httpx.AsyncClient")
@patch.dict("os.environ", {"ARCHON_SERVER_URL": "http://localhost:8181"})
@patch.dict("os.environ", {"ARCHON_SERVER_URL": "http://localhost:8181", "ENABLE_AGENT_WORK_ORDERS": "true"})
async def test_health_check_server_unavailable(mock_client_class):
"""Test health check handles unavailable server"""
from src.agent_work_orders.server import health_check

View File

@@ -61,6 +61,7 @@ async def test_execute_workflow_default_commands(mock_dependencies):
with patch("src.agent_work_orders.workflow_engine.workflow_operations.run_create_branch_step") as mock_branch, \
patch("src.agent_work_orders.workflow_engine.workflow_operations.run_planning_step") as mock_plan, \
patch("src.agent_work_orders.workflow_engine.workflow_operations.run_execute_step") as mock_execute, \
patch("src.agent_work_orders.workflow_engine.workflow_operations.run_review_step") as mock_review, \
patch("src.agent_work_orders.workflow_engine.workflow_operations.run_commit_step") as mock_commit, \
patch("src.agent_work_orders.workflow_engine.workflow_operations.run_create_pr_step") as mock_pr:
@@ -89,6 +90,14 @@ async def test_execute_workflow_default_commands(mock_dependencies):
duration_seconds=30.0,
)
mock_review.return_value = StepExecutionResult(
step=WorkflowStep.REVIEW,
agent_name="Reviewer",
success=True,
output="Review completed, all checks passed",
duration_seconds=10.0,
)
mock_commit.return_value = StepExecutionResult(
step=WorkflowStep.COMMIT,
agent_name="Committer",
@@ -114,10 +123,11 @@ async def test_execute_workflow_default_commands(mock_dependencies):
selected_commands=None, # Should use default
)
# Verify all 5 default commands were executed
# Verify all 6 default commands were executed in order
assert mock_branch.called
assert mock_plan.called
assert mock_execute.called
assert mock_review.called
assert mock_commit.called
assert mock_pr.called