def test_not_image( self, vuforia_database: VuforiaDatabase, target_id: str, vws_client: VWS, ) -> None: """ If the given image is not an image file then a `BadImage` result is returned. """ not_image_data = b'not_image_data' image_data_encoded = base64.b64encode(not_image_data).decode('ascii') vws_client.wait_for_target_processed(target_id=target_id) response = update_target( vuforia_database=vuforia_database, data={'image': image_data_encoded}, target_id=target_id, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.BAD_IMAGE, )
def test_invalid( self, image_file_failed_state: io.BytesIO, vuforia_database: VuforiaDatabase, ) -> None: """ Values which are not Boolean values or NULL are not valid active flags. """ active_flag = 'string' image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') content_type = 'application/json' data = { 'name': 'example', 'width': 1, 'image': image_data_encoded, 'active_flag': active_flag, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, content_type=content_type, ) assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_not_base64_encoded_processable( self, vuforia_database: VuforiaDatabase, target_id: str, not_base64_encoded_processable: str, vws_client: VWS, ) -> None: """ Some strings which are not valid base64 encoded strings are allowed as an image without getting a "Fail" response. This is because Vuforia treats them as valid base64, but then not a valid image. """ vws_client.wait_for_target_processed(target_id=target_id) response = update_target( vuforia_database=vuforia_database, data={'image': not_base64_encoded_processable}, target_id=target_id, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.BAD_IMAGE, )
def test_not_base64_encoded_not_processable( self, vuforia_database: VuforiaDatabase, vws_client: VWS, target_id: str, not_base64_encoded_not_processable: str, ) -> None: """ Some strings which are not valid base64 encoded strings are not processable by Vuforia, and then when given as an image Vuforia returns a "Fail" response. """ vws_client.wait_for_target_processed(target_id=target_id) response = update_target( vuforia_database=vuforia_database, data={'image': not_base64_encoded_not_processable}, target_id=target_id, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.FAIL, )
def test_name_invalid( self, name: str, target_id: str, vuforia_database: VuforiaDatabase, vws_client: VWS, status_code: int, result_code: ResultCodes, ) -> None: """ A target's name must be a string of length 0 < N < 65. """ vws_client.wait_for_target_processed(target_id=target_id) response = update_target( vuforia_database=vuforia_database, data={'name': name}, target_id=target_id, ) assert_vws_failure( response=response, status_code=status_code, result_code=result_code, )
def test_same_name_given( self, image_file_success_state_low_rating: io.BytesIO, vuforia_database: VuforiaDatabase, vws_client: VWS, ) -> None: """ Updating a target with its own name does not give an error. """ name = 'example' target_id = vws_client.add_target( name=name, width=1, image=image_file_success_state_low_rating, active_flag=True, application_metadata=None, ) vws_client.wait_for_target_processed(target_id=target_id) response = update_target( vuforia_database=vuforia_database, data={'name': name}, target_id=target_id, ) assert_vws_failure( response=response, status_code=HTTPStatus.OK, result_code=ResultCodes.SUCCESS, ) target_details = vws_client.get_target_record(target_id=target_id) assert target_details.target_record.name == name
def test_width_invalid( self, vuforia_database: VuforiaDatabase, vws_client: VWS, width: Any, target_id: str, ) -> None: """ The width must be a number greater than zero. """ vws_client.wait_for_target_processed(target_id=target_id) target_details = vws_client.get_target_record(target_id=target_id) original_width = target_details.target_record.width response = update_target( vuforia_database=vuforia_database, data={'width': width}, target_id=target_id, ) assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, ) target_details = vws_client.get_target_record(target_id=target_id) assert target_details.target_record.width == original_width
def test_metadata_too_large( self, vuforia_database: VuforiaDatabase, vws_client: VWS, target_id: str, ) -> None: """ A base64 encoded string of greater than 1024 * 1024 bytes is too large for application metadata. """ metadata = b'a' * (self._MAX_METADATA_BYTES + 1) metadata_encoded = base64.b64encode(metadata).decode('ascii') vws_client.wait_for_target_processed(target_id=target_id) response = update_target( vuforia_database=vuforia_database, data={'application_metadata': metadata_encoded}, target_id=target_id, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.METADATA_TOO_LARGE, )
def test_empty_content_type( self, vuforia_database: VuforiaDatabase, vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: """ An ``UNAUTHORIZED`` response is given if an empty ``Content-Type`` header is given. """ target_id = vws_client.add_target( name='example', width=1, image=image_file_failed_state, active_flag=True, application_metadata=None, ) response = update_target( vuforia_database=vuforia_database, data={'name': 'Adam'}, target_id=target_id, content_type='', ) assert_vws_failure( response=response, status_code=HTTPStatus.UNAUTHORIZED, result_code=ResultCodes.AUTHENTICATION_FAILURE, )
def test_too_small(self, endpoint: Endpoint) -> None: """ An ``UNAUTHORIZED`` response is given if the given content length is too small. """ endpoint_headers = dict(endpoint.prepared_request.headers) if not endpoint_headers.get('Content-Type'): return content_length = str(int(endpoint_headers['Content-Length']) - 1) headers = {**endpoint_headers, 'Content-Length': content_length} endpoint.prepared_request.headers = CaseInsensitiveDict(data=headers) session = requests.Session() response = session.send( # type: ignore request=endpoint.prepared_request, ) url = str(endpoint.prepared_request.url) netloc = urlparse(url).netloc if netloc == 'cloudreco.vuforia.com': assert_vwq_failure( response=response, status_code=HTTPStatus.UNAUTHORIZED, content_type='application/json', ) return assert_vws_failure( response=response, status_code=HTTPStatus.UNAUTHORIZED, result_code=ResultCodes.AUTHENTICATION_FAILURE, )
def test_not_real_id( self, vws_client: VWS, endpoint: Endpoint, target_id: str, ) -> None: """ A `NOT_FOUND` error is returned when an endpoint is given a target ID of a target which does not exist. """ if not endpoint.prepared_request.path_url.endswith(target_id): return vws_client.wait_for_target_processed(target_id=target_id) vws_client.delete_target(target_id=target_id) session = requests.Session() response = session.send( # type: ignore request=endpoint.prepared_request, ) assert_vws_failure( response=response, status_code=HTTPStatus.NOT_FOUND, result_code=ResultCodes.UNKNOWN_TARGET, )
def test_invalid_extra_data( self, vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, ) -> None: """ A `BAD_REQUEST` response is returned when unexpected data is given. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, 'extra_thing': 1, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_content_types( self, vuforia_database: VuforiaDatabase, vws_client: VWS, image_file_failed_state: io.BytesIO, content_type: str, ) -> None: """ The ``Content-Type`` header does not change the response as long as it is not empty. """ target_id = vws_client.add_target( name='example', width=1, image=image_file_failed_state, active_flag=True, application_metadata=None, ) response = update_target( vuforia_database=vuforia_database, data={'name': 'Adam'}, target_id=target_id, content_type=content_type, ) # Code is FORBIDDEN because the target is processing. assert_vws_failure( response=response, status_code=HTTPStatus.FORBIDDEN, result_code=ResultCodes.TARGET_STATUS_NOT_SUCCESS, )
def test_not_base64_encoded_not_processable( self, vuforia_database: VuforiaDatabase, high_quality_image: io.BytesIO, not_base64_encoded_not_processable: str, ) -> None: """ Some strings which are not valid base64 encoded strings are not allowed as application metadata. """ image_content = high_quality_image.getvalue() image_data_encoded = base64.b64encode(image_content).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, 'application_metadata': not_base64_encoded_not_processable, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.FAIL, )
def test_not_image( self, vuforia_database: VuforiaDatabase, ) -> None: """ If the given image is not an image file then a `BadImage` result is returned. """ not_image_data = b'not_image_data' image_data_encoded = base64.b64encode(not_image_data).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.BAD_IMAGE, )
def test_not_base64_encoded_processable( self, vuforia_database: VuforiaDatabase, not_base64_encoded_processable: str, ) -> None: """ Some strings which are not valid base64 encoded strings are allowed as an image without getting a "Fail" response. This is because Vuforia treats them as valid base64, but then not a valid image. """ data = { 'name': 'example_name', 'width': 1, 'image': not_base64_encoded_processable, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.BAD_IMAGE, )
def test_not_base64_encoded_not_processable( self, vuforia_database: VuforiaDatabase, not_base64_encoded_not_processable: str, ) -> None: """ Some strings which are not valid base64 encoded strings are not processable by Vuforia, and then when given as an image Vuforia returns a "Fail" response. """ data = { 'name': 'example_name', 'width': 1, 'image': not_base64_encoded_not_processable, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.FAIL, )
def test_existing_target_name( self, image_file_failed_state: io.BytesIO, vuforia_database: VuforiaDatabase, ) -> None: """ Only one target can have a given name. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, } add_target_to_vws( vuforia_database=vuforia_database, data=data, ) response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.FORBIDDEN, result_code=ResultCodes.TARGET_NAME_EXIST, )
def test_bad_image_format_or_color_space( self, bad_image_file: io.BytesIO, vuforia_database: VuforiaDatabase, ) -> None: """ An `UNPROCESSABLE_ENTITY` response is returned if an image which is not a JPEG or PNG file is given, or if the given image is not in the greyscale or RGB color space. """ image_data = bad_image_file.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.BAD_IMAGE, )
def test_missing_data( self, vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, data_to_remove: str, ) -> None: """ `name`, `width` and `image` are all required. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, } data.pop(data_to_remove) response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_width_invalid( self, vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, width: Any, ) -> None: """ The width must be a number greater than zero. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example_name', 'width': width, 'image': image_data_encoded, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_empty_content_type( self, vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, ) -> None: """ An ``UNAUTHORIZED`` response is given if an empty ``Content-Type`` header is given. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example', 'width': 1, 'image': image_data_encoded, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, content_type='', ) assert_vws_failure( response=response, status_code=HTTPStatus.UNAUTHORIZED, result_code=ResultCodes.AUTHENTICATION_FAILURE, )
def test_inactive_project( self, inactive_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, ) -> None: """ If the project is inactive, a FORBIDDEN response is returned. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example', 'width': 1, 'image': image_data_encoded, } response = add_target_to_vws( vuforia_database=inactive_database, data=data, content_type='application/json', ) assert_vws_failure( response=response, status_code=HTTPStatus.FORBIDDEN, result_code=ResultCodes.PROJECT_INACTIVE, )
def test_metadata_too_large( self, vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, ) -> None: """ A base64 encoded string of greater than 1024 * 1024 bytes is too large for application metadata. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') metadata = b'a' * (self._MAX_METADATA_BYTES + 1) metadata_encoded = base64.b64encode(metadata).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, 'application_metadata': metadata_encoded, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.UNPROCESSABLE_ENTITY, result_code=ResultCodes.METADATA_TOO_LARGE, )
def test_invalid_type( self, vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, ) -> None: """ Values which are not a string or NULL are not valid application metadata. """ image_data = image_file_failed_state.read() image_data_encoded = base64.b64encode(image_data).decode('ascii') data = { 'name': 'example_name', 'width': 1, 'image': image_data_encoded, 'application_metadata': 1, } response = add_target_to_vws( vuforia_database=vuforia_database, data=data, ) assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_incorrect_date_format( self, endpoint: Endpoint, ) -> None: """ A `BAD_REQUEST` response is returned when the date given in the date header is not in the expected format (RFC 1123) to VWS API. An `UNAUTHORIZED` response is returned to the VWQ API. """ gmt = ZoneInfo('GMT') with freeze_time(datetime.now(tz=gmt)): now = datetime.now() date_incorrect_format = now.strftime('%a %b %d %H:%M:%S') endpoint_headers = dict(endpoint.prepared_request.headers) content = endpoint.prepared_request.body or b'' assert isinstance(content, bytes) authorization_string = authorization_header( access_key=endpoint.access_key, secret_key=endpoint.secret_key, method=str(endpoint.prepared_request.method), content=content, content_type=endpoint.auth_header_content_type, date=date_incorrect_format, request_path=endpoint.prepared_request.path_url, ) headers = { **endpoint_headers, 'Authorization': authorization_string, 'Date': date_incorrect_format, } endpoint.prepared_request.headers = CaseInsensitiveDict(data=headers) session = requests.Session() response = session.send(request=endpoint.prepared_request) url = str(endpoint.prepared_request.url) netloc = urlparse(url).netloc if netloc == 'cloudreco.vuforia.com': assert response.text == 'Malformed date header.' assert_vwq_failure( response=response, status_code=HTTPStatus.UNAUTHORIZED, content_type='text/plain;charset=iso-8859-1', cache_control=None, www_authenticate='VWS', connection='keep-alive', ) return assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_missing_signature( self, endpoint: Endpoint, authorization_string: str, ) -> None: """ If a signature is missing `Authorization` header is given, a ``BAD_REQUEST`` response is given. """ date = rfc_1123_date() headers: Dict[str, str] = { **endpoint.prepared_request.headers, 'Authorization': authorization_string, 'Date': date, } endpoint.prepared_request.headers = CaseInsensitiveDict(data=headers) session = requests.Session() response = session.send(request=endpoint.prepared_request) url = str(endpoint.prepared_request.url) netloc = urlparse(url).netloc if netloc == 'cloudreco.vuforia.com': assert_vwq_failure( response=response, status_code=HTTPStatus.INTERNAL_SERVER_ERROR, content_type='text/html;charset=iso-8859-1', cache_control='must-revalidate,no-cache,no-store', www_authenticate=None, connection='keep-alive', ) content_filename = 'jetty_error_array_out_of_bounds.html' content_filename_2 = 'jetty_error_array_out_of_bounds_2.html' content_filename_3 = 'jetty_error_array_out_of_bounds_3.html' content_path = Path(__file__).parent / content_filename content_path_2 = Path(__file__).parent / content_filename_2 content_path_3 = Path(__file__).parent / content_filename_3 content_text = content_path.read_text() content_2_text = content_path_2.read_text() content_3_text = content_path_3.read_text() # We make a new variable for response text so that it is printed # with ``pytest --showlocals``. response_text = response.text assert response_text in ( content_text, content_2_text, content_3_text, ) return assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_date_out_of_range( self, time_multiplier: int, endpoint: Endpoint, ) -> None: """ If the date header is more than five minutes (target API) or 65 minutes (query API) before or after the request is sent, a `FORBIDDEN` response is returned. Because there is a small delay in sending requests and Vuforia isn't consistent, some leeway is given. """ url = str(endpoint.prepared_request.url) netloc = urlparse(url).netloc skew = { 'vws.vuforia.com': _VWS_MAX_TIME_SKEW, 'cloudreco.vuforia.com': _VWQ_MAX_TIME_SKEW, }[netloc] time_difference_from_now = skew + _LEEWAY time_difference_from_now *= time_multiplier gmt = ZoneInfo('GMT') with freeze_time(datetime.now(tz=gmt) + time_difference_from_now): date = rfc_1123_date() endpoint_headers = dict(endpoint.prepared_request.headers) content = endpoint.prepared_request.body or b'' assert isinstance(content, bytes) authorization_string = authorization_header( access_key=endpoint.access_key, secret_key=endpoint.secret_key, method=str(endpoint.prepared_request.method), content=content, content_type=endpoint.auth_header_content_type, date=date, request_path=endpoint.prepared_request.path_url, ) headers = { **endpoint_headers, 'Authorization': authorization_string, 'Date': date, } endpoint.prepared_request.headers = CaseInsensitiveDict(data=headers) session = requests.Session() response = session.send( # type: ignore request=endpoint.prepared_request, ) # Even with the query endpoint, we get a JSON response. assert_vws_failure( response=response, status_code=HTTPStatus.FORBIDDEN, result_code=ResultCodes.REQUEST_TIME_TOO_SKEWED, )
def test_no_date_header( self, endpoint: Endpoint, ) -> None: """ A `BAD_REQUEST` response is returned when no `Date` header is given. """ endpoint_headers = dict(endpoint.prepared_request.headers) content = endpoint.prepared_request.body or b'' assert isinstance(content, bytes) authorization_string = authorization_header( access_key=endpoint.access_key, secret_key=endpoint.secret_key, method=str(endpoint.prepared_request.method), content=content, content_type=endpoint.auth_header_content_type, date='', request_path=endpoint.prepared_request.path_url, ) headers: Dict[str, str] = { **endpoint_headers, 'Authorization': authorization_string, } headers.pop('Date', None) endpoint.prepared_request.headers = CaseInsensitiveDict(data=headers) session = requests.Session() response = session.send(request=endpoint.prepared_request) url = str(endpoint.prepared_request.url) netloc = urlparse(url).netloc if netloc == 'cloudreco.vuforia.com': expected_content_type = 'text/plain;charset=iso-8859-1' assert response.text == 'Date header required.' assert_vwq_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, content_type=expected_content_type, cache_control=None, www_authenticate=None, connection='keep-alive', ) return assert_vws_failure( response=response, status_code=HTTPStatus.BAD_REQUEST, result_code=ResultCodes.FAIL, )
def test_inactive_project( self, inactive_vws_client: VWS, ) -> None: """ If the project is inactive, a FORBIDDEN response is returned. """ target_id = 'abc12345a' with pytest.raises(ProjectInactive) as exc: inactive_vws_client.delete_target(target_id=target_id) assert_vws_failure( response=exc.value.response, status_code=HTTPStatus.FORBIDDEN, result_code=ResultCodes.PROJECT_INACTIVE, )