Skip to content

Commit 4f438cf

Browse files
Merge pull request #632 from adamtheturtle/query-image-formats
Add query endpoint validation for the image format
2 parents 21aad4f + 47dbb06 commit 4f438cf

File tree

2 files changed

+120
-8
lines changed

2 files changed

+120
-8
lines changed

src/mock_vws/_mock_web_query_api.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import pytz
1616
import wrapt
17+
from PIL import Image
1718
from requests import codes
1819
from requests_mock import POST
1920
from requests_mock.request import _RequestObjectProxy
@@ -28,6 +29,60 @@
2829
ROUTES = set([])
2930

3031

32+
@wrapt.decorator
33+
def validate_image_format(
34+
wrapped: Callable[..., str],
35+
instance: Any, # pylint: disable=unused-argument
36+
args: Tuple[_RequestObjectProxy, _Context],
37+
kwargs: Dict,
38+
) -> str:
39+
"""
40+
Validate the format of the image given to the query endpoint.
41+
42+
Args:
43+
wrapped: An endpoint function for `requests_mock`.
44+
instance: The class that the endpoint function is in.
45+
args: The arguments given to the endpoint function.
46+
kwargs: The keyword arguments given to the endpoint function.
47+
48+
Returns:
49+
The result of calling the endpoint.
50+
An `UNPROCESSABLE_ENTITY` response if the image is given and is not
51+
either a PNG or a JPEG.
52+
"""
53+
request, context = args
54+
body_file = io.BytesIO(request.body)
55+
56+
_, pdict = cgi.parse_header(request.headers['Content-Type'])
57+
parsed = cgi.parse_multipart(
58+
fp=body_file,
59+
pdict={
60+
'boundary': pdict['boundary'].encode(),
61+
},
62+
)
63+
64+
[image] = parsed['image']
65+
66+
image_file = io.BytesIO(image)
67+
pil_image = Image.open(image_file)
68+
69+
if pil_image.format in ('PNG', 'JPEG'):
70+
return wrapped(*args, **kwargs)
71+
72+
context.status_code = codes.UNPROCESSABLE_ENTITY
73+
transaction_id = uuid.uuid4().hex
74+
result_code = ResultCodes.BAD_IMAGE.value
75+
76+
# The response has an unusual format of separators, so we construct it
77+
# manually.
78+
return (
79+
'{"transaction_id": '
80+
f'"{transaction_id}",'
81+
f'"result_code":"{result_code}"'
82+
'}'
83+
)
84+
85+
3186
@wrapt.decorator
3287
def validate_date_header_given(
3388
wrapped: Callable[..., str],
@@ -421,6 +476,7 @@ def decorator(method: Callable[..., str]) -> Callable[..., str]:
421476
validate_date_header_given,
422477
validate_include_target_data,
423478
validate_max_num_results,
479+
validate_image_format,
424480
validate_image_field_given,
425481
validate_extra_fields,
426482
validate_content_type_header,

tests/mock_vws/test_query.py

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313

1414
import pytest
1515
import requests
16+
from PIL import Image
1617
from requests import codes
1718
from requests_mock import POST
1819
from urllib3.filepost import encode_multipart_formdata
1920

20-
from mock_vws._constants import TargetStatuses
21+
from mock_vws._constants import ResultCodes, TargetStatuses
2122
from tests.mock_vws.utils import (
2223
add_target_to_vws,
2324
delete_target,
@@ -28,6 +29,8 @@
2829
)
2930
from tests.mock_vws.utils.assertions import (
3031
assert_query_success,
32+
assert_valid_date_header,
33+
assert_valid_transaction_id,
3134
assert_vwq_failure,
3235
)
3336
from tests.mock_vws.utils.authorization import (
@@ -939,7 +942,6 @@ def test_valid(
939942
date=date,
940943
request_path=request_path,
941944
)
942-
943945
headers = {
944946
'Authorization': authorization_string,
945947
'Date': date,
@@ -1077,17 +1079,71 @@ class TestImageFormats:
10771079
Tests for various image formats.
10781080
"""
10791081

1080-
def test_supported(self) -> None:
1082+
@pytest.mark.parametrize('file_format', ['png', 'jpeg'])
1083+
def test_supported(
1084+
self,
1085+
high_quality_image: io.BytesIO,
1086+
vuforia_database_keys: VuforiaDatabaseKeys,
1087+
file_format: str,
1088+
) -> None:
10811089
"""
1082-
See https://github.com/adamtheturtle/vws-python/issues/357 for
1083-
implementing this test.
1090+
PNG and JPEG formats are supported.
10841091
"""
1092+
image_buffer = io.BytesIO()
1093+
pil_image = Image.open(high_quality_image)
1094+
pil_image.save(image_buffer, file_format)
1095+
image_content = image_buffer.getvalue()
10851096

1086-
def test_unsupported(self) -> None:
1097+
body = {'image': ('image.jpeg', image_content, 'image/jpeg')}
1098+
1099+
response = query(
1100+
vuforia_database_keys=vuforia_database_keys,
1101+
body=body,
1102+
)
1103+
1104+
assert_query_success(response=response)
1105+
assert response.json()['results'] == []
1106+
1107+
def test_unsupported(
1108+
self,
1109+
high_quality_image: io.BytesIO,
1110+
vuforia_database_keys: VuforiaDatabaseKeys,
1111+
) -> None:
10871112
"""
1088-
See https://github.com/adamtheturtle/vws-python/issues/357 for
1089-
implementing this test.
1113+
File formats which are not PNG or JPEG are not supported.
10901114
"""
1115+
file_format = 'tiff'
1116+
image_buffer = io.BytesIO()
1117+
pil_image = Image.open(high_quality_image)
1118+
pil_image.save(image_buffer, file_format)
1119+
image_content = image_buffer.getvalue()
1120+
1121+
body = {'image': ('image.jpeg', image_content, 'image/jpeg')}
1122+
1123+
response = query(
1124+
vuforia_database_keys=vuforia_database_keys,
1125+
body=body,
1126+
)
1127+
1128+
assert_vwq_failure(
1129+
response=response,
1130+
status_code=codes.UNPROCESSABLE_ENTITY,
1131+
content_type='application/json',
1132+
)
1133+
assert response.json().keys() == {'transaction_id', 'result_code'}
1134+
assert_valid_transaction_id(response=response)
1135+
assert_valid_date_header(response=response)
1136+
result_code = response.json()['result_code']
1137+
transaction_id = response.json()['transaction_id']
1138+
assert result_code == ResultCodes.BAD_IMAGE.value
1139+
# The separators are inconsistent and we test this.
1140+
expected_text = (
1141+
'{"transaction_id": '
1142+
f'"{transaction_id}",'
1143+
f'"result_code":"{result_code}"'
1144+
'}'
1145+
)
1146+
assert response.text == expected_text
10911147

10921148

10931149
@pytest.mark.usefixtures('verify_mock_vuforia')

0 commit comments

Comments
 (0)