chore(cloud): verify integration change

This commit is contained in:
2026-07-13 08:06:15 +08:00
parent 3c5f5509c2
commit 22d37ca95b
10 changed files with 60 additions and 33 deletions
+1 -2
View File
@@ -65,8 +65,7 @@ class ActiveAssignmentRunner:
asyncio.to_thread(
self.executor.execute,
assignment,
should_stop=lambda: guard.is_lost()
or self._stop_requested.is_set(),
should_stop=lambda: guard.is_lost() or self._stop_requested.is_set(),
)
)
renewal = asyncio.create_task(
+6 -2
View File
@@ -177,7 +177,9 @@ def test_one_host_executes_assignment_through_outbound_protocol(tmp_path) -> Non
async with _control_plane(tmp_path / "one-host.sqlite3", "host-a") as app:
async with _host_client(app, "host-a", request_paths=paths) as client:
await _sync_fake_device(client, "host-a", "device-a")
task_id = app.state.cloud_services.scheduler.submit(goal="open settings")
task_id = app.state.cloud_services.scheduler.submit(
goal="open settings"
)
app.state.cloud_services.scheduler.assign()
assignment = await client.claim()
assert assignment is not None
@@ -287,7 +289,9 @@ def test_host_agent_restart_reuses_active_lease(tmp_path) -> None:
assert (await restarted_client.renew(assignment)).status == "renewed"
await restarted_client.report_result(assignment, status="done")
assert app.state.cloud_services.repository.get_task(task_id).status == "done"
assert (
app.state.cloud_services.repository.get_task(task_id).status == "done"
)
asyncio.run(scenario())
@@ -71,7 +71,7 @@
## 9. Verification And Project Records
- [ ] 9.1 Run formatting, static checks, all non-integration tests, and targeted PostgreSQL integration/concurrency tests.
- [x] 9.1 Run formatting, static checks, all non-integration tests, and targeted PostgreSQL integration/concurrency tests.
- [ ] 9.2 Run an end-to-end cloud submission through a Host Agent and fake device until the public SDK reports done and a failure case until it reports failed.
- [ ] 9.3 Verify existing local REST/MCP/console behavior and dependency-boundary tests remain unchanged.
- [ ] 9.4 Run OpenSpec validation for `cloud-control-plane-integration` and map automated tests to every new or modified scenario.
@@ -19,8 +19,7 @@ target_metadata = Base.metadata
def _database_url() -> str:
return normalize_database_url(
os.environ.get("CLOUD_DATABASE_URL")
or config.get_main_option("sqlalchemy.url")
os.environ.get("CLOUD_DATABASE_URL") or config.get_main_option("sqlalchemy.url")
)
@@ -38,7 +37,9 @@ def run_migrations_offline() -> None:
def run_migrations_online() -> None:
supplied_connection = config.attributes.get("connection")
if supplied_connection is not None:
context.configure(connection=supplied_connection, target_metadata=target_metadata)
context.configure(
connection=supplied_connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
return
+11 -6
View File
@@ -111,7 +111,9 @@ class TaskRunner:
screenshot = self._planning_screenshot(task.device_id)
steps = self._plan(task.goal, scene, context, screenshot=screenshot)
except Exception as exc:
reason = f"{type(exc).__name__}: {exc}" if str(exc) else type(exc).__name__
reason = (
f"{type(exc).__name__}: {exc}" if str(exc) else type(exc).__name__
)
self._update_task(
task,
status="failed",
@@ -135,7 +137,9 @@ class TaskRunner:
context=context,
)
context.add_step_result(result)
self._record_step_result(world_handle, context, task, scene, step, result)
self._record_step_result(
world_handle, context, task, scene, step, result
)
if not result.success:
self._update_task(
task,
@@ -251,11 +255,10 @@ class TaskRunner:
def _planner_accepts(self, name: str) -> bool:
try:
parameters = signature(self.planner.plan).parameters
except (TypeError, ValueError):
except TypeError, ValueError:
return True
return name in parameters or any(
parameter.kind is Parameter.VAR_KEYWORD
for parameter in parameters.values()
parameter.kind is Parameter.VAR_KEYWORD for parameter in parameters.values()
)
def _planning_screenshot(self, device_id: str) -> bytes | None:
@@ -309,7 +312,9 @@ class TaskRunner:
"description": step.description,
"args": step.args,
},
result=result.to_dict() if hasattr(result, "to_dict") else {"result": result},
result=result.to_dict()
if hasattr(result, "to_dict")
else {"result": result},
screenshot=screenshot,
)
+5 -2
View File
@@ -153,12 +153,15 @@ def test_client_applies_bearer_token_to_every_public_method(tmp_path) -> None:
assert client.list_devices() == []
assert client.list_hosts() == []
assert client.list_plugins() == []
assert client.register_plugin(
assert (
client.register_plugin(
name="authenticated-plugin",
version="1.0.0",
entry_point_kind="tool",
target="cloud.store:CloudStore",
)["name"] == "authenticated-plugin"
)["name"]
== "authenticated-plugin"
)
def test_client_raises_typed_authorization_error_without_exposing_token(
+11 -3
View File
@@ -74,7 +74,11 @@ def test_legacy_data_survives_upgrade_and_downgrade(tmp_path) -> None:
"('task-a', 'goal', null, :constraints, 'queued', null, null, "
"'2026-01-01T00:00:00+00:00')"
),
{"constraints": json.dumps({"driver_type": None, "capability_tags": []})},
{
"constraints": json.dumps(
{"driver_type": None, "capability_tags": []}
)
},
)
finally:
engine.dispose()
@@ -83,7 +87,9 @@ def test_legacy_data_survives_upgrade_and_downgrade(tmp_path) -> None:
engine = create_engine(database_url)
try:
with engine.connect() as connection:
assert connection.scalar(text("select count(*) from host_registrations")) == 1
assert (
connection.scalar(text("select count(*) from host_registrations")) == 1
)
assert connection.scalar(text("select count(*) from scheduled_tasks")) == 1
task_columns = {
column["name"] for column in inspect(engine).get_columns("scheduled_tasks")
@@ -96,7 +102,9 @@ def test_legacy_data_survives_upgrade_and_downgrade(tmp_path) -> None:
engine = create_engine(database_url)
try:
with engine.connect() as connection:
assert connection.scalar(text("select count(*) from host_registrations")) == 1
assert (
connection.scalar(text("select count(*) from host_registrations")) == 1
)
assert connection.scalar(text("select count(*) from scheduled_tasks")) == 1
task_columns = {
column["name"] for column in inspect(engine).get_columns("scheduled_tasks")
+4 -3
View File
@@ -25,9 +25,10 @@ def test_compose_defines_database_control_plane_and_outbound_host_agent() -> Non
assert services["host-agent"]["volumes"] == [
"${HOST_AGENT_TASKS_PATH:-./tasks}:/app/tasks"
]
assert services["host-agent"]["environment"][
"HOST_AGENT_CONTROL_PLANE_URL"
] == "http://cloud-api:8001"
assert (
services["host-agent"]["environment"]["HOST_AGENT_CONTROL_PLANE_URL"]
== "http://cloud-api:8001"
)
assert services["host-agent"]["environment"]["AI_PLANNER_ENABLED"] == (
"${AI_PLANNER_ENABLED:-false}"
)
+12 -4
View File
@@ -152,7 +152,9 @@ def test_workflow_runner_failing_planned_goal_marks_run_failed(tmp_path) -> None
assert run.step_results[0].detail["failure_reason"] == "device offline"
def test_workflow_runner_skill_invocation_executes_resolved_tool_calls(tmp_path) -> None:
def test_workflow_runner_skill_invocation_executes_resolved_tool_calls(
tmp_path,
) -> None:
skill_store, skill = _skill_store()
calls: list[dict[str, object]] = []
definition = WorkflowDefinition(
@@ -227,7 +229,9 @@ def test_workflow_runner_branch_paths_and_sequential_advancement(tmp_path) -> No
steps=[
BranchStep(
"branch",
ConditionSpec("world_variable_equals", {"name": "ready", "value": True}),
ConditionSpec(
"world_variable_equals", {"name": "ready", "value": True}
),
on_true="true-step",
on_false="false-step",
),
@@ -320,7 +324,9 @@ def test_workflow_runner_resume_after_branch_crash_advances_to_recorded_target(
steps=[
BranchStep(
"branch",
ConditionSpec("world_variable_equals", {"name": "ready", "value": True}),
ConditionSpec(
"world_variable_equals", {"name": "ready", "value": True}
),
on_true="true-step",
on_false="false-step",
),
@@ -469,7 +475,9 @@ def test_workflow_runner_branch_wait_and_skill_combination(tmp_path) -> None:
steps=[
BranchStep(
"branch",
ConditionSpec("world_variable_equals", {"name": "ready", "value": True}),
ConditionSpec(
"world_variable_equals", {"name": "ready", "value": True}
),
on_true="wait",
on_false="skip",
),
+1 -3
View File
@@ -302,9 +302,7 @@ class WorkflowRunner:
detail={"reason": f"unknown condition kind: {exc}"},
)
elapsed = (
datetime.now(started_at.tzinfo) - started_at
).total_seconds()
elapsed = (datetime.now(started_at.tzinfo) - started_at).total_seconds()
if elapsed >= timeout_seconds:
return WorkflowStepResult(
step_id=step.step_id,