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
7 changes: 6 additions & 1 deletion docs/source/differences-to-vws.rst
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,13 @@ against real databases in the corresponding states:
``target_quota`` targets.
* ``ProjectSuspended`` is returned by VWS endpoints when a database uses the
:attr:`mock_vws.states.States.PROJECT_SUSPENDED` state.
* ``ProjectHasNoAPIAccess`` is returned by VWS endpoints when a database uses
* ``ProjectHasNoApiAccess`` is returned by VWS endpoints when a database uses
the :attr:`mock_vws.states.States.PROJECT_HAS_NO_API_ACCESS` state.
This casing comes from Vuforia's result codes table, as no response from a
real database in this state has been seen.
``vws-python`` and ``vws-cli`` map this result code by the
``ProjectHasNoAPIAccess`` spelling, so they do not recognize this response
until they are updated.
* ``TooManyRequests`` is returned when a
:class:`mock_vws.database.CloudDatabase` exceeds its
``requests_per_second_limit``. Set the limit to ``0`` to return this result
Expand Down
1 change: 1 addition & 0 deletions newsfragments/project-has-no-api-access-casing.change
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change the ``ProjectHasNoAPIAccess`` result code to ``ProjectHasNoApiAccess``, matching Vuforia's result codes table.
5 changes: 4 additions & 1 deletion src/mock_vws/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ class ResultCodes(Enum):
TARGET_QUOTA_REACHED = "TargetQuotaReached"
PROJECT_SUSPENDED = "ProjectSuspended"
PROJECT_INACTIVE = "ProjectInactive"
PROJECT_HAS_NO_API_ACCESS = "ProjectHasNoAPIAccess"
# We have never seen a real response for a database in this state, so this
# casing comes from Vuforia's result codes table rather than from an
# observed response.
PROJECT_HAS_NO_API_ACCESS = "ProjectHasNoApiAccess"
INACTIVE_PROJECT = "InactiveProject"
TOO_MANY_REQUESTS = "TooManyRequests"
INVALID_ACCEPT_HEADER = "InvalidAcceptHeader"
Expand Down
4 changes: 2 additions & 2 deletions src/mock_vws/_services_validators/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,11 @@ def __init__(self) -> None:


@beartype
class ProjectHasNoAPIAccessError(ValidatorError):
class ProjectHasNoApiAccessError(ValidatorError):
"""Exception raised when a database cannot make API requests."""

def __init__(self) -> None:
"""Initialize a ``ProjectHasNoAPIAccess`` response."""
"""Initialize a ``ProjectHasNoApiAccess`` response."""
super().__init__()
self.status_code = HTTPStatus.FORBIDDEN
body = {
Expand Down
4 changes: 2 additions & 2 deletions src/mock_vws/_services_validators/project_state_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
get_database_matching_server_keys,
)
from mock_vws._services_validators.exceptions import (
ProjectHasNoAPIAccessError,
ProjectHasNoApiAccessError,
ProjectInactiveError,
ProjectSuspendedError,
ValidatorError,
Expand Down Expand Up @@ -53,7 +53,7 @@ def validate_project_state(
)

state_errors: dict[States, type[ValidatorError]] = {
States.PROJECT_HAS_NO_API_ACCESS: ProjectHasNoAPIAccessError,
States.PROJECT_HAS_NO_API_ACCESS: ProjectHasNoApiAccessError,
States.PROJECT_SUSPENDED: ProjectSuspendedError,
}
if error := state_errors.get(database.state):
Expand Down
69 changes: 42 additions & 27 deletions tests/mock_vws/test_requests_mock_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
from freezegun import freeze_time
from PIL import Image
from vws import VWS, CloudRecoService
from vws.exceptions.base_exceptions import VWSError
from vws.exceptions.vws_exceptions import (
ProjectHasNoAPIAccessError,
ProjectSuspendedError,
RequestQuotaReachedError,
TargetQuotaReachedError,
Expand Down Expand Up @@ -461,45 +459,62 @@ def test_target_quota_reached(
)

@staticmethod
@pytest.mark.parametrize(
argnames=("state", "expected_exception", "result_code"),
argvalues=[
(
States.PROJECT_SUSPENDED,
ProjectSuspendedError,
ResultCodes.PROJECT_SUSPENDED,
),
(
States.PROJECT_HAS_NO_API_ACCESS,
ProjectHasNoAPIAccessError,
ResultCodes.PROJECT_HAS_NO_API_ACCESS,
),
],
)
def test_project_state_result_codes(
*,
state: States,
expected_exception: type[VWSError],
result_code: ResultCodes,
) -> None:
"""Configured project states reject VWS requests."""
database = CloudDatabase(state=state)
def test_project_suspended() -> None:
"""A suspended project rejects VWS requests."""
database = CloudDatabase(state=States.PROJECT_SUSPENDED)
client = VWS(
server_access_key=database.server_access_key,
server_secret_key=database.server_secret_key,
)

with MockVWS() as mock:
mock.add_cloud_database(cloud_database=database)
with pytest.raises(expected_exception=expected_exception) as exc:
with pytest.raises(
expected_exception=ProjectSuspendedError,
) as exc:
client.list_targets()

assert_vws_failure(
response=exc.value.response,
status_code=HTTPStatus.FORBIDDEN,
result_code=result_code,
result_code=ResultCodes.PROJECT_SUSPENDED,
)

@staticmethod
def test_project_has_no_api_access() -> None:
"""A project with no API access rejects VWS requests.

This does not use ``vws-python`` because that library maps this
result code by the ``ProjectHasNoAPIAccess`` spelling, which
Vuforia's result codes table does not use.
"""
database = CloudDatabase(state=States.PROJECT_HAS_NO_API_ACCESS)
request_path = "/targets"

with MockVWS() as mock:
mock.add_cloud_database(cloud_database=database)
date = rfc_1123_date()
auth = authorization_header(
access_key=database.server_access_key,
secret_key=database.server_secret_key,
method="GET",
content=b"",
content_type="",
date=date,
request_path=request_path,
)
response = requests.get(
url="https://vws.vuforia.com" + request_path,
headers={
"Authorization": auth,
"Date": date,
},
timeout=30,
)

assert response.status_code == HTTPStatus.FORBIDDEN
assert response.json()["result_code"] == "ProjectHasNoApiAccess"


class TestCustomBaseURLs:
"""Tests for using custom base URLs."""
Expand Down
Loading