Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/source/differences-to-vws.rst
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ Real Vuforia separates these by OAuth scope as well, which the mock does not mod

Some Model Target Web API paths remain mock-only in ``tests/mock_vws/test_model_target_web_api.py::TestMockOnlyErrors``.
Downloads of still-processing datasets are mock-only because exercising the path against real Vuforia would require creating a dataset on every test run; the mock drives the processing window deterministically.
A download request for a dataset which is not ready reports the dataset's
training status. The mock reports ``not-started`` for the whole processing
window, as real Vuforia does for a dataset which was just created, and
``failed`` for a dataset whose generation failed. The name which real Vuforia
reports for a failed dataset has not been observed.
Advanced-dataset creation with more than 20 models is mock-only because the available test account lacks the advanced-dataset scope and real Vuforia rejects the request with a 403 before validating model counts.
Cross-dataset-type access is mock-only for the same reason.
State-Based Model Target creation and validation are also mock-only because the
Expand Down
1 change: 1 addition & 0 deletions newsfragments/model-target-failed-download-status.change
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Report the ``failed`` training status when downloading a Model Target dataset whose generation failed, rather than the ``not-started`` status which a still-processing dataset reports.
15 changes: 14 additions & 1 deletion src/mock_vws/_model_target_web_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ def remove_model_target_dataset(self, dataset_uuid: str) -> None:
"simplify": frozenset({"always", "auto", "never"}),
"trackingMode": frozenset({"car", "default", "scan"}),
}
# The training status which the download route reports for a dataset which
# is not ready to download, keyed by the status which the status route
# reports.
#
# Real Vuforia reports ``not-started`` for a dataset which was created just
# before the download request, so the mock uses that name for the whole
# processing window. The name for a dataset whose generation failed has not
# been observed.
_TRAINING_STATUSES: dict[str, str] = {
"processing": "not-started",
"failed": "failed",
}
# ``realisticAppearance`` is documented as an enumerated model field for
# advanced datasets only.
_ADVANCED_MODEL_ENUM_FIELD_VALUES: dict[str, frozenset[str]] = {
Expand Down Expand Up @@ -1057,12 +1069,13 @@ def download_model_target_dataset(
if dataset is None:
return _unknown_dataset_response(dataset_uuid=dataset_uuid)
if dataset.status != "done":
training_status = _TRAINING_STATUSES[dataset.status]
return _error_response(
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
code="UNSUPPORTED_STATE",
message=(
f"Training status for dataset {dataset_uuid} is "
"not-started != done"
f"{training_status} != done"
),
target=dataset_uuid,
details=None,
Expand Down
46 changes: 45 additions & 1 deletion tests/mock_vws/test_model_target_web_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from beartype import beartype
from vws.response import Response

from mock_vws import MockVWS
from mock_vws import MockVWS, ModelTargetGenerationFailure
from mock_vws.model_target import ModelTargetDataset, ModelTargetDatasetType
from tests.mock_vws.fixtures.model_target_prepared_requests import (
MODEL_TARGET_DATASET_UUID,
Expand Down Expand Up @@ -1501,6 +1501,50 @@ def test_processing_dataset_cannot_be_downloaded() -> None:
)
assert error["target"] == dataset_uuid

@staticmethod
def test_failed_dataset_cannot_be_downloaded() -> None:
"""A dataset which failed generation cannot be downloaded, and the
error reports the failed training status rather than the
``not-started`` status which a still-processing dataset reports.

Mock-only because a generation failure cannot be provoked on demand
against real Vuforia, so the training status name it reports for a
failed dataset has not been observed.
"""
failure = ModelTargetGenerationFailure(message="CAD model is invalid")
with MockVWS(
processing_time_seconds=0,
model_target_generation_failure=failure,
):
create_response = requests.post(
url=f"{_VWS_HOST}/modeltargets/datasets",
headers={"Authorization": f"Bearer {_MOCK_BEARER_TOKEN}"},
json=_UNAUTHENTICATED_DATASET_REQUEST,
timeout=30,
)
dataset_uuid = create_response.json()["uuid"]
status_response = requests.get(
url=f"{_VWS_HOST}/modeltargets/datasets/{dataset_uuid}/status",
headers={"Authorization": f"Bearer {_MOCK_BEARER_TOKEN}"},
timeout=30,
)
response = requests.get(
url=(
f"{_VWS_HOST}/modeltargets/datasets/{dataset_uuid}/dataset"
),
headers={"Authorization": f"Bearer {_MOCK_BEARER_TOKEN}"},
timeout=30,
)

assert status_response.json()["status"] == "failed"
assert response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
error = response.json()["error"]
assert error["code"] == "UNSUPPORTED_STATE"
assert error["message"] == (
f"Training status for dataset {dataset_uuid} is failed != done"
)
assert error["target"] == dataset_uuid

@staticmethod
@pytest.mark.parametrize(
argnames=("created_path", "other_path"),
Expand Down
Loading