Skip to content
Merged
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
44 changes: 35 additions & 9 deletions tests/mock_vws/fixtures/api_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import base64
import binascii
import contextlib
import io
import uuid
from dataclasses import dataclass
Expand All @@ -12,13 +13,19 @@
from tenacity.retry import retry_if_not_result
from tenacity.stop import stop_after_attempt
from vws import VWS, CloudRecoService
from vws.reports import TargetStatuses
from vws.exceptions.custom_exceptions import TargetProcessingTimeoutError
from vws.exceptions.vws_exceptions import (
TargetStatusProcessingError,
UnknownTargetError,
)
from vws.reports import TargetStatusAndRecord, TargetStatuses

from mock_vws.database import CloudDatabase
from tests.mock_vws.utils import Endpoint, ModelTargetEndpoint
from tests.mock_vws.utils.retries import (
RETRY_ON_TARGET_NOT_YET_VISIBLE,
RETRY_ON_TRANSIENT_VWS_FAILURE,
TRANSIENT_VWS_EXCEPTIONS,
)

# The number of targets to add before giving up on getting one which
Expand Down Expand Up @@ -107,16 +114,20 @@ def _add_target(*, vws_client: VWS, image: io.BytesIO) -> str:


@beartype
@RETRY_ON_TRANSIENT_VWS_FAILURE
@RETRY_ON_TARGET_NOT_YET_VISIBLE
def _wait_for_target_processed(*, vws_client: VWS, target_id_: str) -> None:
"""Wait for a target to finish processing.
def _get_processed_target(
*, vws_client: VWS, target_id_: str
) -> TargetStatusAndRecord:
"""Wait for and read a known target without repeating its creation.

Real Vuforia sometimes reports a target which it has just created as
unknown, because the target is not yet visible to the read path. We know
the target exists, because Vuforia gave us its ID, so we retry rather
than fail.
"""
vws_client.wait_for_target_processed(target_id=target_id_)
return vws_client.get_target_record(target_id=target_id_)


@dataclass(frozen=True, kw_only=True)
Expand All @@ -136,7 +147,6 @@ def _target_processed_successfully(result: _TargetProcessingResult) -> bool:


@beartype
@RETRY_ON_TRANSIENT_VWS_FAILURE
@retry(
retry=retry_if_not_result(predicate=_target_processed_successfully),
stop=stop_after_attempt(max_attempt_number=_TARGET_SUCCESS_ATTEMPTS),
Expand All @@ -157,11 +167,27 @@ def _add_target_which_processed_successfully(
The ID and processing status of the added target.
"""
target_id_ = _add_target(vws_client=vws_client, image=image)
_wait_for_target_processed(
vws_client=vws_client,
target_id_=target_id_,
)
target_details = vws_client.get_target_record(target_id=target_id_)
try:
target_details = _get_processed_target(
vws_client=vws_client,
target_id_=target_id_,
)
except (
*TRANSIENT_VWS_EXCEPTIONS,
UnknownTargetError,
TargetProcessingTimeoutError,
): # pragma: no cover
# Setup owns the target until it can return it to the test. Cleanup
# is best effort: transient failures, a processing target, or one
# already gone must not hide the setup error.
# The real adapter also clears remaining targets before the next test.
with contextlib.suppress(
*TRANSIENT_VWS_EXCEPTIONS,
TargetStatusProcessingError,
UnknownTargetError,
):
vws_client.delete_target(target_id=target_id_)
raise
# Failed processing is nondeterministic against the live service.
if target_details.status != TargetStatuses.SUCCESS:
vws_client.delete_target(target_id=target_id_) # pragma: no cover
Expand Down
Loading