fix: commit semantic repair changes
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
# [DEF:backend.tests.services.clean_release.test_compliance_task_integration:Module]
|
||||
# [DEF:TestComplianceTaskIntegration:Module]
|
||||
# @RELATION: BELONGS_TO -> SrcRoot
|
||||
# @COMPLEXITY: 5
|
||||
# @SEMANTICS: tests, clean-release, compliance, task-manager, integration
|
||||
# @PURPOSE: Verify clean release compliance runs execute through TaskManager lifecycle with observable success/failure outcomes.
|
||||
# @LAYER: Tests
|
||||
# @RELATION: TESTS -> backend.src.core.task_manager.manager.TaskManager
|
||||
# @RELATION: TESTS -> backend.src.services.clean_release.compliance_orchestrator.CleanComplianceOrchestrator
|
||||
# @INVARIANT: Compliance execution triggered as task produces terminal task status and persists run evidence.
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -24,16 +23,21 @@ from src.models.clean_release import (
|
||||
ReleaseCandidate,
|
||||
SourceRegistrySnapshot,
|
||||
)
|
||||
from src.services.clean_release.compliance_orchestrator import CleanComplianceOrchestrator
|
||||
from src.services.clean_release.compliance_orchestrator import (
|
||||
CleanComplianceOrchestrator,
|
||||
)
|
||||
from src.services.clean_release.enums import CandidateStatus, RunStatus
|
||||
from src.services.clean_release.repository import CleanReleaseRepository
|
||||
|
||||
|
||||
# [DEF:_seed_repository:Function]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @PURPOSE: Prepare deterministic candidate/policy/registry/manifest fixtures for task integration tests.
|
||||
# @PRE: with_manifest controls manifest availability.
|
||||
# @POST: Returns initialized repository and identifiers for compliance run startup.
|
||||
def _seed_repository(*, with_manifest: bool) -> tuple[CleanReleaseRepository, str, str, str]:
|
||||
def _seed_repository(
|
||||
*, with_manifest: bool
|
||||
) -> tuple[CleanReleaseRepository, str, str, str]:
|
||||
repository = CleanReleaseRepository()
|
||||
candidate_id = "cand-task-int-1"
|
||||
policy_id = "policy-task-int-1"
|
||||
@@ -94,10 +98,13 @@ def _seed_repository(*, with_manifest: bool) -> tuple[CleanReleaseRepository, st
|
||||
)
|
||||
|
||||
return repository, candidate_id, policy_id, manifest_id
|
||||
|
||||
|
||||
# [/DEF:_seed_repository:Function]
|
||||
|
||||
|
||||
# [DEF:CleanReleaseCompliancePlugin:Class]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @PURPOSE: TaskManager plugin shim that executes clean release compliance orchestration.
|
||||
class CleanReleaseCompliancePlugin:
|
||||
@property
|
||||
@@ -125,12 +132,21 @@ class CleanReleaseCompliancePlugin:
|
||||
if context is not None:
|
||||
context.logger.info("Compliance run completed via TaskManager plugin")
|
||||
|
||||
return {"run_id": run.id, "run_status": run.status, "final_status": run.final_status}
|
||||
return {
|
||||
"run_id": run.id,
|
||||
"run_status": run.status,
|
||||
"final_status": run.final_status,
|
||||
}
|
||||
|
||||
|
||||
# [/DEF:CleanReleaseCompliancePlugin:Class]
|
||||
|
||||
|
||||
# [DEF:_PluginLoaderStub:Class]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @COMPLEXITY: 2
|
||||
# @PURPOSE: Provide minimal plugin loader contract used by TaskManager in integration tests.
|
||||
# @INVARIANT: has_plugin/get_plugin only acknowledge the seeded compliance plugin id.
|
||||
class _PluginLoaderStub:
|
||||
def __init__(self, plugin: CleanReleaseCompliancePlugin):
|
||||
self._plugin = plugin
|
||||
@@ -142,18 +158,26 @@ class _PluginLoaderStub:
|
||||
if plugin_id != self._plugin.id:
|
||||
raise ValueError("Plugin not found")
|
||||
return self._plugin
|
||||
|
||||
|
||||
# [/DEF:_PluginLoaderStub:Class]
|
||||
|
||||
|
||||
# [DEF:_make_task_manager:Function]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @PURPOSE: Build TaskManager with mocked persistence services for isolated integration tests.
|
||||
# @POST: Returns TaskManager ready for async task execution.
|
||||
def _make_task_manager() -> TaskManager:
|
||||
plugin_loader = _PluginLoaderStub(CleanReleaseCompliancePlugin())
|
||||
|
||||
with patch("src.core.task_manager.manager.TaskPersistenceService") as mock_persistence, patch(
|
||||
"src.core.task_manager.manager.TaskLogPersistenceService"
|
||||
) as mock_log_persistence:
|
||||
with (
|
||||
patch(
|
||||
"src.core.task_manager.manager.TaskPersistenceService"
|
||||
) as mock_persistence,
|
||||
patch(
|
||||
"src.core.task_manager.manager.TaskLogPersistenceService"
|
||||
) as mock_log_persistence,
|
||||
):
|
||||
mock_persistence.return_value.load_tasks.return_value = []
|
||||
mock_persistence.return_value.persist_task = MagicMock()
|
||||
mock_log_persistence.return_value.add_logs = MagicMock()
|
||||
@@ -162,14 +186,19 @@ def _make_task_manager() -> TaskManager:
|
||||
mock_log_persistence.return_value.get_sources = MagicMock(return_value=[])
|
||||
|
||||
return TaskManager(plugin_loader)
|
||||
|
||||
|
||||
# [/DEF:_make_task_manager:Function]
|
||||
|
||||
|
||||
# [DEF:_wait_for_terminal_task:Function]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @PURPOSE: Poll task registry until target task reaches terminal status.
|
||||
# @PRE: task_id exists in manager registry.
|
||||
# @POST: Returns task with SUCCESS or FAILED status, otherwise raises TimeoutError.
|
||||
async def _wait_for_terminal_task(manager: TaskManager, task_id: str, timeout_seconds: float = 3.0):
|
||||
async def _wait_for_terminal_task(
|
||||
manager: TaskManager, task_id: str, timeout_seconds: float = 3.0
|
||||
):
|
||||
started = asyncio.get_running_loop().time()
|
||||
while True:
|
||||
task = manager.get_task(task_id)
|
||||
@@ -178,16 +207,21 @@ async def _wait_for_terminal_task(manager: TaskManager, task_id: str, timeout_se
|
||||
if asyncio.get_running_loop().time() - started > timeout_seconds:
|
||||
raise TimeoutError(f"Task {task_id} did not reach terminal status")
|
||||
await asyncio.sleep(0.05)
|
||||
|
||||
|
||||
# [/DEF:_wait_for_terminal_task:Function]
|
||||
|
||||
|
||||
# [DEF:test_compliance_run_executes_as_task_manager_task:Function]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @PURPOSE: Verify successful compliance execution is observable as TaskManager SUCCESS task.
|
||||
# @PRE: Candidate, policy and manifest are available in repository.
|
||||
# @POST: Task ends with SUCCESS; run is persisted with SUCCEEDED status and task binding.
|
||||
@pytest.mark.asyncio
|
||||
async def test_compliance_run_executes_as_task_manager_task():
|
||||
repository, candidate_id, policy_id, manifest_id = _seed_repository(with_manifest=True)
|
||||
repository, candidate_id, policy_id, manifest_id = _seed_repository(
|
||||
with_manifest=True
|
||||
)
|
||||
manager = _make_task_manager()
|
||||
|
||||
try:
|
||||
@@ -214,16 +248,21 @@ async def test_compliance_run_executes_as_task_manager_task():
|
||||
finally:
|
||||
manager._flusher_stop_event.set()
|
||||
manager._flusher_thread.join(timeout=2)
|
||||
|
||||
|
||||
# [/DEF:test_compliance_run_executes_as_task_manager_task:Function]
|
||||
|
||||
|
||||
# [DEF:test_compliance_run_missing_manifest_marks_task_failed:Function]
|
||||
# @RELATION: BINDS_TO -> TestComplianceTaskIntegration
|
||||
# @PURPOSE: Verify missing manifest startup failure is surfaced as TaskManager FAILED task.
|
||||
# @PRE: Candidate/policy exist but manifest is absent.
|
||||
# @POST: Task ends with FAILED and run history remains empty.
|
||||
@pytest.mark.asyncio
|
||||
async def test_compliance_run_missing_manifest_marks_task_failed():
|
||||
repository, candidate_id, policy_id, manifest_id = _seed_repository(with_manifest=False)
|
||||
repository, candidate_id, policy_id, manifest_id = _seed_repository(
|
||||
with_manifest=False
|
||||
)
|
||||
manager = _make_task_manager()
|
||||
|
||||
try:
|
||||
@@ -241,10 +280,14 @@ async def test_compliance_run_missing_manifest_marks_task_failed():
|
||||
|
||||
assert finished.status == TaskStatus.FAILED
|
||||
assert len(repository.check_runs) == 0
|
||||
assert any("Manifest or Policy not found" in log.message for log in finished.logs)
|
||||
assert any(
|
||||
"Manifest or Policy not found" in log.message for log in finished.logs
|
||||
)
|
||||
finally:
|
||||
manager._flusher_stop_event.set()
|
||||
manager._flusher_thread.join(timeout=2)
|
||||
|
||||
|
||||
# [/DEF:test_compliance_run_missing_manifest_marks_task_failed:Function]
|
||||
|
||||
# [/DEF:backend.tests.services.clean_release.test_compliance_task_integration:Module]
|
||||
# [/DEF:TestComplianceTaskIntegration:Module]
|
||||
|
||||
Reference in New Issue
Block a user