Skip to content

Commit f6644a9

Browse files
Add VuMark to endpoint fixture for auth testing (#2960)
* Add VuMark endpoint to parametrized fixture for auth testing Adds a vumark_generate_instance fixture to the endpoint parametrization, allowing all auth tests (missing header, malformed header, bad keys, etc.) to also cover the VuMark instance generation endpoint. Updates the Endpoint class to support endpoints with binary responses by making successful_headers_result_code optional. Updates test_date_header.py to handle VuMark's binary success response. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Fix invalid JSON test failure for VuMark endpoint Real Vuforia returns result_code 'BadRequest' (not 'Fail') when invalid JSON is sent to the VuMark instance generation endpoint. Adds the BAD_REQUEST result code, a BadRequestError exception, and updates validate_json() to raise the correct error based on the request path. Updates the test to expect BadRequest for the /instances endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 1a57511 commit f6644a9

File tree

9 files changed

+119
-5
lines changed

9 files changed

+119
-5
lines changed

src/mock_vws/_constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class ResultCodes(Enum):
6262
TOO_MANY_REQUESTS = "TooManyRequests"
6363
INVALID_ACCEPT_HEADER = "InvalidAcceptHeader"
6464
INVALID_INSTANCE_ID = "InvalidInstanceId"
65+
BAD_REQUEST = "BadRequest"
6566

6667

6768
@beartype

src/mock_vws/_services_validators/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def run_services_validators(
103103
validate_date_format(request_headers=request_headers)
104104
validate_date_in_range(request_headers=request_headers)
105105

106-
validate_json(request_body=request_body)
106+
validate_json(request_body=request_body, request_path=request_path)
107107

108108
validate_keys(
109109
request_body=request_body,

src/mock_vws/_services_validators/exceptions.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ def __init__(self, *, status_code: HTTPStatus) -> None:
184184
}
185185

186186

187+
@beartype
188+
class BadRequestError(ValidatorError):
189+
"""Exception raised when Vuforia returns a response with a result code
190+
'BadRequest'.
191+
"""
192+
193+
def __init__(self) -> None:
194+
"""
195+
Attributes:
196+
status_code: The status code to use in a response if this is
197+
raised.
198+
response_text: The response text to use in a response if this
199+
is
200+
raised.
201+
"""
202+
super().__init__()
203+
self.status_code = HTTPStatus.BAD_REQUEST
204+
body = {
205+
"transaction_id": uuid.uuid4().hex,
206+
"result_code": ResultCodes.BAD_REQUEST.value,
207+
}
208+
self.response_text = json_dump(body=body)
209+
date = email.utils.formatdate(
210+
timeval=None,
211+
localtime=False,
212+
usegmt=True,
213+
)
214+
self.headers = {
215+
"Connection": "keep-alive",
216+
"Content-Type": "application/json",
217+
"server": "envoy",
218+
"Date": date,
219+
"x-envoy-upstream-service-time": "5",
220+
"Content-Length": str(object=len(self.response_text)),
221+
"strict-transport-security": "max-age=31536000",
222+
"x-aws-region": "us-east-2, us-west-2",
223+
"x-content-type-options": "nosniff",
224+
}
225+
226+
187227
@beartype
188228
class MetadataTooLargeError(ValidatorError):
189229
"""Exception raised when Vuforia returns a response with a result code

src/mock_vws/_services_validators/json_validators.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from beartype import beartype
99

1010
from mock_vws._services_validators.exceptions import (
11+
BadRequestError,
1112
FailError,
1213
UnnecessaryRequestBodyError,
1314
)
@@ -43,14 +44,18 @@ def validate_body_given(*, request_body: bytes, request_method: str) -> None:
4344

4445

4546
@beartype
46-
def validate_json(*, request_body: bytes) -> None:
47+
def validate_json(*, request_body: bytes, request_path: str) -> None:
4748
"""Validate that any given body is valid JSON.
4849
4950
Args:
5051
request_body: The body of the request.
52+
request_path: The path of the request.
5153
5254
Raises:
53-
FailError: The request body includes invalid JSON.
55+
BadRequestError: The request body includes invalid JSON for the
56+
VuMark instance generation endpoint.
57+
FailError: The request body includes invalid JSON for other
58+
endpoints.
5459
"""
5560
if not request_body:
5661
return
@@ -59,4 +64,6 @@ def validate_json(*, request_body: bytes) -> None:
5964
json.loads(s=request_body.decode())
6065
except JSONDecodeError as exc:
6166
_LOGGER.warning(msg="The request body is not valid JSON.")
67+
if request_path.endswith("/instances"):
68+
raise BadRequestError from exc
6269
raise FailError(status_code=HTTPStatus.BAD_REQUEST) from exc

tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def target_id(
8585
"target_summary",
8686
"update_target",
8787
"query",
88+
"vumark_generate_instance",
8889
],
8990
)
9091
def endpoint(request: pytest.FixtureRequest) -> Endpoint:

tests/mock_vws/fixtures/prepared_requests.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import json
66
from http import HTTPMethod, HTTPStatus
77
from typing import Any
8+
from uuid import uuid4
89

910
import pytest
1011
from urllib3.filepost import encode_multipart_formdata
@@ -13,6 +14,7 @@
1314

1415
from mock_vws._constants import ResultCodes
1516
from mock_vws.database import VuforiaDatabase
17+
from tests.mock_vws.fixtures.credentials import VuMarkVuforiaDatabase
1618
from tests.mock_vws.utils import Endpoint
1719
from tests.mock_vws.utils.retries import RETRY_ON_TOO_MANY_REQUESTS
1820

@@ -451,3 +453,49 @@ def query(
451453
access_key=access_key,
452454
secret_key=secret_key,
453455
)
456+
457+
458+
@pytest.fixture
459+
def vumark_generate_instance(
460+
vumark_vuforia_database: VuMarkVuforiaDatabase,
461+
) -> Endpoint:
462+
"""Return details of the endpoint for generating a VuMark instance."""
463+
request_path = f"/targets/{vumark_vuforia_database.target_id}/instances"
464+
content_type = "application/json"
465+
method = HTTPMethod.POST
466+
content = json.dumps(obj={"instance_id": uuid4().hex}).encode(
467+
encoding="utf-8"
468+
)
469+
date = rfc_1123_date()
470+
471+
access_key = vumark_vuforia_database.server_access_key
472+
secret_key = vumark_vuforia_database.server_secret_key
473+
authorization_string = authorization_header(
474+
access_key=access_key,
475+
secret_key=secret_key,
476+
method=method,
477+
content=content,
478+
content_type=content_type,
479+
date=date,
480+
request_path=request_path,
481+
)
482+
483+
headers = {
484+
"Accept": "image/png",
485+
"Authorization": authorization_string,
486+
"Content-Length": str(object=len(content)),
487+
"Content-Type": content_type,
488+
"Date": date,
489+
}
490+
491+
return Endpoint(
492+
successful_headers_status_code=HTTPStatus.OK,
493+
successful_headers_result_code=None,
494+
base_url=VWS_HOST,
495+
path_url=request_path,
496+
method=method,
497+
headers=headers,
498+
data=content,
499+
access_key=access_key,
500+
secret_key=secret_key,
501+
)

tests/mock_vws/test_date_header.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,12 @@ def test_date_in_range_after(endpoint: Endpoint) -> None:
381381
assert_query_success(response=response)
382382
return
383383

384+
if endpoint.successful_headers_result_code is None:
385+
assert (
386+
response.status_code == endpoint.successful_headers_status_code
387+
)
388+
return
389+
384390
assert_vws_response(
385391
response=response,
386392
status_code=endpoint.successful_headers_status_code,
@@ -445,6 +451,12 @@ def test_date_in_range_before(endpoint: Endpoint) -> None:
445451
assert_query_success(response=response)
446452
return
447453

454+
if endpoint.successful_headers_result_code is None:
455+
assert (
456+
response.status_code == endpoint.successful_headers_status_code
457+
)
458+
return
459+
448460
assert_vws_response(
449461
response=response,
450462
status_code=endpoint.successful_headers_status_code,

tests/mock_vws/test_invalid_json.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,15 @@ def test_invalid_json(endpoint: Endpoint) -> None:
7575
assert_valid_date_header(response=response)
7676

7777
if takes_json_data:
78+
expected_result_code = (
79+
ResultCodes.BAD_REQUEST
80+
if endpoint.path_url.endswith("/instances")
81+
else ResultCodes.FAIL
82+
)
7883
assert_vws_failure(
7984
response=response,
8085
status_code=HTTPStatus.BAD_REQUEST,
81-
result_code=ResultCodes.FAIL,
86+
result_code=expected_result_code,
8287
)
8388
return
8489

tests/mock_vws/utils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Endpoint:
4747
method: str
4848
headers: Mapping[str, str]
4949
data: bytes | str
50-
successful_headers_result_code: ResultCodes
50+
successful_headers_result_code: ResultCodes | None
5151
successful_headers_status_code: int
5252
access_key: str
5353
secret_key: str

0 commit comments

Comments
 (0)