Exemple #1
0
    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
Exemple #2
0
    def test_query_request(
        self,
        cloud_reco_client: CloudRecoService,
        high_quality_image: io.BytesIO,
        vws_client: VWS,
    ) -> None:
        """
        The ``*_recos`` counts seem to be delayed by a significant amount of
        time.

        We therefore test that they exist, are integers and do not change
        between quick requests.
        """
        target_id = vws_client.add_target(
            name=uuid.uuid4().hex,
            width=1,
            image=high_quality_image,
            active_flag=True,
            application_metadata=None,
        )
        vws_client.wait_for_target_processed(target_id=target_id)

        report_before = vws_client.get_database_summary_report()
        cloud_reco_client.query(image=high_quality_image)

        report_after = vws_client.get_database_summary_report()
        assert report_before.total_recos == report_after.total_recos
        assert (report_before.current_month_recos ==
                report_after.current_month_recos)
        assert (report_before.previous_month_recos ==
                report_after.previous_month_recos)
def _wait_for_deletion_processed(
    image: io.BytesIO,
    vuforia_database: VuforiaDatabase,
) -> None:
    """
    Wait until the query endpoint "recognizes" the deletion of all targets with
    an image matching the given image.

    That is, wait until querying the given image returns a result with no
    targets.
    """
    _wait_for_deletion_recognized(
        image=image,
        vuforia_database=vuforia_database,
    )

    cloud_reco_client = CloudRecoService(
        client_access_key=vuforia_database.client_access_key,
        client_secret_key=vuforia_database.client_secret_key,
    )

    while True:
        try:
            cloud_reco_client.query(image=image)
        except MatchProcessing:
            continue
        return
    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)
Exemple #5
0
    def test_update_target(
        self,
        vws_client: VWS,
        high_quality_image: io.BytesIO,
        different_high_quality_image: io.BytesIO,
        cloud_reco_client: CloudRecoService,
    ) -> None:
        """
        It is possible to update a target.
        """
        old_name = uuid.uuid4().hex
        old_width = random.uniform(a=0.01, b=50)
        target_id = vws_client.add_target(
            name=old_name,
            width=old_width,
            image=high_quality_image,
            active_flag=True,
            application_metadata=None,
        )
        vws_client.wait_for_target_processed(target_id=target_id)
        [matching_target] = cloud_reco_client.query(image=high_quality_image)
        assert matching_target.target_id == target_id
        query_target_data = matching_target.target_data
        assert query_target_data is not None
        query_metadata = query_target_data.application_metadata
        assert query_metadata is None

        new_name = uuid.uuid4().hex
        new_width = random.uniform(a=0.01, b=50)
        new_application_metadata = base64.b64encode(b'a').decode('ascii')
        vws_client.update_target(
            target_id=target_id,
            name=new_name,
            width=new_width,
            active_flag=True,
            image=different_high_quality_image,
            application_metadata=new_application_metadata,
        )

        vws_client.wait_for_target_processed(target_id=target_id)
        [
            matching_target,
        ] = cloud_reco_client.query(image=different_high_quality_image)
        assert matching_target.target_id == target_id
        query_target_data = matching_target.target_data
        assert query_target_data is not None
        query_metadata = query_target_data.application_metadata
        assert query_metadata == new_application_metadata

        vws_client.update_target(
            target_id=target_id,
            active_flag=False,
        )

        target_details = vws_client.get_target_record(target_id=target_id)
        assert target_details.target_record.name == new_name
        assert target_details.target_record.width == new_width
        assert not target_details.target_record.active_flag
Exemple #6
0
def test_image_too_large(
    cloud_reco_client: CloudRecoService,
    png_too_large: io.BytesIO,
) -> None:
    """
    A ``RequestEntityTooLarge`` exception is raised if an image which is too
    large is given.
    """
    with pytest.raises(RequestEntityTooLarge):
        cloud_reco_client.query(image=png_too_large)
def test_image_too_large(
    cloud_reco_client: CloudRecoService,
    png_too_large: io.BytesIO,
) -> None:
    """
    A ``ConnectionErrorPossiblyImageTooLarge`` exception is raised if an
    image which is too large is given.
    """
    with pytest.raises(ConnectionErrorPossiblyImageTooLarge) as exc:
        cloud_reco_client.query(image=png_too_large)

    assert isinstance(exc.value, requests.ConnectionError)
Exemple #8
0
    def test_recognition(
        self,
        vws_client: VWS,
        cloud_reco_client: CloudRecoService,
        high_quality_image: io.BytesIO,
    ) -> None:
        """
        The recognition counts stay at 0 even after recognitions.
        """
        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)

        results = cloud_reco_client.query(image=high_quality_image)
        [result] = results
        assert result.target_id == target_id

        report = vws_client.get_target_summary_report(target_id=target_id)
        assert report.status == TargetStatuses.SUCCESS
        assert report.total_recos == 0
        assert report.current_month_recos == 0
        assert report.previous_month_recos == 0
Exemple #9
0
 def test_default(
     self,
     vws_client: VWS,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     By default, target data is only returned in the top match.
     """
     target_id = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     target_id_2 = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     vws_client.wait_for_target_processed(target_id=target_id)
     vws_client.wait_for_target_processed(target_id=target_id_2)
     top_match, second_match = cloud_reco_client.query(
         image=high_quality_image,
         max_num_results=2,
     )
     assert top_match.target_data is not None
     assert second_match.target_data is None
Exemple #10
0
 def test_all(
     self,
     vws_client: VWS,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     When ``CloudRecoIncludeTargetData.ALL`` is given, target data is
     returned in all matches.
     """
     target_id = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     target_id_2 = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     vws_client.wait_for_target_processed(target_id=target_id)
     vws_client.wait_for_target_processed(target_id=target_id_2)
     top_match, second_match = cloud_reco_client.query(
         image=high_quality_image,
         max_num_results=2,
         include_target_data=CloudRecoIncludeTargetData.ALL,
     )
     assert top_match.target_data is not None
     assert second_match.target_data is not None
Exemple #11
0
 def test_default(
     self,
     vws_client: VWS,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     By default the maximum number of results is 1.
     """
     target_id = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     target_id_2 = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     vws_client.wait_for_target_processed(target_id=target_id)
     vws_client.wait_for_target_processed(target_id=target_id_2)
     matches = cloud_reco_client.query(image=high_quality_image)
     assert len(matches) == 1
Exemple #12
0
 def test_query_request(
     self,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
     vws_client: VWS,
 ) -> None:
     """
     The ``request_usage`` count does not increase with each query.
     """
     report = vws_client.get_database_summary_report()
     original_request_usage = report.request_usage
     cloud_reco_client.query(image=high_quality_image)
     report = vws_client.get_database_summary_report()
     new_request_usage = report.request_usage
     # The request usage goes up for the database summary request, not the
     # query.
     assert new_request_usage == original_request_usage
def test_authentication_failure(high_quality_image: io.BytesIO) -> None:
    """
    An ``AuthenticationFailure`` exception is raised when the client access key
    exists but the client secret key is incorrect.
    """
    database = VuforiaDatabase()
    cloud_reco_client = CloudRecoService(
        client_access_key=database.client_access_key,
        client_secret_key='a',
    )
    with MockVWS() as mock:
        mock.add_database(database=database)

        with pytest.raises(AuthenticationFailure) as exc:
            cloud_reco_client.query(image=high_quality_image)

        assert exc.value.response.status_code == HTTPStatus.UNAUTHORIZED
def test_inactive_project(high_quality_image: io.BytesIO) -> None:
    """
    An ``InactiveProject`` exception is raised when querying an inactive
    database.
    """
    database = VuforiaDatabase(state=States.PROJECT_INACTIVE)
    with MockVWS() as mock:
        mock.add_database(database=database)
        cloud_reco_client = CloudRecoService(
            client_access_key=database.client_access_key,
            client_secret_key=database.client_secret_key,
        )

        with pytest.raises(InactiveProject) as exc:
            cloud_reco_client.query(image=high_quality_image)

        assert exc.value.response.status_code == HTTPStatus.FORBIDDEN
Exemple #15
0
def cloud_reco_client(vuforia_database: VuforiaDatabase) -> CloudRecoService:
    """
    A query client for an active VWS database.
    """
    return CloudRecoService(
        client_access_key=vuforia_database.client_access_key,
        client_secret_key=vuforia_database.client_secret_key,
    )
Exemple #16
0
def test_too_many_max_results(
    cloud_reco_client: CloudRecoService,
    high_quality_image: io.BytesIO,
) -> None:
    """
    A ``MaxNumResultsOutOfRange`` error is raised if the given
    ``max_num_results`` is out of range.
    """
    with pytest.raises(MaxNumResultsOutOfRange) as exc:
        cloud_reco_client.query(
            image=high_quality_image,
            max_num_results=51,
        )

    expected_value = (
        "Integer out of range (51) in form data part 'max_result'. "
        'Accepted range is from 1 to 50 (inclusive).')
    assert str(exc.value) == exc.value.response.text == expected_value
Exemple #17
0
def cloud_reco_client(
    mock_database: VuforiaDatabase, ) -> Iterator[CloudRecoService]:
    """
    Yield a ``CloudRecoService`` client which connects to a mock database.
    """
    yield CloudRecoService(
        client_access_key=mock_database.client_access_key,
        client_secret_key=mock_database.client_secret_key,
    )
Exemple #18
0
 def test_no_matches(
     self,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     An empty list is returned if there are no matches.
     """
     result = cloud_reco_client.query(image=high_quality_image)
     assert result == []
def test_match_processing(
    vws_client: VWS,
    cloud_reco_client: CloudRecoService,
    high_quality_image: io.BytesIO,
) -> None:
    """
    A ``MatchProcessing`` exception is raised when a target in processing is
    matched.
    """
    vws_client.add_target(
        name='x',
        width=1,
        image=high_quality_image,
        active_flag=True,
        application_metadata=None,
    )
    with pytest.raises(MatchProcessing) as exc:
        cloud_reco_client.query(image=high_quality_image)
    assert exc.value.response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
def test_base_exception(
    vws_client: VWS,
    cloud_reco_client: CloudRecoService,
    high_quality_image: io.BytesIO,
) -> None:
    """
    ``CloudRecoException``s has a response property.
    """
    vws_client.add_target(
        name='x',
        width=1,
        image=high_quality_image,
        active_flag=True,
        application_metadata=None,
    )

    with pytest.raises(CloudRecoException) as exc:
        cloud_reco_client.query(image=high_quality_image)

    assert exc.value.response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR
Exemple #21
0
def test_active_matching_targets_delete_processing(
    vws_client: VWS,
    cloud_reco_client: CloudRecoService,
    high_quality_image: io.BytesIO,
) -> None:
    """
    A ``ActiveMatchingTargetsDeleteProcessing`` exception is raised when a
    target which has recently been deleted is matched.
    """
    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)
    vws_client.delete_target(target_id=target_id)
    time.sleep(0.2)
    with pytest.raises(ActiveMatchingTargetsDeleteProcessing):
        cloud_reco_client.query(image=high_quality_image)
Exemple #22
0
    def test_bad_secret_key_query(
        self,
        vuforia_database: VuforiaDatabase,
        high_quality_image: io.BytesIO,
    ) -> None:
        """
        If the client secret key given is incorrect, an ``UNAUTHORIZED``
        response is returned.
        """
        cloud_reco_client = CloudRecoService(
            client_access_key=vuforia_database.client_access_key,
            client_secret_key='example',
        )

        with pytest.raises(cloud_reco_exceptions.AuthenticationFailure) as exc:
            cloud_reco_client.query(image=high_quality_image)

        response = exc.value.response

        assert_vwq_failure(
            response=response,
            status_code=HTTPStatus.UNAUTHORIZED,
            content_type='application/json',
            cache_control=None,
            www_authenticate='VWS',
            connection='keep-alive',
        )

        assert response.json().keys() == {'transaction_id', 'result_code'}
        assert_valid_transaction_id(response=response)
        assert_valid_date_header(response=response)
        result_code = response.json()['result_code']
        transaction_id = response.json()['transaction_id']
        assert result_code == ResultCodes.AUTHENTICATION_FAILURE.value
        # The separators are inconsistent and we test this.
        expected_text = ('{"transaction_id":'
                         f'"{transaction_id}",'
                         f'"result_code":"{result_code}"'
                         '}')
        assert response.text == expected_text
Exemple #23
0
def vuforia_cloud_reco(
    image: Path,
    client_access_key: str,
    client_secret_key: str,
    max_num_results: int,
    include_target_data: CloudRecoIncludeTargetData,
    base_vwq_url: str,
) -> None:
    """
    Make a request to the Vuforia Cloud Recognition Service API.
    """
    client = CloudRecoService(
        client_access_key=client_access_key,
        client_secret_key=client_secret_key,
        base_vwq_url=base_vwq_url,
    )
    query_result = client.query(
        image=io.BytesIO(image.read_bytes()),
        max_num_results=max_num_results,
        include_target_data=include_target_data,
    )
    query_result_dict_list = [dataclasses.asdict(res) for res in query_result]
    yaml_list = yaml.dump(query_result_dict_list)
    click.echo(yaml_list)
Exemple #24
0
def _wait_for_deletion_recognized(
    image: io.BytesIO,
    vuforia_database: VuforiaDatabase,
) -> None:
    """
    Wait until the query endpoint "recognizes" the deletion of all targets with
    an image matching the given image.

    That is, wait until querying the given image does not return a result with
    targets.
    """
    cloud_reco_client = CloudRecoService(
        client_access_key=vuforia_database.client_access_key,
        client_secret_key=vuforia_database.client_secret_key,
    )

    while True:
        try:
            results = cloud_reco_client.query(image=image)
        except ActiveMatchingTargetsDeleteProcessing:
            return

        if not results:
            return
Exemple #25
0
    def test_add_target(
        self,
        mock_database: VuforiaDatabase,
        vws_client: VWS,
        high_quality_image: io.BytesIO,
        tmp_path: Path,
        cloud_reco_client: CloudRecoService,
    ) -> None:
        """
        It is possible to add a target.
        """
        runner = CliRunner()
        new_file = tmp_path / uuid.uuid4().hex
        name = uuid.uuid4().hex
        image_data = high_quality_image.getvalue()
        new_file.write_bytes(data=image_data)
        width = random.uniform(a=0.01, b=50)
        commands = [
            'add-target',
            '--name',
            name,
            '--width',
            str(width),
            '--image',
            str(new_file),
            '--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

        target_id = result.stdout.strip()
        target_details = vws_client.get_target_record(target_id=target_id)
        target_record = target_details.target_record
        assert target_record.name == name
        assert target_record.width == width
        assert target_record.active_flag is True
        vws_client.wait_for_target_processed(target_id=target_id)

        [query_result] = cloud_reco_client.query(image=high_quality_image)
        assert query_result.target_id == target_id
        target_data = query_result.target_data
        assert target_data is not None
        assert target_data.application_metadata is None
Exemple #26
0
 def test_custom_metadata(
     self,
     mock_database: VuforiaDatabase,
     cloud_reco_client: CloudRecoService,
     vws_client: VWS,
     tmp_path: Path,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     Custom metadata can be given.
     """
     runner = CliRunner()
     new_file = tmp_path / uuid.uuid4().hex
     name = uuid.uuid4().hex
     image_data = high_quality_image.getvalue()
     new_file.write_bytes(data=image_data)
     application_metadata = uuid.uuid4().hex
     metadata_bytes = application_metadata.encode('ascii')
     base64_encoded_metadata_bytes = base64.b64encode(metadata_bytes)
     base64_encoded_metadata = base64_encoded_metadata_bytes.decode('ascii')
     commands = [
         'add-target',
         '--name',
         name,
         '--width',
         '0.1',
         '--image',
         str(new_file),
         '--application-metadata',
         base64_encoded_metadata,
         '--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
     target_id = result.stdout.strip()
     vws_client.wait_for_target_processed(target_id=target_id)
     [query_result] = cloud_reco_client.query(image=high_quality_image)
     assert query_result.target_id == target_id
     target_data = query_result.target_data
     assert target_data is not None
     assert target_data.application_metadata == base64_encoded_metadata
Exemple #27
0
 def test_match(
     self,
     vws_client: VWS,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     Details of matching targets are returned.
     """
     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)
     [matching_target] = cloud_reco_client.query(image=high_quality_image)
     assert matching_target.target_id == target_id
Exemple #28
0
    def test_add_target(
        self,
        vws_client: VWS,
        high_quality_image: io.BytesIO,
        active_flag: bool,
        application_metadata: Optional[bytes],
        cloud_reco_client: CloudRecoService,
    ) -> None:
        """
        No exception is raised when adding one target.
        """
        name = 'x'
        width = 1
        if application_metadata is None:
            encoded_metadata = None
        else:
            encoded_metadata_bytes = base64.b64encode(application_metadata)
            encoded_metadata = encoded_metadata_bytes.decode('utf-8')

        target_id = vws_client.add_target(
            name=name,
            width=width,
            image=high_quality_image,
            application_metadata=encoded_metadata,
            active_flag=active_flag,
        )
        target_record = vws_client.get_target_record(
            target_id=target_id,
        ).target_record
        assert target_record.name == name
        assert target_record.width == width
        assert target_record.active_flag is active_flag
        vws_client.wait_for_target_processed(target_id=target_id)
        matching_targets = cloud_reco_client.query(image=high_quality_image)
        if active_flag:
            [matching_target] = matching_targets
            assert matching_target.target_id == target_id
            assert matching_target.target_data is not None
            query_metadata = matching_target.target_data.application_metadata
            assert query_metadata == encoded_metadata
        else:
            assert matching_targets == []
Exemple #29
0
 def test_custom(
     self,
     vws_client: VWS,
     cloud_reco_client: CloudRecoService,
     high_quality_image: io.BytesIO,
 ) -> None:
     """
     It is possible to set a custom ``max_num_results``.
     """
     target_id = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     target_id_2 = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     target_id_3 = vws_client.add_target(
         name=uuid.uuid4().hex,
         width=1,
         image=high_quality_image,
         active_flag=True,
         application_metadata=None,
     )
     vws_client.wait_for_target_processed(target_id=target_id)
     vws_client.wait_for_target_processed(target_id=target_id_2)
     vws_client.wait_for_target_processed(target_id=target_id_3)
     matches = cloud_reco_client.query(
         image=high_quality_image,
         max_num_results=2,
     )
     assert len(matches) == 2
Exemple #30
0
        'Accept-Encoding': "gzip, deflate",
        'Connection': "keep-alive",
        'cache-control': "no-cache"
    }

    SERVER_ACCESS_KEY = os.environ['UPLOADER_SERVER_ACCESS_KEY']
    SERVER_SECRET_KEY = os.environ['UPLOADER_SERVER_SECRET_KEY']
    CLIENT_ACCESS_KEY = os.environ['UPLOADER_CLIENT_ACCESS_KEY']
    CLIENT_SECRET_KEY = os.environ['UPLOADER_CLIENT_SECRET_KEY']

    VWS_CLIENT = VWS(
        server_access_key=SERVER_ACCESS_KEY,
        server_secret_key=SERVER_SECRET_KEY,
    )
    CLOUD_RECO_CLIENT = CloudRecoService(
        client_access_key=CLIENT_ACCESS_KEY,
        client_secret_key=CLIENT_SECRET_KEY,
    )

    # checks if the database is empty: if it is, perform the initialisation
    LIST_OF_TARGETS = VWS_CLIENT.list_targets()
    if not LIST_OF_TARGETS:
        shutil.rmtree("/logos/")
        os.remove("existing_restaurants.txt")
        os.remove("imagehashes.txt")
        print("Database is empty, performing initialisation")
        initialise(VWS_CLIENT, HEADERS)
    else:
        # Find the new restaurants
        FILE = 'existing_restaurants.txt'
        NEW_RESTAURANTS_LIST = check_for_new_restaurants(HEADERS, FILE)