# 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") assert hasattr(tasks, "memory_consolidation") 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", "memory_consolidation", ] assert set(tasks.__all__) == set(expected_modules)