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
1 change: 1 addition & 0 deletions src/mock_vws/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class ResultCodes(Enum):
TOO_MANY_REQUESTS = "TooManyRequests"
INVALID_ACCEPT_HEADER = "InvalidAcceptHeader"
INVALID_INSTANCE_ID = "InvalidInstanceId"
BAD_REQUEST = "BadRequest"


@beartype
Expand Down
2 changes: 1 addition & 1 deletion src/mock_vws/_services_validators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def run_services_validators(
validate_date_format(request_headers=request_headers)
validate_date_in_range(request_headers=request_headers)

validate_json(request_body=request_body)
validate_json(request_body=request_body, request_path=request_path)

validate_keys(
request_body=request_body,
Expand Down
40 changes: 40 additions & 0 deletions src/mock_vws/_services_validators/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,46 @@ def __init__(self, *, status_code: HTTPStatus) -> None:
}


@beartype
class BadRequestError(ValidatorError):
"""Exception raised when Vuforia returns a response with a result code
'BadRequest'.
"""

def __init__(self) -> None:
"""
Attributes:
status_code: The status code to use in a response if this is
raised.
response_text: The response text to use in a response if this
is
raised.
"""
super().__init__()
self.status_code = HTTPStatus.BAD_REQUEST
body = {
"transaction_id": uuid.uuid4().hex,
"result_code": ResultCodes.BAD_REQUEST.value,
}
self.response_text = json_dump(body=body)
date = email.utils.formatdate(
timeval=None,
localtime=False,
usegmt=True,
)
self.headers = {
"Connection": "keep-alive",
"Content-Type": "application/json",
"server": "envoy",
"Date": date,
"x-envoy-upstream-service-time": "5",
"Content-Length": str(object=len(self.response_text)),
"strict-transport-security": "max-age=31536000",
"x-aws-region": "us-east-2, us-west-2",
"x-content-type-options": "nosniff",
}


@beartype
class MetadataTooLargeError(ValidatorError):
"""Exception raised when Vuforia returns a response with a result code
Expand Down
11 changes: 9 additions & 2 deletions src/mock_vws/_services_validators/json_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from beartype import beartype

from mock_vws._services_validators.exceptions import (
BadRequestError,
FailError,
UnnecessaryRequestBodyError,
)
Expand Down Expand Up @@ -43,14 +44,18 @@ def validate_body_given(*, request_body: bytes, request_method: str) -> None:


@beartype
def validate_json(*, request_body: bytes) -> None:
def validate_json(*, request_body: bytes, request_path: str) -> None:
"""Validate that any given body is valid JSON.

Args:
request_body: The body of the request.
request_path: The path of the request.

Raises:
FailError: The request body includes invalid JSON.
BadRequestError: The request body includes invalid JSON for the
VuMark instance generation endpoint.
FailError: The request body includes invalid JSON for other
endpoints.
"""
if not request_body:
return
Expand All @@ -59,4 +64,6 @@ def validate_json(*, request_body: bytes) -> None:
json.loads(s=request_body.decode())
except JSONDecodeError as exc:
_LOGGER.warning(msg="The request body is not valid JSON.")
if request_path.endswith("/instances"):
raise BadRequestError from exc
raise FailError(status_code=HTTPStatus.BAD_REQUEST) from exc
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def target_id(
"target_summary",
"update_target",
"query",
"vumark_generate_instance",
],
)
def endpoint(request: pytest.FixtureRequest) -> Endpoint:
Expand Down
48 changes: 48 additions & 0 deletions tests/mock_vws/fixtures/prepared_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import json
from http import HTTPMethod, HTTPStatus
from typing import Any
from uuid import uuid4

import pytest
from urllib3.filepost import encode_multipart_formdata
Expand All @@ -13,6 +14,7 @@

from mock_vws._constants import ResultCodes
from mock_vws.database import VuforiaDatabase
from tests.mock_vws.fixtures.credentials import VuMarkVuforiaDatabase
from tests.mock_vws.utils import Endpoint
from tests.mock_vws.utils.retries import RETRY_ON_TOO_MANY_REQUESTS

Expand Down Expand Up @@ -451,3 +453,49 @@ def query(
access_key=access_key,
secret_key=secret_key,
)


@pytest.fixture
def vumark_generate_instance(
vumark_vuforia_database: VuMarkVuforiaDatabase,
) -> Endpoint:
"""Return details of the endpoint for generating a VuMark instance."""
request_path = f"/targets/{vumark_vuforia_database.target_id}/instances"
content_type = "application/json"
method = HTTPMethod.POST
content = json.dumps(obj={"instance_id": uuid4().hex}).encode(
encoding="utf-8"
)
date = rfc_1123_date()

access_key = vumark_vuforia_database.server_access_key
secret_key = vumark_vuforia_database.server_secret_key
authorization_string = authorization_header(
access_key=access_key,
secret_key=secret_key,
method=method,
content=content,
content_type=content_type,
date=date,
request_path=request_path,
)

headers = {
"Accept": "image/png",
"Authorization": authorization_string,
"Content-Length": str(object=len(content)),
"Content-Type": content_type,
"Date": date,
}

return Endpoint(
successful_headers_status_code=HTTPStatus.OK,
successful_headers_result_code=None,
base_url=VWS_HOST,
path_url=request_path,
method=method,
headers=headers,
data=content,
access_key=access_key,
secret_key=secret_key,
)
12 changes: 12 additions & 0 deletions tests/mock_vws/test_date_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,12 @@ def test_date_in_range_after(endpoint: Endpoint) -> None:
assert_query_success(response=response)
return

if endpoint.successful_headers_result_code is None:
assert (
response.status_code == endpoint.successful_headers_status_code
)
return

assert_vws_response(
response=response,
status_code=endpoint.successful_headers_status_code,
Expand Down Expand Up @@ -445,6 +451,12 @@ def test_date_in_range_before(endpoint: Endpoint) -> None:
assert_query_success(response=response)
return

if endpoint.successful_headers_result_code is None:
assert (
response.status_code == endpoint.successful_headers_status_code
)
return

assert_vws_response(
response=response,
status_code=endpoint.successful_headers_status_code,
Expand Down
7 changes: 6 additions & 1 deletion tests/mock_vws/test_invalid_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,15 @@ def test_invalid_json(endpoint: Endpoint) -> None:
assert_valid_date_header(response=response)

if takes_json_data:
expected_result_code = (
ResultCodes.BAD_REQUEST
if endpoint.path_url.endswith("/instances")
else ResultCodes.FAIL
)
assert_vws_failure(
response=response,
status_code=HTTPStatus.BAD_REQUEST,
result_code=ResultCodes.FAIL,
result_code=expected_result_code,
)
return

Expand Down
2 changes: 1 addition & 1 deletion tests/mock_vws/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Endpoint:
method: str
headers: Mapping[str, str]
data: bytes | str
successful_headers_result_code: ResultCodes
successful_headers_result_code: ResultCodes | None
successful_headers_status_code: int
access_key: str
secret_key: str
Expand Down