fix: defer automatic uploads while device synchronization is pending
This commit is contained in:
+107
-1
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user