feat(host-protocol): long poll assignments

This commit is contained in:
2026-07-12 18:12:33 +08:00
parent efb754fbe7
commit c7f8d0c128
3 changed files with 121 additions and 2 deletions
+68
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
from datetime import UTC, datetime
from datetime import timedelta
from fastapi import FastAPI
from fastapi.testclient import TestClient
@@ -9,6 +10,7 @@ from cloud.auth import BearerCredential, ConfiguredBearerAuthProvider
from cloud.config import CloudConfig
from cloud.internal_api.api import create_internal_router
from cloud.pool import DevicePool, PooledDevice
from cloud.scheduler import ScheduledTask, TaskConstraints
from cloud.store import CloudStore
@@ -136,3 +138,69 @@ def test_host_token_cannot_submit_heartbeat_for_another_host(tmp_path) -> None:
assert response.status_code == 403
assert pool.store.get_host("host-b") is None
def test_long_poll_claim_returns_at_most_one_owned_assignment(tmp_path) -> None:
client, pool = _build_client(tmp_path)
now = datetime.now(UTC)
pool.store.upsert_host("host-a", address=None, last_seen_at=now)
pool.store.replace_host_devices(
"host-a",
[
PooledDevice(
device_id="claim-device",
host_id="host-a",
driver_type="wda",
status="idle",
synced_at=now,
)
],
)
pool.store.enqueue_task(
ScheduledTask(
id="claim-task",
goal="open settings",
workflow_definition_id=None,
constraints=TaskConstraints(),
created_at=now,
)
)
pool.store.assign_task(
task_id="claim-task",
host_id="host-a",
device_id="claim-device",
lease_id="claim-lease",
lease_expires_at=now + timedelta(minutes=1),
now=now,
)
first = client.post(
"/internal/v1/hosts/host-a/assignments/claim",
headers={"Authorization": "Bearer token-a"},
json={"host_id": "host-a", "timeout_seconds": 0},
)
second = client.post(
"/internal/v1/hosts/host-a/assignments/claim",
headers={"Authorization": "Bearer token-a"},
json={"host_id": "host-a", "timeout_seconds": 0},
)
assert first.status_code == 200
assignment = first.json()["assignment"]
assert assignment["task_id"] == "claim-task"
assert assignment["lease_id"] == "claim-lease"
assert second.status_code == 200
assert second.json() == {"assignment": None, "timed_out": True}
def test_empty_long_poll_timeout_is_normal_response(tmp_path) -> None:
client, _ = _build_client(tmp_path)
response = client.post(
"/internal/v1/hosts/host-a/assignments/claim",
headers={"Authorization": "Bearer token-a"},
json={"host_id": "host-a", "timeout_seconds": 0},
)
assert response.status_code == 200
assert response.json() == {"assignment": None, "timed_out": True}