fix(simulation): resume live provider builds
This commit is contained in:
@@ -8,6 +8,7 @@ from fastapi import FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from k1link.simulation.gaussian_pipeline_gateway import (
|
||||
GaussianPipelineUnavailableError,
|
||||
GaussianSourceBundleUpload,
|
||||
GaussianSourceMemberUpload,
|
||||
)
|
||||
@@ -281,6 +282,91 @@ def test_failed_project_retries_from_retained_source_and_releases_old_job(tmp_pa
|
||||
assert queued["source"]["uploaded_byte_length"] == queued["source"]["total_byte_length"]
|
||||
|
||||
|
||||
def test_failed_local_project_reattaches_to_live_provider_job_without_rebuild(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
store = SimulationProjectStore(tmp_path)
|
||||
project = store.create(
|
||||
name="Reconnect scene",
|
||||
scene_type="outdoor",
|
||||
source_kind="folder",
|
||||
files=_folder_files(),
|
||||
)
|
||||
_upload_all(store, project)
|
||||
store.begin_build(project["project_id"])
|
||||
store.update_processing(
|
||||
project["project_id"],
|
||||
status="processing",
|
||||
provider_job_id="gsp-20260826000000-deadbeef",
|
||||
provider_state="building_streamed_sog",
|
||||
progress={"completed_steps": 3, "total_steps": 5},
|
||||
bundle_sha256="d" * 64,
|
||||
)
|
||||
store.fail(project["project_id"], "temporary provider transport failure")
|
||||
provider = _ReadyProvider()
|
||||
service = SimulationProjectService(
|
||||
store,
|
||||
provider_factory=lambda: provider,
|
||||
) # type: ignore[arg-type]
|
||||
|
||||
resumed = service.begin_build(project["project_id"])
|
||||
|
||||
assert resumed["status"] == "processing"
|
||||
assert resumed["error"] is None
|
||||
assert resumed["provider"]["job_id"] == "gsp-20260826000000-deadbeef"
|
||||
assert resumed["provider"]["state"] == "ready"
|
||||
assert provider.deleted == []
|
||||
assert provider.upload_calls == 0
|
||||
assert provider.submit_calls == 0
|
||||
|
||||
|
||||
def test_live_provider_reattach_retries_temporary_unavailability(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
store = SimulationProjectStore(tmp_path)
|
||||
project = store.create(
|
||||
name="Flaky tunnel scene",
|
||||
scene_type="outdoor",
|
||||
source_kind="folder",
|
||||
files=_folder_files(),
|
||||
)
|
||||
_upload_all(store, project)
|
||||
store.begin_build(project["project_id"])
|
||||
store.update_processing(
|
||||
project["project_id"],
|
||||
status="processing",
|
||||
provider_job_id="gsp-20260826000000-deadbeef",
|
||||
provider_state="building_collision",
|
||||
bundle_sha256="d" * 64,
|
||||
)
|
||||
store.fail(project["project_id"], "temporary provider transport failure")
|
||||
|
||||
class _FlakyProvider(_ReadyProvider):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.get_job_calls = 0
|
||||
|
||||
def get_job(self, job_id: str) -> dict[str, object]:
|
||||
self.get_job_calls += 1
|
||||
if self.get_job_calls < 3:
|
||||
raise GaussianPipelineUnavailableError("temporary tunnel failure")
|
||||
return super().get_job(job_id)
|
||||
|
||||
provider = _FlakyProvider()
|
||||
monkeypatch.setattr("k1link.simulation.projects.time.sleep", lambda _delay: None)
|
||||
service = SimulationProjectService(
|
||||
store,
|
||||
provider_factory=lambda: provider,
|
||||
) # type: ignore[arg-type]
|
||||
|
||||
resumed = service.begin_build(project["project_id"])
|
||||
|
||||
assert resumed["status"] == "processing"
|
||||
assert provider.get_job_calls == 3
|
||||
assert provider.deleted == []
|
||||
|
||||
|
||||
def test_ready_project_rebuilds_from_retained_source_and_preserves_viewer_settings(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user