-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1866 from sicpa-dlab/feature/universal-resolver
feat: add universal resolver
- Loading branch information
Showing
5 changed files
with
409 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
222 changes: 222 additions & 0 deletions
222
aries_cloudagent/resolver/default/tests/test_universal.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
"""Test universal resolver with http bindings.""" | ||
|
||
import re | ||
from typing import Dict, Union | ||
|
||
from asynctest import mock as async_mock | ||
import pytest | ||
|
||
from aries_cloudagent.config.settings import Settings | ||
|
||
from .. import universal as test_module | ||
from ...base import DIDNotFound, ResolverError | ||
from ..universal import UniversalResolver | ||
|
||
|
||
@pytest.fixture | ||
async def resolver(): | ||
"""Resolver fixture.""" | ||
yield UniversalResolver( | ||
endpoint="https://example.com", supported_did_regex=re.compile("^did:sov:.*$") | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def profile(): | ||
"""Profile fixture.""" | ||
yield async_mock.MagicMock() | ||
|
||
|
||
class MockResponse: | ||
"""Mock http response.""" | ||
|
||
def __init__(self, status: int, body: Union[str, Dict]): | ||
self.status = status | ||
self.body = body | ||
|
||
async def json(self): | ||
return self.body | ||
|
||
async def text(self): | ||
return self.body | ||
|
||
async def __aenter__(self): | ||
"""For use as async context.""" | ||
return self | ||
|
||
async def __aexit__(self, err_type, err_value, err_exc): | ||
"""For use as async context.""" | ||
|
||
|
||
class MockClientSession: | ||
"""Mock client session.""" | ||
|
||
def __init__(self, response: MockResponse = None): | ||
self.response = response | ||
|
||
def __call__(self): | ||
return self | ||
|
||
async def __aenter__(self): | ||
"""For use as async context.""" | ||
return self | ||
|
||
async def __aexit__(self, err_type, err_value, err_exc): | ||
"""For use as async context.""" | ||
|
||
def get(self, endpoint): | ||
"""Return response.""" | ||
return self.response | ||
|
||
|
||
@pytest.fixture | ||
def mock_client_session(): | ||
temp = test_module.aiohttp.ClientSession | ||
session = MockClientSession() | ||
test_module.aiohttp.ClientSession = session | ||
yield session | ||
test_module.aiohttp.ClientSession = temp | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_resolve(profile, resolver, mock_client_session): | ||
mock_client_session.response = MockResponse( | ||
200, | ||
{ | ||
"didDocument": { | ||
"id": "did:example:123", | ||
"@context": "https://www.w3.org/ns/did/v1", | ||
} | ||
}, | ||
) | ||
doc = await resolver.resolve(profile, "did:sov:WRfXPg8dantKVubE3HX8pw") | ||
assert doc.get("id") == "did:example:123" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_resolve_not_found(profile, resolver, mock_client_session): | ||
mock_client_session.response = MockResponse(404, "Not found") | ||
with pytest.raises(DIDNotFound): | ||
await resolver.resolve(profile, "did:sov:WRfXPg8dantKVubE3HX8pw") | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_resolve_unexpeceted_status(profile, resolver, mock_client_session): | ||
mock_client_session.response = MockResponse( | ||
500, "Server failed to complete request" | ||
) | ||
with pytest.raises(ResolverError): | ||
await resolver.resolve(profile, "did:sov:WRfXPg8dantKVubE3HX8pw") | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_fetch_resolver_props(mock_client_session: MockClientSession): | ||
mock_client_session.response = MockResponse(200, {"test": "json"}) | ||
assert await test_module._fetch_resolver_props("test") == {"test": "json"} | ||
mock_client_session.response = MockResponse(404, "Not found") | ||
with pytest.raises(ResolverError): | ||
await test_module._fetch_resolver_props("test") | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_get_supported_did_regex(): | ||
props = {"example": {"http": {"pattern": "match a test string"}}} | ||
with async_mock.patch.object( | ||
test_module, | ||
"_fetch_resolver_props", | ||
async_mock.CoroutineMock(return_value=props), | ||
): | ||
pattern = await test_module._get_supported_did_regex("test") | ||
assert pattern.fullmatch("match a test string") | ||
|
||
|
||
def test_compile_supported_did_regex(): | ||
patterns = ["one", "two", "three"] | ||
compiled = test_module._compile_supported_did_regex(patterns) | ||
assert compiled.match("one") | ||
assert compiled.match("two") | ||
assert compiled.match("three") | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_setup_endpoint_regex_set(resolver: UniversalResolver): | ||
settings = Settings( | ||
{ | ||
"resolver.universal": "http://example.com", | ||
"resolver.universal.supported": "test", | ||
} | ||
) | ||
context = async_mock.MagicMock() | ||
context.settings = settings | ||
with async_mock.patch.object( | ||
test_module, | ||
"_compile_supported_did_regex", | ||
async_mock.MagicMock(return_value="pattern"), | ||
): | ||
await resolver.setup(context) | ||
|
||
assert resolver._endpoint == "http://example.com" | ||
assert resolver._supported_did_regex == "pattern" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_setup_endpoint_set(resolver: UniversalResolver): | ||
settings = Settings( | ||
{ | ||
"resolver.universal": "http://example.com", | ||
} | ||
) | ||
context = async_mock.MagicMock() | ||
context.settings = settings | ||
with async_mock.patch.object( | ||
test_module, | ||
"_get_supported_did_regex", | ||
async_mock.CoroutineMock(return_value="pattern"), | ||
): | ||
await resolver.setup(context) | ||
|
||
assert resolver._endpoint == "http://example.com" | ||
assert resolver._supported_did_regex == "pattern" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_setup_endpoint_default(resolver: UniversalResolver): | ||
settings = Settings( | ||
{ | ||
"resolver.universal": "DEFAULT", | ||
} | ||
) | ||
context = async_mock.MagicMock() | ||
context.settings = settings | ||
with async_mock.patch.object( | ||
test_module, | ||
"_get_supported_did_regex", | ||
async_mock.CoroutineMock(return_value="pattern"), | ||
): | ||
await resolver.setup(context) | ||
|
||
assert resolver._endpoint == test_module.DEFAULT_ENDPOINT | ||
assert resolver._supported_did_regex == "pattern" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_setup_endpoint_unset(resolver: UniversalResolver): | ||
settings = Settings() | ||
context = async_mock.MagicMock() | ||
context.settings = settings | ||
with async_mock.patch.object( | ||
test_module, | ||
"_get_supported_did_regex", | ||
async_mock.CoroutineMock(return_value="pattern"), | ||
): | ||
await resolver.setup(context) | ||
|
||
assert resolver._endpoint == test_module.DEFAULT_ENDPOINT | ||
assert resolver._supported_did_regex == "pattern" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_supported_did_regex_not_setup(): | ||
resolver = UniversalResolver() | ||
with pytest.raises(ResolverError): | ||
resolver.supported_did_regex |
Oops, something went wrong.