Skip to content

Commit

Permalink
Definition routes/services unit tests (#857)
Browse files Browse the repository at this point in the history
* imports

* moved create schema logic here

* service for tenants to get schemas

* service for governance to get schemas

* from schema_ids get full schemas

* moved bulk of create cred_def logic here

* moved get cred_def logic here

* import dataclass for service dependencies

* add service dependencies dataclass

* add schema publisher class

* add class to publish schema to trust registry

* refactor create schema service

* add helper class cred def publisher

* refactor create cred def service

* move to helper class

* formatting

* redo logging not passing logger down

* move to definitions folder

* assert governance is calling function

* formatting

* update doc strings

* call register schema directly

* raise exception if not governance role

* formatting

* add default values

* update function names

* remove unused imports

* move to schema pub class add check for governance agent

* removed arg build in func

* 🚚 move schema specific methods to own module

* 🎨 rename module for clarity

* add definitions routes tests

* formatting

* remove unused imports

* update patching to match new structure

* formatting

* add tests for schemas module in definitions services

* add test for definitions service

* formatting/import sort

* add unit test for publisher modules

* remove unused imports

* some clean-up

* change return type

* if schema exists just return dont register on TR

* convert model to new return type

* remove unused model

* conversion already done

* update tests to mach new return types

* update tests to match new return types

* more tests for schema publisher

* import sort

* add test for multi schemas found

* some deduplication

* formatting

* disable=redefined-outer-name

* remove unused imports

* 🎨

* 🎨 disable pylint warning

* 🎨 disable pylint warning

---------

Co-authored-by: ff137 <[email protected]>
Co-authored-by: cl0ete <[email protected]>
  • Loading branch information
cl0ete and ff137 authored Jul 19, 2024
1 parent f0c39c6 commit 15ef8cb
Show file tree
Hide file tree
Showing 16 changed files with 1,732 additions and 8 deletions.
12 changes: 5 additions & 7 deletions app/services/definitions/schema_publisher.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
from logging import Logger
from typing import List

from aries_cloudcontroller import (
AcaPyClient,
SchemaGetResult,
SchemaSendRequest,
TxnOrSchemaSendResult,
)
from aries_cloudcontroller import AcaPyClient, SchemaGetResult, SchemaSendRequest

from app.exceptions import CloudApiException, handle_acapy_call
from app.models.definitions import CredentialSchema
Expand All @@ -21,7 +16,7 @@ def __init__(self, controller: AcaPyClient, logger: Logger):

async def publish_schema(
self, schema_request: SchemaSendRequest
) -> TxnOrSchemaSendResult:
) -> CredentialSchema:
try:
result = await handle_acapy_call(
logger=self._logger,
Expand All @@ -32,6 +27,7 @@ async def publish_schema(
except CloudApiException as e:
if "already exist" in e.detail and e.status_code == 400:
result = await self._handle_existing_schema(schema_request)
return result
else:
self._logger.warning(
"An unhandled Exception was caught while publishing schema: {}",
Expand All @@ -46,6 +42,8 @@ async def publish_schema(
raise CloudApiException(
"An unexpected error occurred: could not publish schema."
)

result = credential_schema_from_acapy(result.sent.var_schema)
return result

async def _handle_existing_schema(
Expand Down
1 change: 0 additions & 1 deletion app/services/definitions/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ async def create_schema(

result = await publisher.publish_schema(schema_request)

result = credential_schema_from_acapy(result.sent.var_schema)
bound_logger.info("Successfully published and registered schema.")
return result

Expand Down
95 changes: 95 additions & 0 deletions app/tests/routes/definitions/test_create_credential_definition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from unittest.mock import AsyncMock, patch

import pytest

from app.exceptions import CloudApiException
from app.models.definitions import CreateCredentialDefinition, CredentialDefinition
from app.routes.definitions import create_credential_definition

create_cred_def_body = CreateCredentialDefinition(
schema_id="mock_schema_id",
tag="mock_tag",
support_revocation=False,
)
cred_def_response = CredentialDefinition(
id="mock_credential_definition_id",
schema_id="mock_schema_id",
tag="mock_tag",
)


@pytest.mark.anyio
async def test_create_credential_definition_success():
mock_aries_controller = AsyncMock()

mock_create_credential_definition = AsyncMock()
mock_create_credential_definition.return_value = "mock_credential_definition_id"

mock_coroutine_with_retry = AsyncMock()

with patch(
"app.routes.definitions.client_from_auth"
) as mock_get_client_controller, patch(
"app.routes.definitions.cred_def_service.create_credential_definition"
) as mock_create_credential_definition, patch(
"app.routes.definitions.coroutine_with_retry"
) as mock_coroutine_with_retry:

mock_get_client_controller.return_value.__aenter__.return_value = (
mock_aries_controller
)
mock_coroutine_with_retry.return_value = cred_def_response

response = await create_credential_definition(
auth="mocked_auth",
credential_definition=create_cred_def_body,
)

mock_create_credential_definition.assert_called_once_with(
aries_controller=mock_aries_controller,
credential_definition=create_cred_def_body,
support_revocation=False,
)

mock_coroutine_with_retry.assert_awaited()

assert response == cred_def_response


@pytest.mark.anyio
@pytest.mark.parametrize(
"expected_status_code, expected_detail",
[
(400, "Bad request"),
(409, "Conflict"),
(500, "Internal Server Error"),
],
)
async def test_create_credential_definition_fail_acapy_error(
expected_status_code, expected_detail
):
mock_aries_controller = AsyncMock()

mock_create_credential_definition = AsyncMock()

with patch(
"app.routes.definitions.client_from_auth"
) as mock_get_client_controller, patch(
"app.routes.definitions.cred_def_service.create_credential_definition"
) as mock_create_credential_definition:

mock_get_client_controller.return_value.__aenter__.return_value = (
mock_aries_controller
)
mock_create_credential_definition.side_effect = CloudApiException(
status_code=expected_status_code, detail=expected_detail
)

with pytest.raises(CloudApiException) as exc:
await create_credential_definition(
auth="mocked_auth",
credential_definition=create_cred_def_body,
)

assert exc.value.status_code == expected_status_code
assert exc.value.detail == expected_detail
93 changes: 93 additions & 0 deletions app/tests/routes/definitions/test_create_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from unittest.mock import AsyncMock, patch

import pytest
from aries_cloudcontroller import SchemaSendRequest

from app.exceptions import CloudApiException
from app.models.definitions import CreateSchema, CredentialSchema
from app.routes.definitions import create_schema

create_schema_body = CreateSchema(
name="Test_Schema_1", version="0.1.0", attribute_names=["attr1", "attr2"]
)
schema_send_request = SchemaSendRequest(
attributes=["attr1", "attr2"], schema_name="Test_Schema_1", schema_version="0.1.0"
)
create_schema_response = CredentialSchema(
id="27aG25kMFticzJ8GHH87BB:2:Test_Schema_1:0.1.0",
name="Test_Schema_1",
version="0.1.0",
attribute_names=["attr1", "attr2"],
)


@pytest.mark.anyio
@pytest.mark.parametrize(
"request_body",
[
create_schema_body,
],
)
async def test_create_schema_success(request_body):
mock_aries_controller = AsyncMock()
mock_create_schema_service = AsyncMock()
mock_create_schema_service.return_value = create_schema_response

with patch(
"app.routes.definitions.get_governance_controller"
) as mock_get_governance_controller, patch(
"app.routes.definitions.schemas_service.create_schema",
mock_create_schema_service,
):
mock_get_governance_controller.return_value.__aenter__.return_value = (
mock_aries_controller
)

response = await create_schema(
schema=request_body, governance_auth="mocked_auth"
)

mock_create_schema_service.assert_called_once_with(
aries_controller=mock_aries_controller,
schema=request_body,
)

assert response == create_schema_response


@pytest.mark.anyio
@pytest.mark.parametrize(
"expected_status_code, expected_detail",
[
(400, "Bad request"),
(409, "Conflict"),
(500, "Internal Server Error"),
],
)
async def test_create_schema_failure(expected_status_code, expected_detail):
mock_aries_controller = AsyncMock()
mock_create_schema_service = AsyncMock()

with patch(
"app.routes.definitions.get_governance_controller"
) as mock_get_governance_controller, patch(
"app.routes.definitions.schemas_service.create_schema",
mock_create_schema_service,
):
mock_get_governance_controller.return_value.__aenter__.return_value = (
mock_aries_controller
)

mock_create_schema_service.side_effect = CloudApiException(
status_code=expected_status_code, detail=expected_detail
)

with pytest.raises(CloudApiException, match=expected_detail):
await create_schema(
schema=create_schema_body, governance_auth="mocked_auth"
)

mock_create_schema_service.assert_called_once_with(
aries_controller=mock_aries_controller,
schema=create_schema_body,
)
100 changes: 100 additions & 0 deletions app/tests/routes/definitions/test_get_credential_defifnition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from unittest.mock import AsyncMock, patch

import pytest

from app.exceptions import CloudApiException
from app.models.definitions import CredentialDefinition
from app.routes.definitions import get_credential_definitions

cred_def_response = [
CredentialDefinition(
id="J5Pvam9KqK8ZPQWtvhAxSx:3:CL:8:Epic", tag="Epic", schema_id="8"
),
CredentialDefinition(
id="J5Pvam9KqK8ZPQWtvhAxSx:3:CL:9:Default", tag="Default", schema_id="9"
),
]


@pytest.mark.anyio
@pytest.mark.parametrize(
"params, response",
[
({}, cred_def_response),
({"issuer_did": "J5Pvam9KqK8ZPQWtvhAxSx"}, cred_def_response),
(
{"credential_definition_id": "J5Pvam9KqK8ZPQWtvhAxSx:3:CL:8:Epic"},
[cred_def_response[0]],
),
({"schema_id": "8"}, cred_def_response),
({"schema_issuer_did": "some_did"}, [cred_def_response[1]]),
({"schema_name": "some_name"}, [cred_def_response[1]]),
({"schema_version": "some_version"}, cred_def_response[0]),
({"credential_definition_id": "not_found_id"}, []),
],
)
async def test_get_credential_definitions_success(params, response):
mock_aries_controller = AsyncMock()

mock_get_credential_definitions = AsyncMock()

with patch(
"app.routes.definitions.client_from_auth"
) as mock_get_client_controller, patch(
"app.routes.definitions.cred_def_service.get_credential_definitions"
) as mock_get_credential_definitions:

mock_get_credential_definitions.return_value = response
mock_get_client_controller.return_value.__aenter__.return_value = (
mock_aries_controller
)

cred_defs = await get_credential_definitions(
auth="mocked_auth",
**params,
)

mock_get_credential_definitions.assert_called_once_with(
aries_controller=mock_aries_controller,
issuer_did=params.get("issuer_did"),
credential_definition_id=params.get("credential_definition_id"),
schema_id=params.get("schema_id"),
schema_issuer_did=params.get("schema_issuer_did"),
schema_name=params.get("schema_name"),
schema_version=params.get("schema_version"),
)

assert cred_defs == response


@pytest.mark.anyio
@pytest.mark.parametrize(
"expected_status_code, expected_detail",
[
(400, "Bad request"),
(500, "Internal Server Error"),
],
)
async def test_get_credential_definitions_fail_acapy_error(
expected_status_code, expected_detail
):
mock_aries_controller = AsyncMock()

with patch(
"app.routes.definitions.client_from_auth"
) as mock_get_client_controller, patch(
"app.routes.definitions.cred_def_service.get_credential_definitions"
) as mock_get_credential_definitions:

mock_get_credential_definitions.side_effect = CloudApiException(
status_code=expected_status_code, detail=expected_detail
)
mock_get_client_controller.return_value.__aenter__.return_value = (
mock_aries_controller
)

with pytest.raises(CloudApiException) as exc:
await get_credential_definitions(auth="mocked_auth")

assert exc.value.status_code == expected_status_code
assert exc.value.detail == expected_detail
Loading

0 comments on commit 15ef8cb

Please sign in to comment.