QTZPOC-20
QTZPOC-20: Refactor ModelImport status engine for lazy initialization, add byte-counted size validation to bundle extraction, optimize MLflow run ID lookups, and ensure workflow cancellation propagates correctly.
This commit is contained in:
@@ -12,7 +12,7 @@ workflow is: a sequence of activity invocations with policies attached.
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from pytest import fixture, mark, raises
|
||||
from sientia_do.temporal.policies import retry_policy
|
||||
@@ -725,6 +725,95 @@ async def test_reporting_the_report_is_where_it_stops(import_workflow: ImportMod
|
||||
assert result['run_id'] == RUN_ID
|
||||
|
||||
|
||||
# --------------------------------------------------- cancellation is never swallowed
|
||||
|
||||
|
||||
def cancelling_activities():
|
||||
"""Patch the workflow module's `workflow` object so every activity call raises cancellation."""
|
||||
patcher = patch('laborious.workflows.import_model.workflow')
|
||||
workflow_mock = patcher.start()
|
||||
workflow_mock.execute_activity_method = AsyncMock(side_effect=asyncio.CancelledError())
|
||||
return patcher
|
||||
|
||||
|
||||
BASE = {'metadata': {}, 'import_run_id': 77, 'workflow_id': WORKFLOW_ID}
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_a_cancelled_hint_propagates_instead_of_being_reported(import_workflow: ImportModel):
|
||||
patcher = cancelling_activities()
|
||||
try:
|
||||
with raises(asyncio.CancelledError):
|
||||
await import_workflow._record_hint(
|
||||
BASE, Activities.record_import_status, {'step': ImportStep.DOWNLOAD.value}
|
||||
)
|
||||
finally:
|
||||
patcher.stop()
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_a_cancelled_terminal_write_propagates_instead_of_being_reported(
|
||||
import_workflow: ImportModel,
|
||||
):
|
||||
patcher = cancelling_activities()
|
||||
try:
|
||||
with raises(asyncio.CancelledError):
|
||||
await import_workflow._record_terminal(
|
||||
BASE,
|
||||
succeeded=True,
|
||||
step=ImportStep.MODEL_DOCUMENT.value,
|
||||
gate=None,
|
||||
source={},
|
||||
cleanup_failed=False,
|
||||
)
|
||||
finally:
|
||||
patcher.stop()
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_a_cancelled_pipeline_failure_report_propagates(import_workflow: ImportModel):
|
||||
patcher = cancelling_activities()
|
||||
try:
|
||||
with raises(asyncio.CancelledError):
|
||||
await import_workflow._report_failure(
|
||||
BASE, RuntimeError('boom'), step=ImportStep.REGISTRATION.value, gate=None
|
||||
)
|
||||
finally:
|
||||
patcher.stop()
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_a_cancelled_status_write_failure_report_propagates(import_workflow: ImportModel):
|
||||
patcher = cancelling_activities()
|
||||
try:
|
||||
with raises(asyncio.CancelledError):
|
||||
await import_workflow._report_status_write_failure(BASE, RuntimeError('db down'))
|
||||
finally:
|
||||
patcher.stop()
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_a_cancelled_retention_check_propagates(import_workflow: ImportModel):
|
||||
patcher = cancelling_activities()
|
||||
try:
|
||||
with raises(asyncio.CancelledError):
|
||||
await import_workflow._ensure_retention(BASE, valid_input())
|
||||
finally:
|
||||
patcher.stop()
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_a_cancelled_cleanup_propagates_instead_of_returning_not_cleaned(
|
||||
import_workflow: ImportModel,
|
||||
):
|
||||
patcher = cancelling_activities()
|
||||
try:
|
||||
with raises(asyncio.CancelledError):
|
||||
await import_workflow._cleanup(BASE)
|
||||
finally:
|
||||
patcher.stop()
|
||||
|
||||
|
||||
# --------------------------------------------------------------- the failure report
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user