fix: defer automatic uploads while device synchronization is pending
Community checks / verify (push) Skipped
Verify Frame Flow / verify (push) Successful in 5m30s

This commit is contained in:
渡口浪人
2026-10-18 20:21:52 +08:00
parent 50bb41899d
commit a2e8a204e8
11 changed files with 202 additions and 33 deletions
+107 -1
View File
@@ -61,7 +61,9 @@ def test_persistent_block_escalates_once_survives_restart_and_preserves_evidence
== 1
)
assert service.operation(operation)["recovery"]["checks"] == 3
assert service.operation(operation)["result"] == original["result"]
current_result = service.operation(operation)["result"]
assert current_result.pop("sync_observations")
assert current_result == original["result"]
service.reconcile(operation, acknowledge=True)
assert service.operation(operation)["recovery"]["state"] == "resolved"
assert not service.operation(operation)["recovery"]["requires_manual_review"]
@@ -164,3 +166,107 @@ def test_confirmed_temporary_override_does_not_close_earlier_display(service):
service.sync()
assert service.operation(second)["status"] == "COMPLETED"
assert service.operation(first)["status"] == "SYNCING"
@pytest.mark.parametrize("client_id", ["scheduler", "scheduler-retry"])
def test_automatic_upload_waits_for_prior_sync_confirmation(service, client_id):
first = submit(service)
service.process_one()
payload = service.db.one("SELECT payload FROM operations WHERE id=?", (first,))[
"payload"
]
import json
second = service.submit(
"display", json.loads(payload), "living-room", client_id, "fixture"
)
uploads = service.registry.get("living-room").client.uploads
service.process_one()
assert service.operation(second)["status"] == "QUEUED"
assert service.registry.get("living-room").client.uploads == uploads
service.sync()
assert service.operation(first)["status"] == "COMPLETED"
service.process_one()
service.sync()
assert service.operation(second)["status"] == "COMPLETED"
assert service.registry.get("living-room").client.uploads == uploads + 1
def test_device_evidence_is_bounded_and_does_not_extend_sync_timeout(service):
first = submit(service)
service.process_one()
op = service.db.one("SELECT * FROM operations WHERE id=?", (first,))
before = service.operation(first)["updated_at"]
device = service.registry.get("living-room").device()
for i in range(20):
sample = device.model_copy(
update={
"current_content": device.current_content.model_copy(
update={"id": 1000 + i}
)
}
)
service.recovery.observe_device(op, device=sample)
result = service.operation(first)
samples = result["result"]["sync_observations"]
assert len(samples) == 12
assert samples[0]["image_id"] == 1000 and samples[-1]["image_id"] == 1019
assert result["updated_at"] == before
service.update(first, "UNKNOWN", {"image_id": 7})
assert service.operation(first)["result"]["sync_observations"] == samples
def test_device_read_failure_evidence_never_copies_raw_error_details(service):
first = submit(service)
service.process_one()
op = service.db.one("SELECT * FROM operations WHERE id=?", (first,))
service.recovery.observe_device(
op,
error=FlowError(
ErrorCode.CLOUD_UNAVAILABLE,
"unavailable",
details={
"transport_error": "read_timeout",
"url": "private-url-must-not-be-stored",
},
),
)
sample = service.operation(first)["result"]["sync_observations"][-1]
assert sample["read_error"]["transport_error"] == "read_timeout"
assert "private-url" not in str(sample)
def test_sync_timeout_includes_observed_device_state(service):
first = submit(service)
service.process_one()
service.registry.get("living-room").client.synced = False
service.registry.get("living-room").invalidate()
service.settings.sync_timeout = 0
service.sync()
op = service.operation(first)
assert op["status"] == "UNKNOWN"
assert op["error"]["details"]["last_device_observation"]["synced"] is False
def test_automatic_wait_does_not_extend_past_sync_timeout(service):
import json
first = submit(service)
service.process_one()
payload = service.db.one("SELECT payload FROM operations WHERE id=?", (first,))[
"payload"
]
service.db.execute(
"UPDATE operations SET updated_at=? WHERE id=?",
(
(
datetime.now(UTC) - timedelta(seconds=service.settings.sync_timeout + 1)
).isoformat(),
first,
),
)
second = service.submit(
"display", json.loads(payload), "living-room", "scheduler", "fixture"
)
service.process_one()
assert service.operation(second)["status"] == "SYNCING"