def _delete_all_targets(database_keys: VuforiaDatabase) -> None: """ Delete all targets. Args: database_keys: The credentials to the Vuforia target database to delete all targets in. """ vws_client = VWS( server_access_key=database_keys.server_access_key, server_secret_key=database_keys.server_secret_key, ) targets = vws_client.list_targets() for target in targets: vws_client.wait_for_target_processed(target_id=target) # Even deleted targets can be matched by a query for a few seconds so # we change the target to inactive before deleting it. try: vws_client.update_target(target_id=target, active_flag=False) except TargetStatusNotSuccess: pass vws_client.wait_for_target_processed(target_id=target) vws_client.delete_target(target_id=target)
def test_processing_images( self, image_file_success_state_low_rating: io.BytesIO, ) -> None: """ The number of images in the processing state is returned. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) with MockVWS() as mock: mock.add_database(database=database) vws_client.add_target( name=uuid.uuid4().hex, width=1, image=image_file_success_state_low_rating, active_flag=True, application_metadata=None, ) _wait_for_image_numbers( vws_client=vws_client, active_images=0, inactive_images=0, failed_images=0, processing_images=1, )
def wait_for_target_processed( server_access_key: str, server_secret_key: str, target_id: str, seconds_between_requests: float, base_vws_url: str, timeout_seconds: float, ) -> None: """ Wait for a target to be "processed". This is done by polling the VWS API. """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) try: vws_client.wait_for_target_processed( target_id=target_id, seconds_between_requests=seconds_between_requests, timeout_seconds=timeout_seconds, ) except TargetProcessingTimeout: click.echo(f'Timeout of {timeout_seconds} seconds reached.', err=True) sys.exit(1)
def test_custom_base_url(self, high_quality_image: io.BytesIO) -> None: """ It is possible to use query a target to a database under a custom VWQ URL. """ base_vwq_url = 'http://example.com' with MockVWS(base_vwq_url=base_vwq_url) as mock: database = VuforiaDatabase() mock.add_database(database=database) vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) target_id = vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) vws_client.wait_for_target_processed(target_id=target_id) cloud_reco_client = CloudRecoService( client_access_key=database.client_access_key, client_secret_key=database.client_secret_key, base_vwq_url=base_vwq_url, ) matches = cloud_reco_client.query(image=high_quality_image) assert len(matches) == 1 match = matches[0] assert match.target_id == target_id
def processing_time_seconds( vuforia_database: VuforiaDatabase, image: io.BytesIO, ) -> float: """ Return the time taken to process a target in the database. """ vws_client = VWS( server_access_key=vuforia_database.server_access_key, server_secret_key=vuforia_database.server_secret_key, ) target_id = vws_client.add_target( name='example', width=1, image=image, active_flag=True, application_metadata=None, ) start_time = datetime.now() while (vws_client.get_target_record( target_id=target_id).status == TargetStatuses.PROCESSING): pass return (datetime.now() - start_time).total_seconds()
def test_authentication_failure(high_quality_image: io.BytesIO) -> None: """ An ``AuthenticationFailure`` exception is raised when the server access key exists but the server secret key is incorrect, or when a client key is incorrect. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key='a', ) with MockVWS() as mock: mock.add_database(database=database) with pytest.raises(AuthenticationFailure) as exc: vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) assert exc.value.response.status_code == HTTPStatus.UNAUTHORIZED
def test_default(self, image_file_failed_state: io.BytesIO) -> None: """ By default, targets in the mock take 0.5 seconds to be processed. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) with MockVWS() as mock: mock.add_database(database=database) target_id = vws_client.add_target( name='example', width=1, image=image_file_failed_state, active_flag=True, application_metadata=None, ) start_time = datetime.now() while True: target_details = vws_client.get_target_record( target_id=target_id, ) status = target_details.status if status != TargetStatuses.PROCESSING: elapsed_time = datetime.now() - start_time # There is a race condition in this test - if it starts to # fail, maybe extend the acceptable range. assert elapsed_time < timedelta(seconds=0.55) assert elapsed_time > timedelta(seconds=0.49) return
def test_custom(self, image_file_failed_state: io.BytesIO) -> None: """ It is possible to set a custom processing time. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) with MockVWS(processing_time_seconds=0.1) as mock: mock.add_database(database=database) target_id = vws_client.add_target( name='example', width=1, image=image_file_failed_state, active_flag=True, application_metadata=None, ) start_time = datetime.now() while True: target_details = vws_client.get_target_record( target_id=target_id, ) status = target_details.status if status != TargetStatuses.PROCESSING: elapsed_time = datetime.now() - start_time assert elapsed_time < timedelta(seconds=0.15) assert elapsed_time > timedelta(seconds=0.09) return
def test_to_dict_deleted(self, high_quality_image: io.BytesIO) -> None: """ It is possible to dump a deleted target to a dictionary and load it back. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) with MockVWS() as mock: mock.add_database(database=database) target_id = vws_client.add_target( name='example', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) vws_client.wait_for_target_processed(target_id=target_id) vws_client.delete_target(target_id=target_id) (target, ) = database.targets target_dict = target.to_dict() # The dictionary is JSON dump-able assert json.dumps(target_dict) new_target = Target.from_dict(target_dict=target_dict) assert new_target.delete_date == target.delete_date
def test_to_dict(self, high_quality_image: io.BytesIO) -> None: """ It is possible to dump a database to a dictionary and load it back. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) # We test a database with a target added. with MockVWS() as mock: mock.add_database(database=database) vws_client.add_target( name='example', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) database_dict = database.to_dict() # The dictionary is JSON dump-able assert json.dumps(database_dict) new_database = VuforiaDatabase.from_dict(database_dict=database_dict) assert new_database == database
def test_give_no_details(self, high_quality_image: io.BytesIO) -> None: """ It is possible to create a database without giving any data. """ databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + '/databases' response = requests.post(url=databases_url, json={}) assert response.status_code == HTTPStatus.CREATED data = response.json() assert data['targets'] == [] assert data['state_name'] == 'WORKING' assert 'database_name' in data.keys() vws_client = VWS( server_access_key=data['server_access_key'], server_secret_key=data['server_secret_key'], ) cloud_reco_client = CloudRecoService( client_access_key=data['client_access_key'], client_secret_key=data['client_secret_key'], ) assert not vws_client.list_targets() assert not cloud_reco_client.query(image=high_quality_image)
def vws_client(mock_database: VuforiaDatabase) -> Iterator[VWS]: """ Yield a VWS client which connects to a mock database. """ yield VWS( server_access_key=mock_database.server_access_key, server_secret_key=mock_database.server_secret_key, )
def fixture_inactive_vws_client(inactive_database: VuforiaDatabase) -> VWS: """ A client for an inactive VWS database. """ return VWS( server_access_key=inactive_database.server_access_key, server_secret_key=inactive_database.server_secret_key, )
def test_custom_seconds_between_requests( self, high_quality_image: io.BytesIO, ) -> None: """ It is possible to customize the time waited between polling requests. """ runner = CliRunner() with MockVWS(processing_time_seconds=0.5) as mock: mock_database = VuforiaDatabase() mock.add_database(database=mock_database) vws_client = VWS( server_access_key=mock_database.server_access_key, server_secret_key=mock_database.server_secret_key, ) target_id = vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) commands = [ 'wait-for-target-processed', '--target-id', target_id, '--seconds-between-requests', '0.3', '--server-access-key', mock_database.server_access_key, '--server-secret-key', mock_database.server_secret_key, ] result = runner.invoke(vws_group, commands, catch_exceptions=False) assert result.exit_code == 0 assert result.stdout == '' report = vws_client.get_database_summary_report() expected_requests = ( # Add target request 1 + # Database summary request 1 + # Initial request 1 + # Request after 0.3 seconds - not processed # This assumes that there is less than 0.2 seconds taken # between the start of the target processing and the start of # waiting for the target to be processed. 1 + # Request after 0.6 seconds - processed 1) # At the time of writing there is a bug which prevents request # usage from being tracked so we cannot track this. expected_requests = 0 assert report.request_usage == expected_requests
def test_custom_timeout( self, high_quality_image: io.BytesIO, ) -> None: """ It is possible to set a maximum timeout. """ runner = CliRunner(mix_stderr=False) with MockVWS(processing_time_seconds=0.5) as mock: mock_database = VuforiaDatabase() mock.add_database(database=mock_database) vws_client = VWS( server_access_key=mock_database.server_access_key, server_secret_key=mock_database.server_secret_key, ) target_id = vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) report = vws_client.get_target_summary_report(target_id=target_id) assert report.status == TargetStatuses.PROCESSING commands = [ 'wait-for-target-processed', '--target-id', target_id, '--timeout-seconds', '0.1', '--server-access-key', mock_database.server_access_key, '--server-secret-key', mock_database.server_secret_key, ] result = runner.invoke(vws_group, commands, catch_exceptions=False) assert result.exit_code != 0 assert result.stderr == 'Timeout of 0.1 seconds reached.\n' commands = [ 'wait-for-target-processed', '--target-id', target_id, '--timeout-seconds', '0.5', '--server-access-key', mock_database.server_access_key, '--server-secret-key', mock_database.server_secret_key, ] result = runner.invoke(vws_group, commands, catch_exceptions=False) assert result.exit_code == 0 report = vws_client.get_target_summary_report(target_id=target_id) assert report.status != TargetStatuses.PROCESSING
def test_custom_seconds_between_requests( self, high_quality_image: io.BytesIO, ) -> None: """ It is possible to customize the time waited between polling requests. """ with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) target_id = vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) vws_client.wait_for_target_processed( target_id=target_id, seconds_between_requests=0.3, ) report = vws_client.get_database_summary_report() expected_requests = ( # Add target request 1 + # Database summary request 1 + # Initial request 1 + # Request after 0.3 seconds - not processed # This assumes that there is less than 0.2 seconds taken # between the start of the target processing and the start of # waiting for the target to be processed. 1 + # Request after 0.6 seconds - processed 1 ) # At the time of writing there is a bug which prevents request # usage from being tracked so we cannot track this. expected_requests = 0 assert report.request_usage == expected_requests
def test_bad_secret_key_services( self, vuforia_database: VuforiaDatabase, ) -> None: """ If the server secret key given is incorrect, an ``AuthenticationFailure`` response is returned. """ vws_client = VWS( server_access_key=vuforia_database.server_access_key, server_secret_key='example', ) with pytest.raises(AuthenticationFailure): vws_client.get_target_record(target_id=uuid.uuid4().hex)
def test_bad_access_key_services( self, vuforia_database: VuforiaDatabase, ) -> None: """ If the server access key given does not match any database, a ``Fail`` response is returned. """ vws_client = VWS( server_access_key='example', server_secret_key=vuforia_database.server_secret_key, ) with pytest.raises(Fail) as exc: vws_client.get_target_record(target_id=uuid.uuid4().hex) assert exc.value.response.status_code == HTTPStatus.BAD_REQUEST
def test_base_vwq_url(high_quality_image: io.BytesIO, tmp_path: Path) -> None: """ It is possible to use query a target to a database under a custom VWQ URL. """ runner = CliRunner(mix_stderr=False) base_vwq_url = 'http://example.com' new_file = tmp_path / uuid.uuid4().hex image_data = high_quality_image.getvalue() new_file.write_bytes(data=image_data) with MockVWS(base_vwq_url=base_vwq_url) as mock: mock_database = VuforiaDatabase() mock.add_database(database=mock_database) vws_client = VWS( server_access_key=mock_database.server_access_key, server_secret_key=mock_database.server_secret_key, ) target_id = vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) vws_client.wait_for_target_processed(target_id=target_id) commands = [ str(new_file), '--client-access-key', mock_database.client_access_key, '--client-secret-key', mock_database.client_secret_key, '--base-vwq-url', base_vwq_url, ] result = runner.invoke( vuforia_cloud_reco, commands, catch_exceptions=False, ) assert result.exit_code == 0 [match] = yaml.load(result.stdout, Loader=yaml.FullLoader) assert match['target_id'] == target_id
def update_target( server_access_key: str, server_secret_key: str, target_id: str, image_file_path: Path | None, base_vws_url: str, name: str | None = None, application_metadata: str | None = None, active_flag_choice: ActiveFlagChoice | None = None, width: float | None = None, ) -> None: """ Update a target. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API#How-To-Update-a-Target """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) if image_file_path is None: image = None else: image_bytes = image_file_path.read_bytes() image = io.BytesIO(image_bytes) active_flag = { ActiveFlagChoice.TRUE: True, ActiveFlagChoice.FALSE: False, None: None, }[active_flag_choice] vws_client.update_target( name=name, target_id=target_id, image=image, application_metadata=application_metadata, active_flag=active_flag, width=width, )
def list_targets( server_access_key: str, server_secret_key: str, base_vws_url: str, ) -> None: """ List targets. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Get-a-Target-List-for-a-Cloud-Database. """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) targets = vws_client.list_targets() yaml_list = yaml.dump(targets) click.echo(yaml_list)
def get_database_summary_report( server_access_key: str, server_secret_key: str, base_vws_url: str, ) -> None: """ Get a database summary report. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Get-a-Database-Summary-Report. """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) report = vws_client.get_database_summary_report() yaml_report = yaml.dump(dataclasses.asdict(report)) click.echo(yaml_report)
def test_fail(high_quality_image: io.BytesIO) -> None: """ A ``Fail`` exception is raised when the server access key does not exist. """ with MockVWS(): vws_client = VWS( server_access_key='a', server_secret_key='a', ) with pytest.raises(Fail) as exc: vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) assert exc.value.response.status_code == HTTPStatus.BAD_REQUEST
def delete_target( server_access_key: str, server_secret_key: str, target_id: str, base_vws_url: str, ) -> None: """ Delete a target. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Delete-a-Target. """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) vws_client.delete_target(target_id=target_id)
def _add_and_delete_target( image: io.BytesIO, vuforia_database: VuforiaDatabase, ) -> None: """ Add and delete a target with the given image. """ vws_client = VWS( server_access_key=vuforia_database.server_access_key, server_secret_key=vuforia_database.server_secret_key, ) target_id = vws_client.add_target( name='example_name', width=1, image=image, active_flag=True, application_metadata=None, ) vws_client.wait_for_target_processed(target_id=target_id) vws_client.delete_target(target_id=target_id)
def add_target( server_access_key: str, server_secret_key: str, name: str, width: float, image_file_path: Path, active_flag_choice: ActiveFlagChoice, base_vws_url: str, application_metadata: str | None = None, ) -> None: """ Add a target. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API#How-To-Add-a-Target """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) image_bytes = image_file_path.read_bytes() image = io.BytesIO(image_bytes) active_flag = { ActiveFlagChoice.TRUE: True, ActiveFlagChoice.FALSE: False, }[active_flag_choice] target_id = vws_client.add_target( name=name, width=width, image=image, active_flag=active_flag, application_metadata=application_metadata, ) click.echo(target_id)
def get_target_record( server_access_key: str, server_secret_key: str, target_id: str, base_vws_url: str, ) -> None: """ Get a target record. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#How-To-Retrieve-a-Target-Record. """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) record = vws_client.get_target_record(target_id=target_id).target_record yaml_record = yaml.dump(dataclasses.asdict(record)) click.echo(yaml_record)
def get_duplicate_targets( server_access_key: str, server_secret_key: str, target_id: str, base_vws_url: str, ) -> None: """ Get a list of potential duplicate targets. \b See https://library.vuforia.com/articles/Solution/How-To-Use-the-Vuforia-Web-Services-API.html#how-to-check-for-similar-targets. """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, base_vws_url=base_vws_url, ) record = vws_client.get_duplicate_targets(target_id=target_id) yaml_record = yaml.dump(record) click.echo(yaml_record)
def test_custom_base_url(self, high_quality_image: io.BytesIO) -> None: """ It is possible to use add a target to a database under a custom VWS URL. """ base_vws_url = 'http://example.com' with MockVWS(base_vws_url=base_vws_url) as mock: database = VuforiaDatabase() mock.add_database(database=database) vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, base_vws_url=base_vws_url, ) vws_client.add_target( name='x', width=1, image=high_quality_image, active_flag=True, application_metadata=None, )
def test_repr(self, high_quality_image: io.BytesIO) -> None: """ Test for the representation of a ``Target``. """ database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, server_secret_key=database.server_secret_key, ) with MockVWS() as mock: mock.add_database(database=database) target_id = vws_client.add_target( name='example', width=1, image=high_quality_image, active_flag=True, application_metadata=None, ) (target,) = database.targets assert repr(target) == f'<Target: {target_id}>'