feat(workbench): add dynamic task approval lifecycle
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
import httpx
|
||||
@@ -6,6 +9,7 @@ import pytest
|
||||
|
||||
from scripts.run_operational_worker import CredentialProvider, WorkerSettings
|
||||
from scripts.sync_peripheral_work_orders import (
|
||||
peripheral_order_id,
|
||||
should_project_work_order,
|
||||
sync_once,
|
||||
work_order_snapshot,
|
||||
@@ -19,6 +23,19 @@ def anyio_backend():
|
||||
return "asyncio"
|
||||
|
||||
|
||||
def test_documented_sync_command_can_start_from_repository_root():
|
||||
repository_root = Path(__file__).resolve().parents[2]
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(repository_root / "scripts/sync_peripheral_work_orders.py"), "--help"],
|
||||
cwd=repository_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
assert result.returncode == 0, result.stderr
|
||||
assert "--once" in result.stdout
|
||||
|
||||
|
||||
def test_unlinked_synthetic_checks_are_not_operational_tasks():
|
||||
order_id = str(uuid4())
|
||||
order = {
|
||||
@@ -42,6 +59,14 @@ def test_unlinked_synthetic_checks_are_not_operational_tasks():
|
||||
)
|
||||
|
||||
|
||||
def test_peripheral_order_id_ignores_foreign_and_malformed_namespaces():
|
||||
order_id = str(uuid4())
|
||||
|
||||
assert peripheral_order_id(f"peripheral_sample:{order_id}") == order_id
|
||||
assert peripheral_order_id("peripheral_sample:not-a-uuid") is None
|
||||
assert peripheral_order_id(f"other_system:{order_id}") is None
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sync_creates_one_task_and_only_applies_new_external_revisions():
|
||||
project_id, order_id, task_id = map(str, (uuid4(), uuid4(), uuid4()))
|
||||
@@ -129,6 +154,79 @@ async def test_sync_skips_unlinked_synthetic_check_before_writing():
|
||||
assert synchronized == 0
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sync_withdraws_only_deleted_peripheral_projection():
|
||||
project_id, deleted_id, deleted_task_id, other_task_id = map(
|
||||
str, (uuid4(), uuid4(), uuid4(), uuid4())
|
||||
)
|
||||
deleted_source = f"peripheral_sample:{deleted_id}"
|
||||
tasks = [
|
||||
{"task_id": deleted_task_id, "task_type": "external_work_order",
|
||||
"source": {"external_id": deleted_source, "external_revision": 1}},
|
||||
{"task_id": other_task_id, "task_type": "external_work_order",
|
||||
"source": {"external_id": f"other_system:{uuid4()}", "external_revision": 1}},
|
||||
]
|
||||
withdrawals = []
|
||||
|
||||
def handler(request):
|
||||
if request.url.host == "sample.test":
|
||||
if request.url.path.endswith("/work-orders"):
|
||||
return httpx.Response(200, json={"items": [], "next_cursor": None})
|
||||
assert request.url.path.endswith(f"/work-orders/{deleted_id}")
|
||||
return httpx.Response(404, json={"code": "WORK_ORDER_NOT_FOUND"})
|
||||
if request.method == "GET":
|
||||
return httpx.Response(200, json={"items": tasks, "next_offset": None})
|
||||
assert request.url.path.endswith(f"/{deleted_task_id}/withdraw-external-source")
|
||||
withdrawals.append(json.loads(request.content))
|
||||
tasks.pop(0)
|
||||
return httpx.Response(200, json={})
|
||||
|
||||
settings = WorkerSettings(
|
||||
"http://server.test", "http://agent.test", project_id, bearer="TEST_ONLY"
|
||||
)
|
||||
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client:
|
||||
credentials = CredentialProvider(settings)
|
||||
assert await sync_once(client, settings, "http://sample.test", credentials) == 1
|
||||
assert await sync_once(client, settings, "http://sample.test", credentials) == 0
|
||||
|
||||
assert len(withdrawals) == 1
|
||||
assert withdrawals[0]["source_event_id"] == deleted_source
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.parametrize("lookup_status", [200, 503])
|
||||
async def test_sync_does_not_withdraw_when_missing_order_is_not_confirmed_deleted(lookup_status):
|
||||
project_id, order_id, task_id = map(str, (uuid4(), uuid4(), uuid4()))
|
||||
source_id = f"peripheral_sample:{order_id}"
|
||||
writes = []
|
||||
|
||||
def handler(request):
|
||||
if request.url.host == "sample.test":
|
||||
if request.url.path.endswith("/work-orders"):
|
||||
return httpx.Response(200, json={"items": [], "next_cursor": None})
|
||||
return httpx.Response(lookup_status, json={"work_order_id": order_id})
|
||||
if request.method == "GET":
|
||||
return httpx.Response(200, json={"items": [{
|
||||
"task_id": task_id, "task_type": "external_work_order",
|
||||
"source": {"external_id": source_id, "external_revision": 1},
|
||||
}], "next_offset": None})
|
||||
writes.append(request.url.path)
|
||||
return httpx.Response(200, json={})
|
||||
|
||||
settings = WorkerSettings(
|
||||
"http://server.test", "http://agent.test", project_id, bearer="TEST_ONLY"
|
||||
)
|
||||
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client:
|
||||
if lookup_status == 503:
|
||||
with pytest.raises(httpx.HTTPStatusError):
|
||||
await sync_once(client, settings, "http://sample.test", CredentialProvider(settings))
|
||||
else:
|
||||
assert await sync_once(
|
||||
client, settings, "http://sample.test", CredentialProvider(settings)
|
||||
) == 0
|
||||
assert writes == []
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sample_sync_rejects_cross_project_data_before_writing():
|
||||
def handler(request):
|
||||
|
||||
Reference in New Issue
Block a user