Files
specklepy/tests/integration/client/current/test_file_import_resource.py
T
Gergő Jedlicska 7bc78b6bf9 feat: add file import resource with complete job handling support (#440)
* feat: add file import resource with complete job handling support

* fix: include the file import resource in the core client too

* feat: integrate with server side parser app

* chore: fix pr comments and make docker compose work with new object
storage

* chore: fix test compose file readiness probe
2025-08-26 14:25:01 +01:00

252 lines
8.0 KiB
Python

from pathlib import Path
import pytest
from specklepy.api import operations
from specklepy.api.client import SpeckleClient
from specklepy.core.api.enums import ProjectVisibility
from specklepy.core.api.inputs.file_import_inputs import (
FileImportErrorInput,
FileImportResult,
FileImportSuccessInput,
GenerateFileUploadUrlInput,
StartFileImportInput,
)
from specklepy.core.api.inputs.model_inputs import CreateModelInput
from specklepy.core.api.inputs.project_inputs import ProjectCreateInput
from specklepy.core.api.inputs.version_inputs import CreateVersionInput
from specklepy.core.api.models import Project
from specklepy.core.api.models.current import FileUploadUrl
from specklepy.core.helpers import crypto_random_string
from specklepy.transports.server.server import ServerTransport
from tests.integration.fakemesh import FakeMesh
class TestFileImportResource:
@pytest.fixture
def file_path(self) -> Path:
path = Path("./tests/integration/client/current/test_file.ifc").absolute()
assert path.exists()
return path
@pytest.fixture
def project(self, client: SpeckleClient) -> Project:
return client.project.create(
ProjectCreateInput(
name="test", description=None, visibility=ProjectVisibility.PRIVATE
)
)
@pytest.fixture(scope="function")
def upload_url(
self, project: Project, file_path: Path, client: SpeckleClient
) -> FileUploadUrl:
upload_url_result = client.file_import.generate_upload_url(
GenerateFileUploadUrlInput(project_id=project.id, file_name=file_path.name)
)
return upload_url_result
def test_generate_upload_url(self, upload_url: FileUploadUrl) -> None:
assert upload_url.file_id
assert upload_url.url
def test_upload_file(
self, file_path: Path, client: SpeckleClient, upload_url: FileUploadUrl
) -> None:
response = client.file_import.upload_file(file=file_path, url=upload_url.url)
assert response.etag
def test_download_file(
self,
file_path: Path,
client: SpeckleClient,
project: Project,
upload_url: FileUploadUrl,
) -> None:
_ = client.file_import.upload_file(file=file_path, url=upload_url.url)
target_file = file_path.parent.joinpath("download.ifc")
downloaded_file = client.file_import.download_file(
project_id=project.id, file_id=upload_url.file_id, target_file=target_file
)
assert downloaded_file.exists()
assert file_path.stat().st_size == downloaded_file.stat().st_size
downloaded_file.unlink()
def test_start_file_import(
self,
file_path: Path,
client: SpeckleClient,
project: Project,
upload_url: FileUploadUrl,
) -> None:
model = client.model.create(
CreateModelInput(name=crypto_random_string(10), project_id=project.id)
)
upload_response = client.file_import.upload_file(
file=file_path, url=upload_url.url
)
response = client.file_import.start_file_import(
StartFileImportInput(
project_id=project.id,
model_id=model.id,
file_id=upload_url.file_id,
etag=upload_response.etag,
)
)
assert response.converted_status == 0
assert response.converted_version_id is None
upload_jobs = client.file_import.get_model_file_import_jobs(
project_id=project.id,
model_id=model.id,
)
assert upload_jobs.total_count == 1
job = upload_jobs.items[0]
assert job
assert job.converted_status == 0
assert job.converted_version_id is None
def test_finish_file_import_success(
self,
file_path: Path,
client: SpeckleClient,
project: Project,
upload_url: FileUploadUrl,
mesh: FakeMesh,
) -> None:
model = client.model.create(
CreateModelInput(name=crypto_random_string(10), project_id=project.id)
)
upload_response = client.file_import.upload_file(
file=file_path, url=upload_url.url
)
job_response = client.file_import.start_file_import(
StartFileImportInput(
project_id=project.id,
model_id=model.id,
file_id=upload_url.file_id,
etag=upload_response.etag,
)
)
assert job_response.converted_status == 0
assert job_response.converted_version_id is None
upload_jobs = client.file_import.get_model_file_import_jobs(
project_id=project.id,
model_id=model.id,
)
assert upload_jobs.total_count == 1
job = upload_jobs.items[0]
assert job
assert job.converted_status == 0
assert job.converted_version_id is None
transport = ServerTransport(client=client, stream_id=project.id)
hash = operations.send(mesh, transports=[transport])
version = client.version.create(
input=CreateVersionInput(
project_id=project.id, model_id=model.id, object_id=hash
)
)
finish_result = client.file_import.finish_file_import_job(
input=FileImportSuccessInput(
project_id=project.id,
job_id=job_response.id,
result=FileImportResult(
download_duration_seconds=0,
duration_seconds=0,
parse_duration_seconds=0,
parser="test",
version_id=version.id,
),
)
)
assert finish_result
upload_jobs = client.file_import.get_model_file_import_jobs(
project_id=project.id,
model_id=model.id,
)
assert upload_jobs.total_count == 1
job = upload_jobs.items[0]
assert job
assert job.converted_status == 2
assert job.converted_version_id == version.id
def test_finish_file_import_error(
self,
file_path: Path,
client: SpeckleClient,
project: Project,
upload_url: FileUploadUrl,
) -> None:
model = client.model.create(
CreateModelInput(name=crypto_random_string(10), project_id=project.id)
)
upload_response = client.file_import.upload_file(
file=file_path, url=upload_url.url
)
job_response = client.file_import.start_file_import(
StartFileImportInput(
project_id=project.id,
model_id=model.id,
file_id=upload_url.file_id,
etag=upload_response.etag,
)
)
assert job_response.converted_status == 0
assert job_response.converted_version_id is None
upload_jobs = client.file_import.get_model_file_import_jobs(
project_id=project.id,
model_id=model.id,
)
assert upload_jobs.total_count == 1
job = upload_jobs.items[0]
assert job
assert job.converted_status == 0
assert job.converted_version_id is None
finish_result = client.file_import.finish_file_import_job(
input=FileImportErrorInput(
project_id=project.id,
job_id=job_response.id,
reason="Test error",
result=FileImportResult(
download_duration_seconds=0,
duration_seconds=0,
parse_duration_seconds=0,
parser="test",
version_id=None,
),
)
)
assert finish_result
upload_jobs = client.file_import.get_model_file_import_jobs(
project_id=project.id,
model_id=model.id,
)
assert upload_jobs.total_count == 1
job = upload_jobs.items[0]
assert job
assert job.converted_status == 3
assert job.converted_version_id is None