Skip to content

Commit a762378

Browse files
Merge pull request #645 from adamtheturtle/weird-target-name-384
Add tests for emoji in target names
2 parents 4a42fbc + 0cf5355 commit a762378

File tree

6 files changed

+127
-4
lines changed

6 files changed

+127
-4
lines changed

CONTRIBUTING.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ A response to an invalid query may have an ``application/json`` content type but
178178

179179
After deleting a target, for up to approximately 30 seconds, matching it with a query returns a 500 response.
180180

181+
A target with the name ``\uffff`` gets stuck in processing.
182+
181183
Performing a release
182184
--------------------
183185

README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ The mock is strict.
193193
That is, it accepts only a few date formats, and rejects all others.
194194
If you find a date format which is accepted by the real Query API but rejected by the mock, please create a GitHub issue.
195195

196+
Targets stuck in processing
197+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
198+
199+
On the real Vuforia Web Services, targets sometimes get stuck in the processing state.
200+
For example, targets with the name ``\uffff`` get stuck in the processing state.
201+
On the mock, no targets get stuck in the processing state.
202+
196203
.. |Build Status| image:: https://travis-ci.org/adamtheturtle/vws-python.svg?branch=master
197204
:target: https://travis-ci.org/adamtheturtle/vws-python
198205
.. |codecov| image:: https://codecov.io/gh/adamtheturtle/vws-python/branch/master/graph/badge.svg

src/mock_vws/_mock_web_services_api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
validate_metadata_encoding,
4242
validate_metadata_size,
4343
validate_metadata_type,
44+
validate_name_characters_in_range,
4445
validate_name_length,
4546
validate_name_type,
4647
validate_not_invalid_json,
@@ -167,6 +168,7 @@ def decorator(method: Callable[..., str]) -> Callable[..., str]:
167168
validate_image_is_image,
168169
validate_image_encoding,
169170
validate_image_data_type,
171+
validate_name_characters_in_range,
170172
validate_name_length,
171173
validate_name_type,
172174
validate_width,

src/mock_vws/_validators.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,48 @@ def validate_name_length(
494494
return json_dump(body)
495495

496496

497+
@wrapt.decorator
498+
def validate_name_characters_in_range(
499+
wrapped: Callable[..., str],
500+
instance: Any, # pylint: disable=unused-argument
501+
args: Tuple[_RequestObjectProxy, _Context],
502+
kwargs: Dict,
503+
) -> str:
504+
"""
505+
Validate the characters in the name argument given to a VWS endpoint.
506+
507+
Args:
508+
wrapped: An endpoint function for `requests_mock`.
509+
instance: The class that the endpoint function is in.
510+
args: The arguments given to the endpoint function.
511+
kwargs: The keyword arguments given to the endpoint function.
512+
513+
Returns:
514+
The result of calling the endpoint.
515+
An ``INTERNAL_SERVER_ERROR`` response if the name is given includes
516+
characters outside of the accepted range.
517+
"""
518+
request, context = args
519+
520+
if not request.text:
521+
return wrapped(*args, **kwargs)
522+
523+
if 'name' not in request.json():
524+
return wrapped(*args, **kwargs)
525+
526+
name = request.json()['name']
527+
528+
if all(ord(character) <= 65535 for character in name):
529+
return wrapped(*args, **kwargs)
530+
531+
context.status_code = codes.INTERNAL_SERVER_ERROR
532+
body = {
533+
'transaction_id': uuid.uuid4().hex,
534+
'result_code': ResultCodes.FAIL.value,
535+
}
536+
return json_dump(body)
537+
538+
497539
@wrapt.decorator
498540
def validate_image_format(
499541
wrapped: Callable[..., str],

tests/mock_vws/test_add_target.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,19 @@ class TestTargetName:
203203
Tests for the target name field.
204204
"""
205205

206+
_MAX_CHAR_VALUE = 65535
207+
206208
@pytest.mark.parametrize(
207209
'name',
208210
[
209211
'á',
212+
# We test just below the max character value.
213+
# This is because targets with the max character value in their
214+
# names get stuck in the processing stage.
215+
chr(_MAX_CHAR_VALUE - 2),
210216
'a' * 64,
211217
],
212-
ids=['Short name', 'Long name'],
218+
ids=['Short name', 'Max char value', 'Long name'],
213219
)
214220
def test_name_valid(
215221
self,
@@ -250,6 +256,9 @@ def test_name_invalid(
250256
) -> None:
251257
"""
252258
A target's name must be a string of length 0 < N < 65.
259+
260+
We test characters out of range in another test as that gives a
261+
different error.
253262
"""
254263
image_data = png_rgb.read()
255264
image_data_encoded = base64.b64encode(image_data).decode('ascii')
@@ -271,6 +280,32 @@ def test_name_invalid(
271280
result_code=ResultCodes.FAIL,
272281
)
273282

283+
def test_character_out_of_range(
284+
self,
285+
png_rgb: io.BytesIO,
286+
vuforia_database_keys: VuforiaDatabaseKeys,
287+
) -> None:
288+
name = chr(self._MAX_CHAR_VALUE + 1)
289+
image_data = png_rgb.read()
290+
image_data_encoded = base64.b64encode(image_data).decode('ascii')
291+
292+
data = {
293+
'name': name,
294+
'width': 1,
295+
'image': image_data_encoded,
296+
}
297+
298+
response = add_target_to_vws(
299+
vuforia_database_keys=vuforia_database_keys,
300+
data=data,
301+
)
302+
303+
assert_vws_failure(
304+
response=response,
305+
status_code=codes.INTERNAL_SERVER_ERROR,
306+
result_code=ResultCodes.FAIL,
307+
)
308+
274309
def test_existing_target_name(
275310
self,
276311
png_rgb: io.BytesIO,

tests/mock_vws/test_update_target.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,19 @@ class TestTargetName:
478478
Tests for the target name field.
479479
"""
480480

481+
_MAX_CHAR_VALUE = 65535
482+
481483
@pytest.mark.parametrize(
482484
'name',
483485
[
484-
'a',
486+
'á',
487+
# We test just below the max character value.
488+
# This is because targets with the max character value in their
489+
# names get stuck in the processing stage.
490+
chr(_MAX_CHAR_VALUE - 2),
485491
'a' * 64,
486492
],
487-
ids=['Short name', 'Long name'],
493+
ids=['Short name', 'Max char value', 'Long name'],
488494
)
489495
def test_name_valid(
490496
self,
@@ -493,7 +499,10 @@ def test_name_valid(
493499
target_id: str,
494500
) -> None:
495501
"""
496-
Names between 1 and 64 characters in length are valid.
502+
A target's name must be a string of length 0 < N < 65.
503+
504+
We test characters out of range in another test as that gives a
505+
different error.
497506
"""
498507
wait_for_target_processed(
499508
vuforia_database_keys=vuforia_database_keys,
@@ -550,6 +559,32 @@ def test_name_invalid(
550559
result_code=ResultCodes.FAIL,
551560
)
552561

562+
def test_character_out_of_range(
563+
self,
564+
png_rgb: io.BytesIO,
565+
vuforia_database_keys: VuforiaDatabaseKeys,
566+
) -> None:
567+
name = chr(self._MAX_CHAR_VALUE + 1)
568+
image_data = png_rgb.read()
569+
image_data_encoded = base64.b64encode(image_data).decode('ascii')
570+
571+
data = {
572+
'name': name,
573+
'width': 1,
574+
'image': image_data_encoded,
575+
}
576+
577+
response = add_target_to_vws(
578+
vuforia_database_keys=vuforia_database_keys,
579+
data=data,
580+
)
581+
582+
assert_vws_failure(
583+
response=response,
584+
status_code=codes.INTERNAL_SERVER_ERROR,
585+
result_code=ResultCodes.FAIL,
586+
)
587+
553588
def test_existing_target_name(
554589
self,
555590
png_rgb_success: io.BytesIO,

0 commit comments

Comments
 (0)