Skip to content

Commit 21aad4f

Browse files
Merge pull request #630 from adamtheturtle/user-set-time
Allow users to set the amount of time after a target is deleted for which a 500 will be returned on a match
2 parents 9072640 + 80da22e commit 21aad4f

File tree

6 files changed

+190
-55
lines changed

6 files changed

+190
-55
lines changed

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ Matching deleted targets
182182

183183
Matching a target which has been deleted returns a 500 (INTERNAL SERVER ERROR) response within the first few seconds.
184184
This timeframe is not consistent on the real Vuforia Web Services.
185-
On the mock, this timeframe is always three seconds.
185+
On the mock, this timeframe is three seconds by default.
186+
``MockVWS`` takes a parameter ``query_recognizes_deletion_seconds`` to change this.
186187

187188
.. |Build Status| image:: https://travis-ci.org/adamtheturtle/vws-python.svg?branch=master
188189
:target: https://travis-ci.org/adamtheturtle/vws-python

src/mock_vws/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def __init__( # pylint: disable=too-many-arguments
3737
client_secret_key: Optional[str]=None,
3838
database_name: Optional[str]=None,
3939
processing_time_seconds: Union[int, float]=0.5,
40+
query_recognizes_deletion_seconds: Union[int, float]=3,
4041
) -> None:
4142
"""
4243
Args:
@@ -56,6 +57,9 @@ def __init__( # pylint: disable=too-many-arguments
5657
deterministic.
5758
base_vwq_url: The base URL for the VWQ API.
5859
base_vws_url: The base URL for the VWS API.
60+
query_recognizes_deletion_seconds: The number of seconds after a
61+
target has been deleted that the query endpoint will return a
62+
500 response for on a match.
5963
6064
6165
Attributes:
@@ -95,6 +99,10 @@ def __init__( # pylint: disable=too-many-arguments
9599
self._base_vws_url = base_vws_url
96100
self._base_vwq_url = base_vwq_url
97101

102+
self._query_recognizes_deletion_seconds = (
103+
query_recognizes_deletion_seconds
104+
)
105+
98106
def __enter__(self) -> 'MockVWS':
99107
"""
100108
Start an instance of a Vuforia mock with access keys set from
@@ -115,7 +123,9 @@ def __enter__(self) -> 'MockVWS':
115123
client_access_key=self.client_access_key,
116124
client_secret_key=self.client_secret_key,
117125
mock_web_services_api=mock_vws_api,
118-
query_recognizes_deletion_seconds=3,
126+
query_recognizes_deletion_seconds=(
127+
self._query_recognizes_deletion_seconds
128+
),
119129
)
120130

121131
date = email.utils.formatdate(None, localtime=False, usegmt=True)

src/mock_vws/_mock_web_query_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import io
1111
import uuid
1212
from pathlib import Path
13-
from typing import Any, Callable, Dict, List, Set, Tuple
13+
from typing import Any, Callable, Dict, List, Set, Tuple, Union
1414

1515
import pytz
1616
import wrapt
@@ -449,7 +449,7 @@ def __init__(
449449
client_access_key: str,
450450
client_secret_key: str,
451451
mock_web_services_api: MockVuforiaWebServicesAPI,
452-
query_recognizes_deletion_seconds: int,
452+
query_recognizes_deletion_seconds: Union[int, float],
453453
) -> None:
454454
"""
455455
Args:

tests/mock_vws/test_query.py

Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
import calendar
99
import io
1010
import time
11-
from typing import Any, Dict, Union
11+
from typing import Dict, Union
1212
from urllib.parse import urljoin
1313

1414
import pytest
1515
import requests
16-
from requests import Response, codes
16+
from requests import codes
1717
from requests_mock import POST
1818
from urllib3.filepost import encode_multipart_formdata
1919

@@ -22,6 +22,7 @@
2222
add_target_to_vws,
2323
delete_target,
2424
get_vws_target,
25+
query,
2526
update_target,
2627
wait_for_target_processed,
2728
)
@@ -38,55 +39,6 @@
3839
VWQ_HOST = 'https://cloudreco.vuforia.com'
3940

4041

41-
def query(
42-
vuforia_database_keys: VuforiaDatabaseKeys,
43-
body: Dict[str, Any],
44-
) -> Response:
45-
"""
46-
Make a request to the endpoint to make an image recognition query.
47-
48-
Args:
49-
vuforia_database_keys: The credentials to use to connect to
50-
Vuforia.
51-
body: The request body to send in ``multipart/formdata`` format.
52-
53-
Returns:
54-
The response returned by the API.
55-
"""
56-
date = rfc_1123_date()
57-
request_path = '/v1/query'
58-
content, content_type_header = encode_multipart_formdata(body)
59-
method = POST
60-
61-
access_key = vuforia_database_keys.client_access_key
62-
secret_key = vuforia_database_keys.client_secret_key
63-
authorization_string = authorization_header(
64-
access_key=access_key,
65-
secret_key=secret_key,
66-
method=method,
67-
content=content,
68-
# Note that this is not the actual Content-Type header value sent.
69-
content_type='multipart/form-data',
70-
date=date,
71-
request_path=request_path,
72-
)
73-
74-
headers = {
75-
'Authorization': authorization_string,
76-
'Date': date,
77-
'Content-Type': content_type_header,
78-
}
79-
80-
response = requests.request(
81-
method=method,
82-
url=urljoin(base=VWQ_HOST, url=request_path),
83-
headers=headers,
84-
data=content,
85-
)
86-
87-
return response
88-
89-
9042
@pytest.mark.usefixtures('verify_mock_vuforia')
9143
class TestContentType:
9244
"""

tests/mock_vws/test_usage.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io
88
import socket
99
import string
10+
import time
1011
import uuid
1112

1213
import pytest
@@ -22,9 +23,13 @@
2223
VuforiaDatabaseKeys,
2324
add_target_to_vws,
2425
database_summary,
26+
delete_target,
2527
get_vws_target,
28+
query,
2629
rfc_1123_date,
30+
wait_for_target_processed,
2731
)
32+
from tests.mock_vws.utils.assertions import assert_query_success
2833

2934

3035
def request_unmocked_address() -> None:
@@ -420,3 +425,119 @@ def test_custom_base_vwq_url(self) -> None:
420425

421426
requests.post(url='https://vuforia.vwq.example.com/v1/query')
422427
requests.get('https://vws.vuforia.com/summary')
428+
429+
430+
class TestCustomQueryRecognizesDeletionSeconds:
431+
"""
432+
Tests for setting the amount of time after a target has been deleted
433+
until it is not recognized by the query endpoint.
434+
"""
435+
436+
def _recognize_deletion_seconds(
437+
self,
438+
high_quality_image: io.BytesIO,
439+
vuforia_database_keys: VuforiaDatabaseKeys,
440+
) -> float:
441+
"""
442+
XXX
443+
"""
444+
image_content = high_quality_image.getvalue()
445+
image_data_encoded = base64.b64encode(image_content).decode('ascii')
446+
add_target_data = {
447+
'name': 'example_name',
448+
'width': 1,
449+
'image': image_data_encoded,
450+
}
451+
response = add_target_to_vws(
452+
vuforia_database_keys=vuforia_database_keys,
453+
data=add_target_data,
454+
)
455+
456+
target_id = response.json()['target_id']
457+
458+
wait_for_target_processed(
459+
target_id=target_id,
460+
vuforia_database_keys=vuforia_database_keys,
461+
)
462+
463+
response = delete_target(
464+
vuforia_database_keys=vuforia_database_keys,
465+
target_id=target_id,
466+
)
467+
468+
time_after_delete = datetime.datetime.now()
469+
470+
body = {'image': ('image.jpeg', image_content, 'image/jpeg')}
471+
472+
while True:
473+
response = query(
474+
vuforia_database_keys=vuforia_database_keys,
475+
body=body,
476+
)
477+
478+
try:
479+
assert_query_success(response=response)
480+
except AssertionError:
481+
# The response text for a 500 response is not consistent.
482+
# Therefore we only test for consistent features.
483+
assert 'Error 500 Server Error' in response.text
484+
assert 'HTTP ERROR 500' in response.text
485+
assert 'Problem accessing /v1/query' in response.text
486+
time.sleep(0.05)
487+
continue
488+
489+
assert response.json()['results'] == []
490+
time_difference = datetime.datetime.now() - time_after_delete
491+
return time_difference.total_seconds()
492+
493+
def test_default(
494+
self,
495+
high_quality_image: io.BytesIO,
496+
vuforia_database_keys: VuforiaDatabaseKeys,
497+
) -> None:
498+
"""
499+
By default it takes three seconds for the Query API on the mock to
500+
recognize that a target has been deleted.
501+
502+
The real Query API takes between seven and thirty seconds.
503+
See ``test_query`` for more information.
504+
"""
505+
with MockVWS(
506+
client_access_key=vuforia_database_keys.client_access_key.decode(),
507+
client_secret_key=vuforia_database_keys.client_secret_key.decode(),
508+
server_access_key=vuforia_database_keys.server_access_key.decode(),
509+
server_secret_key=vuforia_database_keys.server_secret_key.decode(),
510+
):
511+
recognize_deletion_seconds = self._recognize_deletion_seconds(
512+
high_quality_image=high_quality_image,
513+
vuforia_database_keys=vuforia_database_keys,
514+
)
515+
516+
expected = 3
517+
assert abs(expected - recognize_deletion_seconds) < 0.2
518+
519+
def test_custom(
520+
self,
521+
high_quality_image: io.BytesIO,
522+
vuforia_database_keys: VuforiaDatabaseKeys,
523+
) -> None:
524+
"""
525+
It is possible to use set a custom amount of time that it takes for the
526+
Query API on the mock to recognize that a target has been deleted.
527+
"""
528+
# We choose a low time for a quick test.
529+
query_recognizes_deletion = 0.1
530+
with MockVWS(
531+
client_access_key=vuforia_database_keys.client_access_key.decode(),
532+
client_secret_key=vuforia_database_keys.client_secret_key.decode(),
533+
server_access_key=vuforia_database_keys.server_access_key.decode(),
534+
server_secret_key=vuforia_database_keys.server_secret_key.decode(),
535+
query_recognizes_deletion_seconds=query_recognizes_deletion,
536+
):
537+
recognize_deletion_seconds = self._recognize_deletion_seconds(
538+
high_quality_image=high_quality_image,
539+
vuforia_database_keys=vuforia_database_keys,
540+
)
541+
542+
expected = query_recognizes_deletion
543+
assert abs(expected - recognize_deletion_seconds) < 0.2

tests/mock_vws/utils/__init__.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import timeout_decorator
1212
from requests import Response
1313
from requests_mock import DELETE, GET, POST, PUT
14+
from urllib3.filepost import encode_multipart_formdata
1415

1516
from mock_vws._constants import ResultCodes, TargetStatuses
1617
from tests.mock_vws.utils.authorization import (
@@ -366,3 +367,53 @@ def target_summary(
366367
)
367368

368369
return response
370+
371+
372+
def query(
373+
vuforia_database_keys: VuforiaDatabaseKeys,
374+
body: Dict[str, Any],
375+
) -> Response:
376+
"""
377+
Make a request to the endpoint to make an image recognition query.
378+
379+
Args:
380+
vuforia_database_keys: The credentials to use to connect to
381+
Vuforia.
382+
body: The request body to send in ``multipart/formdata`` format.
383+
384+
Returns:
385+
The response returned by the API.
386+
"""
387+
date = rfc_1123_date()
388+
request_path = '/v1/query'
389+
content, content_type_header = encode_multipart_formdata(body)
390+
method = POST
391+
392+
access_key = vuforia_database_keys.client_access_key
393+
secret_key = vuforia_database_keys.client_secret_key
394+
authorization_string = authorization_header(
395+
access_key=access_key,
396+
secret_key=secret_key,
397+
method=method,
398+
content=content,
399+
# Note that this is not the actual Content-Type header value sent.
400+
content_type='multipart/form-data',
401+
date=date,
402+
request_path=request_path,
403+
)
404+
405+
headers = {
406+
'Authorization': authorization_string,
407+
'Date': date,
408+
'Content-Type': content_type_header,
409+
}
410+
411+
vwq_host = 'https://cloudreco.vuforia.com'
412+
response = requests.request(
413+
method=method,
414+
url=urljoin(base=vwq_host, url=request_path),
415+
headers=headers,
416+
data=content,
417+
)
418+
419+
return response

0 commit comments

Comments
 (0)