# tests/tasks/test_celery_config.py """ Tests for Celery application configuration. These tests verify: - Celery app is properly configured - Queue routing is correctly set up per ADR-003 - Task discovery works for all task modules - Beat schedule is configured for periodic tasks """ class TestCeleryAppConfiguration: """Tests for the Celery application instance configuration.""" def test_celery_app_is_created_with_correct_name(self): """Test that the Celery app is created with 'syndarix' as the name.""" from app.celery_app import celery_app assert celery_app.main == "syndarix" def test_celery_app_uses_redis_broker(self): """Test that Celery is configured to use Redis as the broker.""" from app.celery_app import celery_app from app.core.config import settings # The broker URL should match the settings assert celery_app.conf.broker_url == settings.celery_broker_url def test_celery_app_uses_redis_backend(self): """Test that Celery is configured to use Redis as the result backend.""" from app.celery_app import celery_app from app.core.config import settings assert celery_app.conf.result_backend == settings.celery_result_backend def test_celery_uses_json_serialization(self): """Test that Celery is configured to use JSON for serialization.""" from app.celery_app import celery_app assert celery_app.conf.task_serializer == "json" assert celery_app.conf.result_serializer == "json" assert "json" in celery_app.conf.accept_content def test_celery_uses_utc_timezone(self): """Test that Celery is configured to use UTC timezone.""" from app.celery_app import celery_app assert celery_app.conf.timezone == "UTC" assert celery_app.conf.enable_utc is True def test_celery_has_late_ack_enabled(self): """Test that late acknowledgment is enabled for task reliability.""" from app.celery_app import celery_app # Per ADR-003: Late ack for reliability assert celery_app.conf.task_acks_late is True assert celery_app.conf.task_reject_on_worker_lost is True def test_celery_prefetch_multiplier_is_one(self): """Test that worker prefetch is set to 1 for fair task distribution.""" from app.celery_app import celery_app assert celery_app.conf.worker_prefetch_multiplier == 1 def test_celery_result_expiration(self): """Test that results expire after 24 hours.""" from app.celery_app import celery_app # 86400 seconds = 24 hours assert celery_app.conf.result_expires == 86400 def test_celery_has_time_limits_configured(self): """Test that task time limits are configured per ADR-003.""" from app.celery_app import celery_app # 5 minutes soft limit, 10 minutes hard limit assert celery_app.conf.task_soft_time_limit == 300 assert celery_app.conf.task_time_limit == 600 def test_celery_broker_connection_retry_enabled(self): """Test that broker connection retry is enabled on startup.""" from app.celery_app import celery_app assert celery_app.conf.broker_connection_retry_on_startup is True class TestQueueRoutingConfiguration: """Tests for Celery queue routing configuration per ADR-003.""" def test_default_queue_is_configured(self): """Test that 'default' is set as the default queue.""" from app.celery_app import celery_app assert celery_app.conf.task_default_queue == "default" def test_task_routes_are_configured(self): """Test that task routes are properly configured.""" from app.celery_app import celery_app routes = celery_app.conf.task_routes assert routes is not None assert isinstance(routes, dict) def test_agent_tasks_routed_to_agent_queue(self): """Test that agent tasks are routed to the 'agent' queue.""" from app.celery_app import celery_app routes = celery_app.conf.task_routes assert "app.tasks.agent.*" in routes assert routes["app.tasks.agent.*"]["queue"] == "agent" def test_git_tasks_routed_to_git_queue(self): """Test that git tasks are routed to the 'git' queue.""" from app.celery_app import celery_app routes = celery_app.conf.task_routes assert "app.tasks.git.*" in routes assert routes["app.tasks.git.*"]["queue"] == "git" def test_sync_tasks_routed_to_sync_queue(self): """Test that sync tasks are routed to the 'sync' queue.""" from app.celery_app import celery_app routes = celery_app.conf.task_routes assert "app.tasks.sync.*" in routes assert routes["app.tasks.sync.*"]["queue"] == "sync" def test_default_tasks_routed_to_default_queue(self): """Test that unmatched tasks are routed to the 'default' queue.""" from app.celery_app import celery_app routes = celery_app.conf.task_routes assert "app.tasks.*" in routes assert routes["app.tasks.*"]["queue"] == "default" def test_all_queues_are_defined(self): """Test that all expected queues are defined in task_queues.""" from app.celery_app import celery_app queues = celery_app.conf.task_queues expected_queues = {"agent", "git", "sync", "default"} assert queues is not None assert set(queues.keys()) == expected_queues def test_queue_exchanges_are_configured(self): """Test that each queue has its own exchange configured.""" from app.celery_app import celery_app queues = celery_app.conf.task_queues for queue_name in ["agent", "git", "sync", "default"]: assert queue_name in queues assert queues[queue_name]["exchange"] == queue_name assert queues[queue_name]["routing_key"] == queue_name class TestTaskDiscovery: """Tests for Celery task auto-discovery.""" def test_task_imports_are_configured(self): """Test that task imports are configured for auto-discovery.""" from app.celery_app import celery_app imports = celery_app.conf.imports assert imports is not None assert "app.tasks" in imports def test_agent_tasks_are_discoverable(self): """Test that agent tasks can be discovered and accessed.""" # Force task registration by importing import app.tasks.agent # noqa: F401 from app.celery_app import celery_app # Check that agent tasks are registered registered_tasks = celery_app.tasks assert "app.tasks.agent.run_agent_step" in registered_tasks assert "app.tasks.agent.spawn_agent" in registered_tasks assert "app.tasks.agent.terminate_agent" in registered_tasks def test_git_tasks_are_discoverable(self): """Test that git tasks can be discovered and accessed.""" # Force task registration by importing import app.tasks.git # noqa: F401 from app.celery_app import celery_app registered_tasks = celery_app.tasks assert "app.tasks.git.clone_repository" in registered_tasks assert "app.tasks.git.commit_changes" in registered_tasks assert "app.tasks.git.create_branch" in registered_tasks assert "app.tasks.git.create_pull_request" in registered_tasks assert "app.tasks.git.push_changes" in registered_tasks def test_sync_tasks_are_discoverable(self): """Test that sync tasks can be discovered and accessed.""" # Force task registration by importing import app.tasks.sync # noqa: F401 from app.celery_app import celery_app registered_tasks = celery_app.tasks assert "app.tasks.sync.sync_issues_incremental" in registered_tasks assert "app.tasks.sync.sync_issues_full" in registered_tasks assert "app.tasks.sync.process_webhook_event" in registered_tasks assert "app.tasks.sync.sync_project_issues" in registered_tasks assert "app.tasks.sync.push_issue_to_external" in registered_tasks def test_workflow_tasks_are_discoverable(self): """Test that workflow tasks can be discovered and accessed.""" # Force task registration by importing import app.tasks.workflow # noqa: F401 from app.celery_app import celery_app registered_tasks = celery_app.tasks assert "app.tasks.workflow.recover_stale_workflows" in registered_tasks assert "app.tasks.workflow.execute_workflow_step" in registered_tasks assert "app.tasks.workflow.handle_approval_response" in registered_tasks assert "app.tasks.workflow.start_sprint_workflow" in registered_tasks assert "app.tasks.workflow.start_story_workflow" in registered_tasks def test_cost_tasks_are_discoverable(self): """Test that cost tasks can be discovered and accessed.""" # Force task registration by importing import app.tasks.cost # noqa: F401 from app.celery_app import celery_app registered_tasks = celery_app.tasks assert "app.tasks.cost.aggregate_daily_costs" in registered_tasks assert "app.tasks.cost.check_budget_thresholds" in registered_tasks assert "app.tasks.cost.record_llm_usage" in registered_tasks assert "app.tasks.cost.generate_cost_report" in registered_tasks assert "app.tasks.cost.reset_daily_budget_counters" in registered_tasks class TestBeatSchedule: """Tests for Celery Beat scheduled tasks configuration.""" def test_beat_schedule_is_configured(self): """Test that beat_schedule is configured.""" from app.celery_app import celery_app assert celery_app.conf.beat_schedule is not None assert isinstance(celery_app.conf.beat_schedule, dict) def test_incremental_sync_is_scheduled(self): """Test that incremental issue sync is scheduled per ADR-011.""" from app.celery_app import celery_app schedule = celery_app.conf.beat_schedule assert "sync-issues-incremental" in schedule task_config = schedule["sync-issues-incremental"] assert task_config["task"] == "app.tasks.sync.sync_issues_incremental" assert task_config["schedule"] == 60.0 # Every 60 seconds def test_full_sync_is_scheduled(self): """Test that full issue sync is scheduled per ADR-011.""" from app.celery_app import celery_app schedule = celery_app.conf.beat_schedule assert "sync-issues-full" in schedule task_config = schedule["sync-issues-full"] assert task_config["task"] == "app.tasks.sync.sync_issues_full" assert task_config["schedule"] == 900.0 # Every 15 minutes def test_stale_workflow_recovery_is_scheduled(self): """Test that stale workflow recovery is scheduled per ADR-007.""" from app.celery_app import celery_app schedule = celery_app.conf.beat_schedule assert "recover-stale-workflows" in schedule task_config = schedule["recover-stale-workflows"] assert task_config["task"] == "app.tasks.workflow.recover_stale_workflows" assert task_config["schedule"] == 300.0 # Every 5 minutes def test_daily_cost_aggregation_is_scheduled(self): """Test that daily cost aggregation is scheduled per ADR-012.""" from app.celery_app import celery_app schedule = celery_app.conf.beat_schedule assert "aggregate-daily-costs" in schedule task_config = schedule["aggregate-daily-costs"] assert task_config["task"] == "app.tasks.cost.aggregate_daily_costs" assert task_config["schedule"] == 3600.0 # Every hour class TestTaskModuleExports: """Tests for the task module __init__.py exports.""" def test_tasks_package_exports_all_modules(self): """Test that the tasks package exports all task modules.""" from app import tasks assert hasattr(tasks, "agent") assert hasattr(tasks, "git") assert hasattr(tasks, "sync") assert hasattr(tasks, "workflow") assert hasattr(tasks, "cost") def test_tasks_all_attribute_is_correct(self): """Test that __all__ contains all expected module names.""" from app import tasks expected_modules = ["agent", "git", "sync", "workflow", "cost"] assert set(tasks.__all__) == set(expected_modules)