kubiya-control-plane-api 0.9.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- control_plane_api/LICENSE +676 -0
- control_plane_api/README.md +350 -0
- control_plane_api/__init__.py +4 -0
- control_plane_api/__version__.py +8 -0
- control_plane_api/alembic/README +1 -0
- control_plane_api/alembic/env.py +121 -0
- control_plane_api/alembic/script.py.mako +28 -0
- control_plane_api/alembic/versions/2613c65c3dbe_initial_database_setup.py +32 -0
- control_plane_api/alembic/versions/2df520d4927d_merge_heads.py +28 -0
- control_plane_api/alembic/versions/43abf98d6a01_add_paused_status_to_executions.py +73 -0
- control_plane_api/alembic/versions/6289854264cb_merge_multiple_heads.py +28 -0
- control_plane_api/alembic/versions/6a4d4dc3d8dc_generate_execution_transitions.py +50 -0
- control_plane_api/alembic/versions/87d11cf0a783_add_disconnected_status_to_worker_.py +44 -0
- control_plane_api/alembic/versions/add_ephemeral_queue_support.py +85 -0
- control_plane_api/alembic/versions/add_model_type_to_llm_models.py +31 -0
- control_plane_api/alembic/versions/add_plan_executions_table.py +114 -0
- control_plane_api/alembic/versions/add_trace_span_tables.py +154 -0
- control_plane_api/alembic/versions/add_user_info_to_traces.py +36 -0
- control_plane_api/alembic/versions/adjusting_foreign_keys.py +32 -0
- control_plane_api/alembic/versions/b4983d976db2_initial_tables.py +1128 -0
- control_plane_api/alembic/versions/d181a3b40e71_rename_custom_metadata_to_metadata_in_.py +50 -0
- control_plane_api/alembic/versions/df9117888e82_add_missing_columns.py +82 -0
- control_plane_api/alembic/versions/f25de6ad895a_missing_migrations.py +34 -0
- control_plane_api/alembic/versions/f71305fb69b9_fix_ephemeral_queue_deletion_foreign_key.py +54 -0
- control_plane_api/alembic/versions/mark_local_exec_queues_as_ephemeral.py +68 -0
- control_plane_api/alembic.ini +148 -0
- control_plane_api/api/index.py +12 -0
- control_plane_api/app/__init__.py +11 -0
- control_plane_api/app/activities/__init__.py +20 -0
- control_plane_api/app/activities/agent_activities.py +384 -0
- control_plane_api/app/activities/plan_generation_activities.py +499 -0
- control_plane_api/app/activities/team_activities.py +424 -0
- control_plane_api/app/activities/temporal_cloud_activities.py +588 -0
- control_plane_api/app/config/__init__.py +35 -0
- control_plane_api/app/config/api_config.py +469 -0
- control_plane_api/app/config/config_loader.py +224 -0
- control_plane_api/app/config/model_pricing.py +323 -0
- control_plane_api/app/config/storage_config.py +159 -0
- control_plane_api/app/config.py +115 -0
- control_plane_api/app/controllers/__init__.py +0 -0
- control_plane_api/app/controllers/execution_environment_controller.py +1315 -0
- control_plane_api/app/database.py +135 -0
- control_plane_api/app/exceptions.py +408 -0
- control_plane_api/app/lib/__init__.py +11 -0
- control_plane_api/app/lib/environment.py +65 -0
- control_plane_api/app/lib/event_bus/__init__.py +17 -0
- control_plane_api/app/lib/event_bus/base.py +136 -0
- control_plane_api/app/lib/event_bus/manager.py +335 -0
- control_plane_api/app/lib/event_bus/providers/__init__.py +6 -0
- control_plane_api/app/lib/event_bus/providers/http_provider.py +166 -0
- control_plane_api/app/lib/event_bus/providers/nats_provider.py +324 -0
- control_plane_api/app/lib/event_bus/providers/redis_provider.py +233 -0
- control_plane_api/app/lib/event_bus/providers/websocket_provider.py +497 -0
- control_plane_api/app/lib/job_executor.py +330 -0
- control_plane_api/app/lib/kubiya_client.py +293 -0
- control_plane_api/app/lib/litellm_pricing.py +166 -0
- control_plane_api/app/lib/mcp_validation.py +163 -0
- control_plane_api/app/lib/nats/__init__.py +13 -0
- control_plane_api/app/lib/nats/credentials_manager.py +288 -0
- control_plane_api/app/lib/nats/listener.py +374 -0
- control_plane_api/app/lib/planning_prompt_builder.py +153 -0
- control_plane_api/app/lib/planning_tools/__init__.py +41 -0
- control_plane_api/app/lib/planning_tools/agents.py +409 -0
- control_plane_api/app/lib/planning_tools/agno_toolkit.py +836 -0
- control_plane_api/app/lib/planning_tools/base.py +119 -0
- control_plane_api/app/lib/planning_tools/cognitive_memory_tools.py +403 -0
- control_plane_api/app/lib/planning_tools/context_graph_tools.py +545 -0
- control_plane_api/app/lib/planning_tools/environments.py +218 -0
- control_plane_api/app/lib/planning_tools/knowledge.py +204 -0
- control_plane_api/app/lib/planning_tools/models.py +93 -0
- control_plane_api/app/lib/planning_tools/planning_service.py +646 -0
- control_plane_api/app/lib/planning_tools/resources.py +242 -0
- control_plane_api/app/lib/planning_tools/teams.py +334 -0
- control_plane_api/app/lib/policy_enforcer_client.py +1016 -0
- control_plane_api/app/lib/redis_client.py +803 -0
- control_plane_api/app/lib/sqlalchemy_utils.py +486 -0
- control_plane_api/app/lib/state_transition_tools/__init__.py +7 -0
- control_plane_api/app/lib/state_transition_tools/execution_context.py +388 -0
- control_plane_api/app/lib/storage/__init__.py +20 -0
- control_plane_api/app/lib/storage/base_provider.py +274 -0
- control_plane_api/app/lib/storage/provider_factory.py +157 -0
- control_plane_api/app/lib/storage/vercel_blob_provider.py +468 -0
- control_plane_api/app/lib/supabase.py +71 -0
- control_plane_api/app/lib/supabase_utils.py +138 -0
- control_plane_api/app/lib/task_planning/__init__.py +138 -0
- control_plane_api/app/lib/task_planning/agent_factory.py +308 -0
- control_plane_api/app/lib/task_planning/agents.py +389 -0
- control_plane_api/app/lib/task_planning/cache.py +218 -0
- control_plane_api/app/lib/task_planning/entity_resolver.py +273 -0
- control_plane_api/app/lib/task_planning/helpers.py +293 -0
- control_plane_api/app/lib/task_planning/hooks.py +474 -0
- control_plane_api/app/lib/task_planning/models.py +503 -0
- control_plane_api/app/lib/task_planning/plan_validator.py +166 -0
- control_plane_api/app/lib/task_planning/planning_workflow.py +2911 -0
- control_plane_api/app/lib/task_planning/runner.py +656 -0
- control_plane_api/app/lib/task_planning/streaming_hook.py +213 -0
- control_plane_api/app/lib/task_planning/workflow.py +424 -0
- control_plane_api/app/lib/templating/__init__.py +88 -0
- control_plane_api/app/lib/templating/compiler.py +278 -0
- control_plane_api/app/lib/templating/engine.py +178 -0
- control_plane_api/app/lib/templating/parsers/__init__.py +29 -0
- control_plane_api/app/lib/templating/parsers/base.py +96 -0
- control_plane_api/app/lib/templating/parsers/env.py +85 -0
- control_plane_api/app/lib/templating/parsers/graph.py +112 -0
- control_plane_api/app/lib/templating/parsers/secret.py +87 -0
- control_plane_api/app/lib/templating/parsers/simple.py +81 -0
- control_plane_api/app/lib/templating/resolver.py +366 -0
- control_plane_api/app/lib/templating/types.py +214 -0
- control_plane_api/app/lib/templating/validator.py +201 -0
- control_plane_api/app/lib/temporal_client.py +232 -0
- control_plane_api/app/lib/temporal_credentials_cache.py +178 -0
- control_plane_api/app/lib/temporal_credentials_service.py +203 -0
- control_plane_api/app/lib/validation/__init__.py +24 -0
- control_plane_api/app/lib/validation/runtime_validation.py +388 -0
- control_plane_api/app/main.py +531 -0
- control_plane_api/app/middleware/__init__.py +10 -0
- control_plane_api/app/middleware/auth.py +645 -0
- control_plane_api/app/middleware/exception_handler.py +267 -0
- control_plane_api/app/middleware/prometheus_middleware.py +173 -0
- control_plane_api/app/middleware/rate_limiting.py +384 -0
- control_plane_api/app/middleware/request_id.py +202 -0
- control_plane_api/app/models/__init__.py +40 -0
- control_plane_api/app/models/agent.py +90 -0
- control_plane_api/app/models/analytics.py +206 -0
- control_plane_api/app/models/associations.py +107 -0
- control_plane_api/app/models/auth_user.py +73 -0
- control_plane_api/app/models/context.py +161 -0
- control_plane_api/app/models/custom_integration.py +99 -0
- control_plane_api/app/models/environment.py +64 -0
- control_plane_api/app/models/execution.py +125 -0
- control_plane_api/app/models/execution_transition.py +50 -0
- control_plane_api/app/models/job.py +159 -0
- control_plane_api/app/models/llm_model.py +78 -0
- control_plane_api/app/models/orchestration.py +66 -0
- control_plane_api/app/models/plan_execution.py +102 -0
- control_plane_api/app/models/presence.py +49 -0
- control_plane_api/app/models/project.py +61 -0
- control_plane_api/app/models/project_management.py +85 -0
- control_plane_api/app/models/session.py +29 -0
- control_plane_api/app/models/skill.py +155 -0
- control_plane_api/app/models/system_tables.py +43 -0
- control_plane_api/app/models/task_planning.py +372 -0
- control_plane_api/app/models/team.py +86 -0
- control_plane_api/app/models/trace.py +257 -0
- control_plane_api/app/models/user_profile.py +54 -0
- control_plane_api/app/models/worker.py +221 -0
- control_plane_api/app/models/workflow.py +161 -0
- control_plane_api/app/models/workspace.py +50 -0
- control_plane_api/app/observability/__init__.py +177 -0
- control_plane_api/app/observability/context_logging.py +475 -0
- control_plane_api/app/observability/decorators.py +337 -0
- control_plane_api/app/observability/local_span_processor.py +702 -0
- control_plane_api/app/observability/metrics.py +303 -0
- control_plane_api/app/observability/middleware.py +246 -0
- control_plane_api/app/observability/optional.py +115 -0
- control_plane_api/app/observability/tracing.py +382 -0
- control_plane_api/app/policies/README.md +149 -0
- control_plane_api/app/policies/approved_users.rego +62 -0
- control_plane_api/app/policies/business_hours.rego +51 -0
- control_plane_api/app/policies/rate_limiting.rego +100 -0
- control_plane_api/app/policies/tool_enforcement/README.md +336 -0
- control_plane_api/app/policies/tool_enforcement/bash_command_validation.rego +71 -0
- control_plane_api/app/policies/tool_enforcement/business_hours_enforcement.rego +82 -0
- control_plane_api/app/policies/tool_enforcement/mcp_tool_allowlist.rego +58 -0
- control_plane_api/app/policies/tool_enforcement/production_safeguards.rego +80 -0
- control_plane_api/app/policies/tool_enforcement/role_based_tool_access.rego +44 -0
- control_plane_api/app/policies/tool_restrictions.rego +86 -0
- control_plane_api/app/routers/__init__.py +4 -0
- control_plane_api/app/routers/agents.py +382 -0
- control_plane_api/app/routers/agents_v2.py +1598 -0
- control_plane_api/app/routers/analytics.py +1310 -0
- control_plane_api/app/routers/auth.py +59 -0
- control_plane_api/app/routers/client_config.py +57 -0
- control_plane_api/app/routers/context_graph.py +561 -0
- control_plane_api/app/routers/context_manager.py +577 -0
- control_plane_api/app/routers/custom_integrations.py +490 -0
- control_plane_api/app/routers/enforcer.py +132 -0
- control_plane_api/app/routers/environment_context.py +252 -0
- control_plane_api/app/routers/environments.py +761 -0
- control_plane_api/app/routers/execution_environment.py +847 -0
- control_plane_api/app/routers/executions/__init__.py +28 -0
- control_plane_api/app/routers/executions/router.py +286 -0
- control_plane_api/app/routers/executions/services/__init__.py +22 -0
- control_plane_api/app/routers/executions/services/demo_worker_health.py +156 -0
- control_plane_api/app/routers/executions/services/status_service.py +420 -0
- control_plane_api/app/routers/executions/services/test_worker_health.py +480 -0
- control_plane_api/app/routers/executions/services/worker_health.py +514 -0
- control_plane_api/app/routers/executions/streaming/__init__.py +22 -0
- control_plane_api/app/routers/executions/streaming/deduplication.py +352 -0
- control_plane_api/app/routers/executions/streaming/event_buffer.py +353 -0
- control_plane_api/app/routers/executions/streaming/event_formatter.py +964 -0
- control_plane_api/app/routers/executions/streaming/history_loader.py +588 -0
- control_plane_api/app/routers/executions/streaming/live_source.py +693 -0
- control_plane_api/app/routers/executions/streaming/streamer.py +849 -0
- control_plane_api/app/routers/executions.py +4888 -0
- control_plane_api/app/routers/health.py +165 -0
- control_plane_api/app/routers/health_v2.py +394 -0
- control_plane_api/app/routers/integration_templates.py +496 -0
- control_plane_api/app/routers/integrations.py +287 -0
- control_plane_api/app/routers/jobs.py +1809 -0
- control_plane_api/app/routers/metrics.py +517 -0
- control_plane_api/app/routers/models.py +82 -0
- control_plane_api/app/routers/models_v2.py +628 -0
- control_plane_api/app/routers/plan_executions.py +1481 -0
- control_plane_api/app/routers/plan_generation_async.py +304 -0
- control_plane_api/app/routers/policies.py +669 -0
- control_plane_api/app/routers/presence.py +234 -0
- control_plane_api/app/routers/projects.py +987 -0
- control_plane_api/app/routers/runners.py +379 -0
- control_plane_api/app/routers/runtimes.py +172 -0
- control_plane_api/app/routers/secrets.py +171 -0
- control_plane_api/app/routers/skills.py +1010 -0
- control_plane_api/app/routers/skills_definitions.py +140 -0
- control_plane_api/app/routers/storage.py +456 -0
- control_plane_api/app/routers/task_planning.py +611 -0
- control_plane_api/app/routers/task_queues.py +650 -0
- control_plane_api/app/routers/team_context.py +274 -0
- control_plane_api/app/routers/teams.py +1747 -0
- control_plane_api/app/routers/templates.py +248 -0
- control_plane_api/app/routers/traces.py +571 -0
- control_plane_api/app/routers/websocket_client.py +479 -0
- control_plane_api/app/routers/websocket_executions_status.py +437 -0
- control_plane_api/app/routers/websocket_gateway.py +323 -0
- control_plane_api/app/routers/websocket_traces.py +576 -0
- control_plane_api/app/routers/worker_queues.py +2555 -0
- control_plane_api/app/routers/worker_websocket.py +419 -0
- control_plane_api/app/routers/workers.py +1004 -0
- control_plane_api/app/routers/workflows.py +204 -0
- control_plane_api/app/runtimes/__init__.py +6 -0
- control_plane_api/app/runtimes/validation.py +344 -0
- control_plane_api/app/schemas/__init__.py +1 -0
- control_plane_api/app/schemas/job_schemas.py +302 -0
- control_plane_api/app/schemas/mcp_schemas.py +311 -0
- control_plane_api/app/schemas/template_schemas.py +133 -0
- control_plane_api/app/schemas/trace_schemas.py +168 -0
- control_plane_api/app/schemas/worker_queue_observability_schemas.py +165 -0
- control_plane_api/app/services/__init__.py +1 -0
- control_plane_api/app/services/agno_planning_strategy.py +233 -0
- control_plane_api/app/services/agno_service.py +838 -0
- control_plane_api/app/services/claude_code_planning_service.py +203 -0
- control_plane_api/app/services/context_graph_client.py +224 -0
- control_plane_api/app/services/custom_integration_service.py +415 -0
- control_plane_api/app/services/integration_resolution_service.py +345 -0
- control_plane_api/app/services/litellm_service.py +394 -0
- control_plane_api/app/services/plan_generator.py +79 -0
- control_plane_api/app/services/planning_strategy.py +66 -0
- control_plane_api/app/services/planning_strategy_factory.py +118 -0
- control_plane_api/app/services/policy_service.py +615 -0
- control_plane_api/app/services/state_transition_service.py +755 -0
- control_plane_api/app/services/storage_service.py +593 -0
- control_plane_api/app/services/temporal_cloud_provisioning.py +150 -0
- control_plane_api/app/services/toolsets/context_graph_skill.py +432 -0
- control_plane_api/app/services/trace_retention.py +354 -0
- control_plane_api/app/services/worker_queue_metrics_service.py +190 -0
- control_plane_api/app/services/workflow_cancellation_manager.py +135 -0
- control_plane_api/app/services/workflow_operations_service.py +611 -0
- control_plane_api/app/skills/__init__.py +100 -0
- control_plane_api/app/skills/base.py +239 -0
- control_plane_api/app/skills/builtin/__init__.py +37 -0
- control_plane_api/app/skills/builtin/agent_communication/__init__.py +8 -0
- control_plane_api/app/skills/builtin/agent_communication/skill.py +246 -0
- control_plane_api/app/skills/builtin/code_ingestion/__init__.py +4 -0
- control_plane_api/app/skills/builtin/code_ingestion/skill.py +267 -0
- control_plane_api/app/skills/builtin/cognitive_memory/__init__.py +4 -0
- control_plane_api/app/skills/builtin/cognitive_memory/skill.py +174 -0
- control_plane_api/app/skills/builtin/contextual_awareness/__init__.py +4 -0
- control_plane_api/app/skills/builtin/contextual_awareness/skill.py +387 -0
- control_plane_api/app/skills/builtin/data_visualization/__init__.py +4 -0
- control_plane_api/app/skills/builtin/data_visualization/skill.py +154 -0
- control_plane_api/app/skills/builtin/docker/__init__.py +4 -0
- control_plane_api/app/skills/builtin/docker/skill.py +104 -0
- control_plane_api/app/skills/builtin/file_generation/__init__.py +4 -0
- control_plane_api/app/skills/builtin/file_generation/skill.py +94 -0
- control_plane_api/app/skills/builtin/file_system/__init__.py +4 -0
- control_plane_api/app/skills/builtin/file_system/skill.py +110 -0
- control_plane_api/app/skills/builtin/knowledge_api/__init__.py +5 -0
- control_plane_api/app/skills/builtin/knowledge_api/skill.py +124 -0
- control_plane_api/app/skills/builtin/python/__init__.py +4 -0
- control_plane_api/app/skills/builtin/python/skill.py +92 -0
- control_plane_api/app/skills/builtin/remote_filesystem/__init__.py +5 -0
- control_plane_api/app/skills/builtin/remote_filesystem/skill.py +170 -0
- control_plane_api/app/skills/builtin/shell/__init__.py +4 -0
- control_plane_api/app/skills/builtin/shell/skill.py +161 -0
- control_plane_api/app/skills/builtin/slack/__init__.py +3 -0
- control_plane_api/app/skills/builtin/slack/skill.py +302 -0
- control_plane_api/app/skills/builtin/workflow_executor/__init__.py +4 -0
- control_plane_api/app/skills/builtin/workflow_executor/skill.py +469 -0
- control_plane_api/app/skills/business_intelligence.py +189 -0
- control_plane_api/app/skills/config.py +63 -0
- control_plane_api/app/skills/loaders/__init__.py +14 -0
- control_plane_api/app/skills/loaders/base.py +73 -0
- control_plane_api/app/skills/loaders/filesystem_loader.py +199 -0
- control_plane_api/app/skills/registry.py +125 -0
- control_plane_api/app/utils/helpers.py +12 -0
- control_plane_api/app/utils/workflow_executor.py +354 -0
- control_plane_api/app/workflows/__init__.py +11 -0
- control_plane_api/app/workflows/agent_execution.py +520 -0
- control_plane_api/app/workflows/agent_execution_with_skills.py +223 -0
- control_plane_api/app/workflows/namespace_provisioning.py +326 -0
- control_plane_api/app/workflows/plan_generation.py +254 -0
- control_plane_api/app/workflows/team_execution.py +442 -0
- control_plane_api/scripts/seed_models.py +240 -0
- control_plane_api/scripts/validate_existing_tool_names.py +492 -0
- control_plane_api/shared/__init__.py +8 -0
- control_plane_api/shared/version.py +17 -0
- control_plane_api/test_deduplication.py +274 -0
- control_plane_api/test_executor_deduplication_e2e.py +309 -0
- control_plane_api/test_job_execution_e2e.py +283 -0
- control_plane_api/test_real_integration.py +193 -0
- control_plane_api/version.py +38 -0
- control_plane_api/worker/__init__.py +0 -0
- control_plane_api/worker/activities/__init__.py +0 -0
- control_plane_api/worker/activities/agent_activities.py +1585 -0
- control_plane_api/worker/activities/approval_activities.py +234 -0
- control_plane_api/worker/activities/job_activities.py +199 -0
- control_plane_api/worker/activities/runtime_activities.py +1167 -0
- control_plane_api/worker/activities/skill_activities.py +282 -0
- control_plane_api/worker/activities/team_activities.py +479 -0
- control_plane_api/worker/agent_runtime_server.py +370 -0
- control_plane_api/worker/binary_manager.py +333 -0
- control_plane_api/worker/config/__init__.py +31 -0
- control_plane_api/worker/config/worker_config.py +273 -0
- control_plane_api/worker/control_plane_client.py +1491 -0
- control_plane_api/worker/examples/analytics_integration_example.py +362 -0
- control_plane_api/worker/health_monitor.py +159 -0
- control_plane_api/worker/metrics.py +237 -0
- control_plane_api/worker/models/__init__.py +1 -0
- control_plane_api/worker/models/error_events.py +105 -0
- control_plane_api/worker/models/inputs.py +89 -0
- control_plane_api/worker/runtimes/__init__.py +35 -0
- control_plane_api/worker/runtimes/agent_runtime/runtime.py +485 -0
- control_plane_api/worker/runtimes/agno/__init__.py +34 -0
- control_plane_api/worker/runtimes/agno/config.py +248 -0
- control_plane_api/worker/runtimes/agno/hooks.py +385 -0
- control_plane_api/worker/runtimes/agno/mcp_builder.py +195 -0
- control_plane_api/worker/runtimes/agno/runtime.py +1063 -0
- control_plane_api/worker/runtimes/agno/utils.py +163 -0
- control_plane_api/worker/runtimes/base.py +979 -0
- control_plane_api/worker/runtimes/claude_code/__init__.py +38 -0
- control_plane_api/worker/runtimes/claude_code/cleanup.py +184 -0
- control_plane_api/worker/runtimes/claude_code/client_pool.py +529 -0
- control_plane_api/worker/runtimes/claude_code/config.py +829 -0
- control_plane_api/worker/runtimes/claude_code/hooks.py +482 -0
- control_plane_api/worker/runtimes/claude_code/litellm_proxy.py +1702 -0
- control_plane_api/worker/runtimes/claude_code/mcp_builder.py +467 -0
- control_plane_api/worker/runtimes/claude_code/mcp_discovery.py +558 -0
- control_plane_api/worker/runtimes/claude_code/runtime.py +1546 -0
- control_plane_api/worker/runtimes/claude_code/tool_mapper.py +403 -0
- control_plane_api/worker/runtimes/claude_code/utils.py +149 -0
- control_plane_api/worker/runtimes/factory.py +173 -0
- control_plane_api/worker/runtimes/model_utils.py +107 -0
- control_plane_api/worker/runtimes/validation.py +93 -0
- control_plane_api/worker/services/__init__.py +1 -0
- control_plane_api/worker/services/agent_communication_tools.py +908 -0
- control_plane_api/worker/services/agent_executor.py +485 -0
- control_plane_api/worker/services/agent_executor_v2.py +793 -0
- control_plane_api/worker/services/analytics_collector.py +457 -0
- control_plane_api/worker/services/analytics_service.py +464 -0
- control_plane_api/worker/services/approval_tools.py +310 -0
- control_plane_api/worker/services/approval_tools_agno.py +207 -0
- control_plane_api/worker/services/cancellation_manager.py +177 -0
- control_plane_api/worker/services/code_ingestion_tools.py +465 -0
- control_plane_api/worker/services/contextual_awareness_tools.py +405 -0
- control_plane_api/worker/services/data_visualization.py +834 -0
- control_plane_api/worker/services/event_publisher.py +531 -0
- control_plane_api/worker/services/jira_tools.py +257 -0
- control_plane_api/worker/services/remote_filesystem_tools.py +498 -0
- control_plane_api/worker/services/runtime_analytics.py +328 -0
- control_plane_api/worker/services/session_service.py +365 -0
- control_plane_api/worker/services/skill_context_enhancement.py +181 -0
- control_plane_api/worker/services/skill_factory.py +471 -0
- control_plane_api/worker/services/system_prompt_enhancement.py +410 -0
- control_plane_api/worker/services/team_executor.py +715 -0
- control_plane_api/worker/services/team_executor_v2.py +1866 -0
- control_plane_api/worker/services/tool_enforcement.py +254 -0
- control_plane_api/worker/services/workflow_executor/__init__.py +52 -0
- control_plane_api/worker/services/workflow_executor/event_processor.py +287 -0
- control_plane_api/worker/services/workflow_executor/event_publisher.py +210 -0
- control_plane_api/worker/services/workflow_executor/executors/__init__.py +15 -0
- control_plane_api/worker/services/workflow_executor/executors/base.py +270 -0
- control_plane_api/worker/services/workflow_executor/executors/json_executor.py +50 -0
- control_plane_api/worker/services/workflow_executor/executors/python_executor.py +50 -0
- control_plane_api/worker/services/workflow_executor/models.py +142 -0
- control_plane_api/worker/services/workflow_executor_tools.py +1748 -0
- control_plane_api/worker/skills/__init__.py +12 -0
- control_plane_api/worker/skills/builtin/context_graph_search/README.md +213 -0
- control_plane_api/worker/skills/builtin/context_graph_search/__init__.py +5 -0
- control_plane_api/worker/skills/builtin/context_graph_search/agno_impl.py +808 -0
- control_plane_api/worker/skills/builtin/context_graph_search/skill.yaml +67 -0
- control_plane_api/worker/skills/builtin/contextual_awareness/__init__.py +4 -0
- control_plane_api/worker/skills/builtin/contextual_awareness/agno_impl.py +62 -0
- control_plane_api/worker/skills/builtin/data_visualization/agno_impl.py +18 -0
- control_plane_api/worker/skills/builtin/data_visualization/skill.yaml +84 -0
- control_plane_api/worker/skills/builtin/docker/agno_impl.py +65 -0
- control_plane_api/worker/skills/builtin/docker/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/file_generation/agno_impl.py +47 -0
- control_plane_api/worker/skills/builtin/file_generation/skill.yaml +64 -0
- control_plane_api/worker/skills/builtin/file_system/agno_impl.py +32 -0
- control_plane_api/worker/skills/builtin/file_system/skill.yaml +54 -0
- control_plane_api/worker/skills/builtin/knowledge_api/__init__.py +4 -0
- control_plane_api/worker/skills/builtin/knowledge_api/agno_impl.py +50 -0
- control_plane_api/worker/skills/builtin/knowledge_api/skill.yaml +66 -0
- control_plane_api/worker/skills/builtin/python/agno_impl.py +25 -0
- control_plane_api/worker/skills/builtin/python/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/schema_fix_mixin.py +260 -0
- control_plane_api/worker/skills/builtin/shell/agno_impl.py +31 -0
- control_plane_api/worker/skills/builtin/shell/skill.yaml +60 -0
- control_plane_api/worker/skills/builtin/slack/__init__.py +3 -0
- control_plane_api/worker/skills/builtin/slack/agno_impl.py +1282 -0
- control_plane_api/worker/skills/builtin/slack/skill.yaml +276 -0
- control_plane_api/worker/skills/builtin/workflow_executor/agno_impl.py +62 -0
- control_plane_api/worker/skills/builtin/workflow_executor/skill.yaml +79 -0
- control_plane_api/worker/skills/loaders/__init__.py +5 -0
- control_plane_api/worker/skills/loaders/base.py +23 -0
- control_plane_api/worker/skills/loaders/filesystem_loader.py +357 -0
- control_plane_api/worker/skills/registry.py +208 -0
- control_plane_api/worker/tests/__init__.py +1 -0
- control_plane_api/worker/tests/conftest.py +12 -0
- control_plane_api/worker/tests/e2e/__init__.py +0 -0
- control_plane_api/worker/tests/e2e/test_context_graph_real_api.py +338 -0
- control_plane_api/worker/tests/e2e/test_context_graph_templates_e2e.py +523 -0
- control_plane_api/worker/tests/e2e/test_enforcement_e2e.py +344 -0
- control_plane_api/worker/tests/e2e/test_execution_flow.py +571 -0
- control_plane_api/worker/tests/e2e/test_single_execution_mode.py +656 -0
- control_plane_api/worker/tests/integration/__init__.py +0 -0
- control_plane_api/worker/tests/integration/test_builtin_skills_fixes.py +245 -0
- control_plane_api/worker/tests/integration/test_context_graph_search_integration.py +365 -0
- control_plane_api/worker/tests/integration/test_control_plane_integration.py +308 -0
- control_plane_api/worker/tests/integration/test_hook_enforcement_integration.py +579 -0
- control_plane_api/worker/tests/integration/test_scheduled_job_workflow.py +237 -0
- control_plane_api/worker/tests/integration/test_system_prompt_enhancement_integration.py +343 -0
- control_plane_api/worker/tests/unit/__init__.py +0 -0
- control_plane_api/worker/tests/unit/test_builtin_skill_autoload.py +396 -0
- control_plane_api/worker/tests/unit/test_context_graph_search.py +450 -0
- control_plane_api/worker/tests/unit/test_context_graph_templates.py +403 -0
- control_plane_api/worker/tests/unit/test_control_plane_client.py +401 -0
- control_plane_api/worker/tests/unit/test_control_plane_client_jobs.py +345 -0
- control_plane_api/worker/tests/unit/test_job_activities.py +353 -0
- control_plane_api/worker/tests/unit/test_skill_context_enhancement.py +321 -0
- control_plane_api/worker/tests/unit/test_system_prompt_enhancement.py +415 -0
- control_plane_api/worker/tests/unit/test_tool_enforcement.py +324 -0
- control_plane_api/worker/utils/__init__.py +1 -0
- control_plane_api/worker/utils/chunk_batcher.py +330 -0
- control_plane_api/worker/utils/environment.py +65 -0
- control_plane_api/worker/utils/error_publisher.py +260 -0
- control_plane_api/worker/utils/event_batcher.py +256 -0
- control_plane_api/worker/utils/logging_config.py +335 -0
- control_plane_api/worker/utils/logging_helper.py +326 -0
- control_plane_api/worker/utils/parameter_validator.py +120 -0
- control_plane_api/worker/utils/retry_utils.py +60 -0
- control_plane_api/worker/utils/streaming_utils.py +665 -0
- control_plane_api/worker/utils/tool_validation.py +332 -0
- control_plane_api/worker/utils/workspace_manager.py +163 -0
- control_plane_api/worker/websocket_client.py +393 -0
- control_plane_api/worker/worker.py +1297 -0
- control_plane_api/worker/workflows/__init__.py +0 -0
- control_plane_api/worker/workflows/agent_execution.py +909 -0
- control_plane_api/worker/workflows/scheduled_job_wrapper.py +332 -0
- control_plane_api/worker/workflows/team_execution.py +611 -0
- kubiya_control_plane_api-0.9.15.dist-info/METADATA +354 -0
- kubiya_control_plane_api-0.9.15.dist-info/RECORD +479 -0
- kubiya_control_plane_api-0.9.15.dist-info/WHEEL +5 -0
- kubiya_control_plane_api-0.9.15.dist-info/entry_points.txt +5 -0
- kubiya_control_plane_api-0.9.15.dist-info/licenses/LICENSE +676 -0
- kubiya_control_plane_api-0.9.15.dist-info/top_level.txt +3 -0
- scripts/__init__.py +1 -0
- scripts/migrations.py +39 -0
- scripts/seed_worker_queues.py +128 -0
- scripts/setup_agent_runtime.py +142 -0
- worker_internal/__init__.py +1 -0
- worker_internal/planner/__init__.py +1 -0
- worker_internal/planner/activities.py +1499 -0
- worker_internal/planner/agent_tools.py +197 -0
- worker_internal/planner/event_models.py +148 -0
- worker_internal/planner/event_publisher.py +67 -0
- worker_internal/planner/models.py +199 -0
- worker_internal/planner/retry_logic.py +134 -0
- worker_internal/planner/worker.py +300 -0
- worker_internal/planner/workflows.py +970 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
"""Tests for WorkerHealthChecker service
|
|
2
|
+
|
|
3
|
+
Test Strategy:
|
|
4
|
+
1. Test each health check individually (Temporal, Redis, Database)
|
|
5
|
+
2. Test with service unavailable scenarios
|
|
6
|
+
3. Test timeout behavior
|
|
7
|
+
4. Test all degradation mode combinations
|
|
8
|
+
5. Test health check caching
|
|
9
|
+
6. Test concurrent health checks
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import pytest
|
|
14
|
+
from unittest.mock import AsyncMock, Mock, patch
|
|
15
|
+
from sqlalchemy import text
|
|
16
|
+
|
|
17
|
+
from control_plane_api.app.routers.executions.services.worker_health import (
|
|
18
|
+
WorkerHealthChecker,
|
|
19
|
+
DegradationMode,
|
|
20
|
+
CAPABILITIES,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Fixtures
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def mock_temporal_client():
|
|
28
|
+
"""Create mock Temporal client."""
|
|
29
|
+
client = Mock()
|
|
30
|
+
client.workflow_service = Mock()
|
|
31
|
+
return client
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def mock_redis_client():
|
|
36
|
+
"""Create mock Redis client."""
|
|
37
|
+
client = AsyncMock()
|
|
38
|
+
client.ping = AsyncMock(return_value=True)
|
|
39
|
+
return client
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def mock_db_session():
|
|
44
|
+
"""Create mock database session."""
|
|
45
|
+
session = Mock()
|
|
46
|
+
session.execute = Mock(return_value=True)
|
|
47
|
+
return session
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Test Temporal Health Checks
|
|
51
|
+
|
|
52
|
+
@pytest.mark.asyncio
|
|
53
|
+
async def test_temporal_health_check_success(mock_temporal_client):
|
|
54
|
+
"""Test Temporal health check with available service."""
|
|
55
|
+
checker = WorkerHealthChecker(temporal_client=mock_temporal_client)
|
|
56
|
+
|
|
57
|
+
result = await checker.check_temporal_connectivity()
|
|
58
|
+
|
|
59
|
+
assert result is True
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.asyncio
|
|
63
|
+
async def test_temporal_health_check_no_client():
|
|
64
|
+
"""Test Temporal health check with no client."""
|
|
65
|
+
checker = WorkerHealthChecker(temporal_client=None)
|
|
66
|
+
|
|
67
|
+
result = await checker.check_temporal_connectivity()
|
|
68
|
+
|
|
69
|
+
assert result is False
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@pytest.mark.asyncio
|
|
73
|
+
async def test_temporal_health_check_timeout(mock_temporal_client):
|
|
74
|
+
"""Test Temporal health check timeout behavior."""
|
|
75
|
+
checker = WorkerHealthChecker(temporal_client=mock_temporal_client)
|
|
76
|
+
|
|
77
|
+
# Mock slow response that exceeds timeout
|
|
78
|
+
with patch.object(
|
|
79
|
+
checker,
|
|
80
|
+
'_check_temporal_service',
|
|
81
|
+
side_effect=asyncio.sleep(10) # Longer than TEMPORAL_TIMEOUT
|
|
82
|
+
):
|
|
83
|
+
result = await checker.check_temporal_connectivity()
|
|
84
|
+
|
|
85
|
+
assert result is False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@pytest.mark.asyncio
|
|
89
|
+
async def test_temporal_health_check_exception(mock_temporal_client):
|
|
90
|
+
"""Test Temporal health check with connection error."""
|
|
91
|
+
checker = WorkerHealthChecker(temporal_client=mock_temporal_client)
|
|
92
|
+
|
|
93
|
+
with patch.object(
|
|
94
|
+
checker,
|
|
95
|
+
'_check_temporal_service',
|
|
96
|
+
side_effect=Exception("Connection failed")
|
|
97
|
+
):
|
|
98
|
+
result = await checker.check_temporal_connectivity()
|
|
99
|
+
|
|
100
|
+
assert result is False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Test Redis Health Checks
|
|
104
|
+
|
|
105
|
+
@pytest.mark.asyncio
|
|
106
|
+
async def test_redis_health_check_success(mock_redis_client):
|
|
107
|
+
"""Test Redis health check with available service."""
|
|
108
|
+
checker = WorkerHealthChecker(redis_client=mock_redis_client)
|
|
109
|
+
|
|
110
|
+
result = await checker.check_redis_connectivity()
|
|
111
|
+
|
|
112
|
+
assert result is True
|
|
113
|
+
mock_redis_client.ping.assert_awaited_once()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.mark.asyncio
|
|
117
|
+
async def test_redis_health_check_no_client():
|
|
118
|
+
"""Test Redis health check with no client."""
|
|
119
|
+
checker = WorkerHealthChecker(redis_client=None)
|
|
120
|
+
|
|
121
|
+
result = await checker.check_redis_connectivity()
|
|
122
|
+
|
|
123
|
+
assert result is False
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@pytest.mark.asyncio
|
|
127
|
+
async def test_redis_health_check_timeout(mock_redis_client):
|
|
128
|
+
"""Test Redis health check timeout behavior."""
|
|
129
|
+
# Mock slow ping that exceeds timeout
|
|
130
|
+
mock_redis_client.ping = AsyncMock(side_effect=asyncio.sleep(10))
|
|
131
|
+
|
|
132
|
+
checker = WorkerHealthChecker(redis_client=mock_redis_client)
|
|
133
|
+
|
|
134
|
+
result = await checker.check_redis_connectivity()
|
|
135
|
+
|
|
136
|
+
assert result is False
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@pytest.mark.asyncio
|
|
140
|
+
async def test_redis_health_check_connection_error(mock_redis_client):
|
|
141
|
+
"""Test Redis health check with connection error."""
|
|
142
|
+
mock_redis_client.ping = AsyncMock(side_effect=Exception("Connection refused"))
|
|
143
|
+
|
|
144
|
+
checker = WorkerHealthChecker(redis_client=mock_redis_client)
|
|
145
|
+
|
|
146
|
+
result = await checker.check_redis_connectivity()
|
|
147
|
+
|
|
148
|
+
assert result is False
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# Test Database Health Checks
|
|
152
|
+
|
|
153
|
+
@pytest.mark.asyncio
|
|
154
|
+
async def test_database_health_check_success(mock_db_session):
|
|
155
|
+
"""Test database health check with available service."""
|
|
156
|
+
checker = WorkerHealthChecker(db_session=mock_db_session)
|
|
157
|
+
|
|
158
|
+
result = await checker.check_database_connectivity()
|
|
159
|
+
|
|
160
|
+
assert result is True
|
|
161
|
+
mock_db_session.execute.assert_called_once()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@pytest.mark.asyncio
|
|
165
|
+
async def test_database_health_check_no_session():
|
|
166
|
+
"""Test database health check with no session."""
|
|
167
|
+
checker = WorkerHealthChecker(db_session=None)
|
|
168
|
+
|
|
169
|
+
result = await checker.check_database_connectivity()
|
|
170
|
+
|
|
171
|
+
assert result is False
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@pytest.mark.asyncio
|
|
175
|
+
async def test_database_health_check_timeout(mock_db_session):
|
|
176
|
+
"""Test database health check timeout behavior."""
|
|
177
|
+
checker = WorkerHealthChecker(db_session=mock_db_session)
|
|
178
|
+
|
|
179
|
+
with patch.object(
|
|
180
|
+
checker,
|
|
181
|
+
'_check_database_query',
|
|
182
|
+
side_effect=asyncio.sleep(10) # Longer than DATABASE_TIMEOUT
|
|
183
|
+
):
|
|
184
|
+
result = await checker.check_database_connectivity()
|
|
185
|
+
|
|
186
|
+
assert result is False
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@pytest.mark.asyncio
|
|
190
|
+
async def test_database_health_check_query_error(mock_db_session):
|
|
191
|
+
"""Test database health check with query error."""
|
|
192
|
+
mock_db_session.execute = Mock(side_effect=Exception("Query failed"))
|
|
193
|
+
|
|
194
|
+
checker = WorkerHealthChecker(db_session=mock_db_session)
|
|
195
|
+
|
|
196
|
+
result = await checker.check_database_connectivity()
|
|
197
|
+
|
|
198
|
+
assert result is False
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Test Check All
|
|
202
|
+
|
|
203
|
+
@pytest.mark.asyncio
|
|
204
|
+
async def test_check_all_services_available(
|
|
205
|
+
mock_temporal_client,
|
|
206
|
+
mock_redis_client,
|
|
207
|
+
mock_db_session
|
|
208
|
+
):
|
|
209
|
+
"""Test check_all with all services available."""
|
|
210
|
+
checker = WorkerHealthChecker(
|
|
211
|
+
temporal_client=mock_temporal_client,
|
|
212
|
+
redis_client=mock_redis_client,
|
|
213
|
+
db_session=mock_db_session
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
results = await checker.check_all()
|
|
217
|
+
|
|
218
|
+
assert results["temporal"] is True
|
|
219
|
+
assert results["redis"] is True
|
|
220
|
+
assert results["database"] is True
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@pytest.mark.asyncio
|
|
224
|
+
async def test_check_all_services_unavailable():
|
|
225
|
+
"""Test check_all with all services unavailable."""
|
|
226
|
+
checker = WorkerHealthChecker(
|
|
227
|
+
temporal_client=None,
|
|
228
|
+
redis_client=None,
|
|
229
|
+
db_session=None
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
results = await checker.check_all()
|
|
233
|
+
|
|
234
|
+
assert results["temporal"] is False
|
|
235
|
+
assert results["redis"] is False
|
|
236
|
+
assert results["database"] is False
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@pytest.mark.asyncio
|
|
240
|
+
async def test_check_all_mixed_availability(mock_redis_client):
|
|
241
|
+
"""Test check_all with mixed service availability."""
|
|
242
|
+
checker = WorkerHealthChecker(
|
|
243
|
+
temporal_client=None,
|
|
244
|
+
redis_client=mock_redis_client,
|
|
245
|
+
db_session=None
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
results = await checker.check_all()
|
|
249
|
+
|
|
250
|
+
assert results["temporal"] is False
|
|
251
|
+
assert results["redis"] is True
|
|
252
|
+
assert results["database"] is False
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# Test Degradation Modes
|
|
256
|
+
|
|
257
|
+
@pytest.mark.asyncio
|
|
258
|
+
async def test_degradation_mode_full(
|
|
259
|
+
mock_temporal_client,
|
|
260
|
+
mock_redis_client,
|
|
261
|
+
mock_db_session
|
|
262
|
+
):
|
|
263
|
+
"""Test FULL degradation mode with all services available."""
|
|
264
|
+
checker = WorkerHealthChecker(
|
|
265
|
+
temporal_client=mock_temporal_client,
|
|
266
|
+
redis_client=mock_redis_client,
|
|
267
|
+
db_session=mock_db_session
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
mode = await checker.get_degradation_mode()
|
|
271
|
+
|
|
272
|
+
assert mode == DegradationMode.FULL
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@pytest.mark.asyncio
|
|
276
|
+
async def test_degradation_mode_history_only(mock_db_session):
|
|
277
|
+
"""Test HISTORY_ONLY degradation mode with only database available."""
|
|
278
|
+
checker = WorkerHealthChecker(
|
|
279
|
+
temporal_client=None,
|
|
280
|
+
redis_client=None,
|
|
281
|
+
db_session=mock_db_session
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
mode = await checker.get_degradation_mode()
|
|
285
|
+
|
|
286
|
+
assert mode == DegradationMode.HISTORY_ONLY
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@pytest.mark.asyncio
|
|
290
|
+
async def test_degradation_mode_live_only(mock_redis_client):
|
|
291
|
+
"""Test LIVE_ONLY degradation mode with only Redis available."""
|
|
292
|
+
checker = WorkerHealthChecker(
|
|
293
|
+
temporal_client=None,
|
|
294
|
+
redis_client=mock_redis_client,
|
|
295
|
+
db_session=None
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
mode = await checker.get_degradation_mode()
|
|
299
|
+
|
|
300
|
+
assert mode == DegradationMode.LIVE_ONLY
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@pytest.mark.asyncio
|
|
304
|
+
async def test_degradation_mode_degraded(mock_temporal_client, mock_redis_client):
|
|
305
|
+
"""Test DEGRADED mode with partial availability."""
|
|
306
|
+
checker = WorkerHealthChecker(
|
|
307
|
+
temporal_client=mock_temporal_client,
|
|
308
|
+
redis_client=mock_redis_client,
|
|
309
|
+
db_session=None
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
mode = await checker.get_degradation_mode()
|
|
313
|
+
|
|
314
|
+
assert mode == DegradationMode.DEGRADED
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@pytest.mark.asyncio
|
|
318
|
+
async def test_degradation_mode_unavailable():
|
|
319
|
+
"""Test UNAVAILABLE mode with no services available."""
|
|
320
|
+
checker = WorkerHealthChecker(
|
|
321
|
+
temporal_client=None,
|
|
322
|
+
redis_client=None,
|
|
323
|
+
db_session=None
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
mode = await checker.get_degradation_mode()
|
|
327
|
+
|
|
328
|
+
assert mode == DegradationMode.UNAVAILABLE
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# Test Capabilities
|
|
332
|
+
|
|
333
|
+
def test_get_capabilities_full():
|
|
334
|
+
"""Test capabilities for FULL mode."""
|
|
335
|
+
checker = WorkerHealthChecker()
|
|
336
|
+
|
|
337
|
+
capabilities = checker.get_capabilities(DegradationMode.FULL)
|
|
338
|
+
|
|
339
|
+
assert "history" in capabilities
|
|
340
|
+
assert "live_events" in capabilities
|
|
341
|
+
assert "status_updates" in capabilities
|
|
342
|
+
assert "completion_detection" in capabilities
|
|
343
|
+
assert "workflow_queries" in capabilities
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def test_get_capabilities_history_only():
|
|
347
|
+
"""Test capabilities for HISTORY_ONLY mode."""
|
|
348
|
+
checker = WorkerHealthChecker()
|
|
349
|
+
|
|
350
|
+
capabilities = checker.get_capabilities(DegradationMode.HISTORY_ONLY)
|
|
351
|
+
|
|
352
|
+
assert capabilities == ["history"]
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def test_get_capabilities_live_only():
|
|
356
|
+
"""Test capabilities for LIVE_ONLY mode."""
|
|
357
|
+
checker = WorkerHealthChecker()
|
|
358
|
+
|
|
359
|
+
capabilities = checker.get_capabilities(DegradationMode.LIVE_ONLY)
|
|
360
|
+
|
|
361
|
+
assert capabilities == ["live_events"]
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def test_get_capabilities_unavailable():
|
|
365
|
+
"""Test capabilities for UNAVAILABLE mode."""
|
|
366
|
+
checker = WorkerHealthChecker()
|
|
367
|
+
|
|
368
|
+
capabilities = checker.get_capabilities(DegradationMode.UNAVAILABLE)
|
|
369
|
+
|
|
370
|
+
assert capabilities == []
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
# Test Caching
|
|
374
|
+
|
|
375
|
+
@pytest.mark.asyncio
|
|
376
|
+
async def test_health_check_caching(mock_redis_client):
|
|
377
|
+
"""Test that health check results are cached."""
|
|
378
|
+
checker = WorkerHealthChecker(
|
|
379
|
+
redis_client=mock_redis_client,
|
|
380
|
+
cache_ttl=10 # 10 second cache
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
# First check should call Redis
|
|
384
|
+
result1 = await checker.check_redis_connectivity()
|
|
385
|
+
assert result1 is True
|
|
386
|
+
assert mock_redis_client.ping.call_count == 1
|
|
387
|
+
|
|
388
|
+
# Second check should use cache (no additional Redis call)
|
|
389
|
+
result2 = await checker.check_redis_connectivity()
|
|
390
|
+
assert result2 is True
|
|
391
|
+
assert mock_redis_client.ping.call_count == 1 # Still 1, not 2
|
|
392
|
+
|
|
393
|
+
# Verify cache was used
|
|
394
|
+
assert checker._is_cached("redis") is True
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
@pytest.mark.asyncio
|
|
398
|
+
async def test_health_check_cache_expiry(mock_redis_client):
|
|
399
|
+
"""Test that health check cache expires."""
|
|
400
|
+
checker = WorkerHealthChecker(
|
|
401
|
+
redis_client=mock_redis_client,
|
|
402
|
+
cache_ttl=0.1 # 100ms cache
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# First check
|
|
406
|
+
result1 = await checker.check_redis_connectivity()
|
|
407
|
+
assert result1 is True
|
|
408
|
+
assert mock_redis_client.ping.call_count == 1
|
|
409
|
+
|
|
410
|
+
# Wait for cache to expire
|
|
411
|
+
await asyncio.sleep(0.2)
|
|
412
|
+
|
|
413
|
+
# Second check should call Redis again
|
|
414
|
+
result2 = await checker.check_redis_connectivity()
|
|
415
|
+
assert result2 is True
|
|
416
|
+
assert mock_redis_client.ping.call_count == 2 # Called again
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
@pytest.mark.asyncio
|
|
420
|
+
async def test_clear_cache(mock_redis_client):
|
|
421
|
+
"""Test clearing health check cache."""
|
|
422
|
+
checker = WorkerHealthChecker(
|
|
423
|
+
redis_client=mock_redis_client,
|
|
424
|
+
cache_ttl=10
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
# First check
|
|
428
|
+
result1 = await checker.check_redis_connectivity()
|
|
429
|
+
assert result1 is True
|
|
430
|
+
assert checker._is_cached("redis") is True
|
|
431
|
+
|
|
432
|
+
# Clear cache
|
|
433
|
+
checker.clear_cache()
|
|
434
|
+
assert checker._is_cached("redis") is None
|
|
435
|
+
|
|
436
|
+
# Next check should call Redis again
|
|
437
|
+
result2 = await checker.check_redis_connectivity()
|
|
438
|
+
assert result2 is True
|
|
439
|
+
assert mock_redis_client.ping.call_count == 2
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
# Integration Test Examples (commented out - requires real services)
|
|
443
|
+
|
|
444
|
+
"""
|
|
445
|
+
@pytest.mark.asyncio
|
|
446
|
+
async def test_integration_with_real_services():
|
|
447
|
+
# This test would require real Temporal, Redis, and Database instances
|
|
448
|
+
# Uncomment and configure for integration testing
|
|
449
|
+
|
|
450
|
+
from control_plane_api.app.lib.temporal_client import get_temporal_client
|
|
451
|
+
from control_plane_api.app.lib.redis_client import get_redis_client
|
|
452
|
+
from control_plane_api.app.database import get_session_local
|
|
453
|
+
|
|
454
|
+
temporal_client = await get_temporal_client()
|
|
455
|
+
redis_client = get_redis_client()
|
|
456
|
+
SessionLocal = get_session_local()
|
|
457
|
+
db_session = SessionLocal()
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
checker = WorkerHealthChecker(
|
|
461
|
+
temporal_client=temporal_client,
|
|
462
|
+
redis_client=redis_client,
|
|
463
|
+
db_session=db_session
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
# Test all health checks
|
|
467
|
+
results = await checker.check_all()
|
|
468
|
+
print(f"Health check results: {results}")
|
|
469
|
+
|
|
470
|
+
# Test degradation mode
|
|
471
|
+
mode = await checker.get_degradation_mode()
|
|
472
|
+
print(f"Degradation mode: {mode}")
|
|
473
|
+
|
|
474
|
+
# Test capabilities
|
|
475
|
+
capabilities = checker.get_capabilities(mode)
|
|
476
|
+
print(f"Available capabilities: {capabilities}")
|
|
477
|
+
|
|
478
|
+
finally:
|
|
479
|
+
db_session.close()
|
|
480
|
+
"""
|