feat(simulation): add portable gaussian provider connector
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from k1link.simulation.gaussian_pipeline_gateway import (
|
||||
BUILD_REQUEST_SCHEMA,
|
||||
GaussianPipelineGateway,
|
||||
GaussianPipelineGatewayError,
|
||||
GaussianPipelineIntegrityError,
|
||||
)
|
||||
|
||||
|
||||
def _token_file(tmp_path: Path) -> Path:
|
||||
token = tmp_path / "gaussian.token"
|
||||
token.write_text("t" * 64, encoding="utf-8")
|
||||
return token
|
||||
|
||||
|
||||
def test_gateway_uploads_with_tus_and_reads_provider_contract(tmp_path: Path) -> None:
|
||||
uploaded = bytearray()
|
||||
metadata: dict[str, str] = {}
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
assert request.headers["authorization"] == f"Bearer {'t' * 64}"
|
||||
if request.method == "GET" and request.url.path == "/v1/capabilities":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"schema_version": "gaussian-pipeline.capabilities/v1",
|
||||
"service": "ndc-gaussian-pipeline",
|
||||
"provider": {"id": "playcanvas-splat-transform", "version": "3.3.3"},
|
||||
},
|
||||
)
|
||||
if request.method == "POST" and request.url.path == "/v1/uploads":
|
||||
for item in request.headers["upload-metadata"].split(","):
|
||||
key, encoded = item.split(" ", 1)
|
||||
metadata[key] = base64.b64decode(encoded).decode("utf-8")
|
||||
return httpx.Response(201, headers={"Location": "/v1/uploads/upload-001"})
|
||||
if request.method == "HEAD" and request.url.path == "/v1/uploads/upload-001":
|
||||
return httpx.Response(200, headers={"Upload-Offset": str(len(uploaded))})
|
||||
if request.method == "PATCH" and request.url.path == "/v1/uploads/upload-001":
|
||||
assert int(request.headers["upload-offset"]) == len(uploaded)
|
||||
uploaded.extend(request.content)
|
||||
return httpx.Response(204, headers={"Upload-Offset": str(len(uploaded))})
|
||||
return httpx.Response(404)
|
||||
|
||||
source = tmp_path / "yard.lcc2"
|
||||
source.write_bytes(b"portable-gaussian-source")
|
||||
digest = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
with GaussianPipelineGateway(
|
||||
"http://gaussian.test",
|
||||
_token_file(tmp_path),
|
||||
chunk_bytes=5,
|
||||
transport=httpx.MockTransport(handler),
|
||||
) as gateway:
|
||||
assert gateway.capabilities()["service"] == "ndc-gaussian-pipeline"
|
||||
descriptor = gateway.upload_source(
|
||||
source,
|
||||
filename="yard.lcc2",
|
||||
source_format="lcc2",
|
||||
sha256=digest,
|
||||
)
|
||||
|
||||
assert bytes(uploaded) == source.read_bytes()
|
||||
assert metadata == {"filename": "yard.lcc2", "format": "lcc2", "sha256": digest}
|
||||
assert descriptor.to_dict() == {
|
||||
"upload_id": "upload-001",
|
||||
"filename": "yard.lcc2",
|
||||
"format": "lcc2",
|
||||
"sha256": digest,
|
||||
"byte_length": len(uploaded),
|
||||
}
|
||||
|
||||
|
||||
def test_gateway_rejects_local_source_digest_mismatch(tmp_path: Path) -> None:
|
||||
source = tmp_path / "yard.lcc"
|
||||
source.write_bytes(b"source")
|
||||
with (
|
||||
GaussianPipelineGateway(
|
||||
"http://gaussian.test",
|
||||
_token_file(tmp_path),
|
||||
transport=httpx.MockTransport(lambda _request: httpx.Response(500)),
|
||||
) as gateway,
|
||||
pytest.raises(GaussianPipelineIntegrityError, match="digest does not match"),
|
||||
):
|
||||
gateway.upload_source(
|
||||
source,
|
||||
filename="yard.lcc",
|
||||
source_format="lcc",
|
||||
sha256="a" * 64,
|
||||
)
|
||||
|
||||
|
||||
def test_gateway_rejects_upload_location_outside_provider(tmp_path: Path) -> None:
|
||||
source = tmp_path / "yard.lcc"
|
||||
source.write_bytes(b"source")
|
||||
digest = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
|
||||
def handler(_request: httpx.Request) -> httpx.Response:
|
||||
return httpx.Response(
|
||||
201,
|
||||
headers={"Location": "https://attacker.invalid/v1/uploads/stolen"},
|
||||
)
|
||||
|
||||
with (
|
||||
GaussianPipelineGateway(
|
||||
"http://gaussian.test",
|
||||
_token_file(tmp_path),
|
||||
transport=httpx.MockTransport(handler),
|
||||
) as gateway,
|
||||
pytest.raises(GaussianPipelineGatewayError, match="escaped the provider"),
|
||||
):
|
||||
gateway.upload_source(
|
||||
source,
|
||||
filename="yard.lcc",
|
||||
source_format="lcc",
|
||||
sha256=digest,
|
||||
)
|
||||
|
||||
|
||||
def test_gateway_rejects_symlink_source_and_token(tmp_path: Path) -> None:
|
||||
source = tmp_path / "source.lcc"
|
||||
source.write_bytes(b"source")
|
||||
source_link = tmp_path / "source-link.lcc"
|
||||
source_link.symlink_to(source)
|
||||
token = _token_file(tmp_path)
|
||||
token_link = tmp_path / "token-link"
|
||||
token_link.symlink_to(token)
|
||||
|
||||
with pytest.raises(GaussianPipelineGatewayError, match="token must be one regular file"):
|
||||
GaussianPipelineGateway("http://gaussian.test", token_link)
|
||||
|
||||
digest = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||
with (
|
||||
GaussianPipelineGateway(
|
||||
"http://gaussian.test",
|
||||
token,
|
||||
transport=httpx.MockTransport(lambda _request: httpx.Response(500)),
|
||||
) as gateway,
|
||||
pytest.raises(GaussianPipelineIntegrityError, match="one regular file"),
|
||||
):
|
||||
gateway.upload_source(
|
||||
source_link,
|
||||
filename="source.lcc",
|
||||
source_format="lcc",
|
||||
sha256=digest,
|
||||
)
|
||||
|
||||
|
||||
def test_gateway_submits_tracks_and_imports_digest_bound_artifact(tmp_path: Path) -> None:
|
||||
artifact = b"preview-sog"
|
||||
artifact_sha = hashlib.sha256(artifact).hexdigest()
|
||||
job_id = "gsp-20260825200000-deadbeef"
|
||||
request_document: dict[str, object] = {
|
||||
"schema_version": BUILD_REQUEST_SCHEMA,
|
||||
"idempotency_key": "missioncore-build-01",
|
||||
}
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
if request.method == "POST" and request.url.path == "/v1/jobs":
|
||||
assert json.loads(request.content) == request_document
|
||||
return httpx.Response(
|
||||
202,
|
||||
json={"schema_version": "gaussian-pipeline.job/v1", "job_id": job_id},
|
||||
)
|
||||
if request.method == "GET" and request.url.path == f"/v1/jobs/{job_id}":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={"schema_version": "gaussian-pipeline.job/v1", "job_id": job_id},
|
||||
)
|
||||
if request.method == "GET" and request.url.path == f"/v1/jobs/{job_id}/result":
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={"schema_version": "gaussian-pipeline.build-result/v1", "job_id": job_id},
|
||||
)
|
||||
if request.method == "GET" and request.url.path.endswith("/artifacts/preview.sog"):
|
||||
return httpx.Response(200, content=artifact)
|
||||
return httpx.Response(404)
|
||||
|
||||
with GaussianPipelineGateway(
|
||||
"http://gaussian.test",
|
||||
_token_file(tmp_path),
|
||||
transport=httpx.MockTransport(handler),
|
||||
) as gateway:
|
||||
assert gateway.submit_build(request_document)["job_id"] == job_id
|
||||
assert gateway.get_job(job_id)["job_id"] == job_id
|
||||
assert gateway.get_result(job_id)["job_id"] == job_id
|
||||
destination = gateway.download_artifact(
|
||||
job_id,
|
||||
{
|
||||
"logical_path": "preview.sog",
|
||||
"sha256": artifact_sha,
|
||||
"byte_length": len(artifact),
|
||||
},
|
||||
tmp_path / "import" / "preview.sog",
|
||||
)
|
||||
assert destination.read_bytes() == artifact
|
||||
Reference in New Issue
Block a user