Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

low hanging fruit of transport test coverage #553

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions aries_cloudagent/transport/outbound/tests/test_http_transport.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import asyncio
import pytest

from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from aiohttp import web
from asynctest import mock as async_mock

from ....config.injection_context import InjectionContext
from ....utils.stats import Collector

from ...outbound.message import OutboundMessage
from ...wire_format import JsonWireFormat

from ..base import OutboundTransportError
from ..http import HttpTransport


Expand Down Expand Up @@ -38,6 +42,7 @@ async def send_message(transport, payload, endpoint):
await transport.handle_message(self.context, payload, endpoint)

transport = HttpTransport()

await asyncio.wait_for(send_message(transport, "{}", endpoint=server_addr), 5.0)
assert self.message_results == [{}]

Expand All @@ -61,3 +66,29 @@ async def send_message(transport, payload, endpoint):
"outbound-http:connect": 1,
"outbound-http:POST": 1,
}

@unittest_run_loop
async def test_transport_coverage(self):
transport = HttpTransport()
assert transport.wire_format is None
transport.wire_format = JsonWireFormat()
assert transport.wire_format is not None

await transport.start()

with pytest.raises(OutboundTransportError):
await transport.handle_message(None, None, None)

with async_mock.patch.object(
transport, "client_session", async_mock.MagicMock()
) as mock_session:
mock_response = async_mock.MagicMock(status=404)
mock_session.post = async_mock.MagicMock(
return_value=async_mock.MagicMock(
__aenter__=async_mock.CoroutineMock(return_value=mock_response)
)
)
with pytest.raises(OutboundTransportError):
await transport.handle_message(None, "dummy", "http://localhost")

await transport.__aexit__(KeyError, KeyError("just a drill"), None)
67 changes: 67 additions & 0 deletions aries_cloudagent/transport/outbound/tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@ def test_register_path(self):
assert mgr.get_registered_transport_for_scheme("http")
assert mgr.MAX_RETRY_COUNT == 4

assert mgr.get_registered_transport_for_scheme("xmpp") is None

with self.assertRaises(OutboundTransportRegistrationError):
mgr.register("http")

with self.assertRaises(OutboundTransportRegistrationError):
mgr.register("no.such.module.path")

def test_maximum_retry_count(self):
context = InjectionContext()
context.update_settings({"transport.max_outbound_retry": 5})
Expand Down Expand Up @@ -67,6 +72,7 @@ async def test_send_message(self):
assert mgr.get_running_transport_for_scheme("http") == "transport_cls"

message = OutboundMessage(payload="{}")
assert "payload" in str(message)
message.target = ConnectionTarget(
endpoint="http://localhost",
recipient_keys=[1, 2],
Expand All @@ -89,11 +95,33 @@ async def test_send_message(self):
transport.wire_format.encode_message.return_value,
message.target.endpoint,
)

with self.assertRaises(OutboundDeliveryError):
mgr.get_running_transport_for_endpoint("localhost")

message.target = ConnectionTarget(
endpoint="localhost", recipient_keys=[1, 2], routing_keys=[3], sender_key=4,
)
with self.assertRaises(OutboundDeliveryError) as context:
mgr.enqueue_message(send_context, message)
assert "No supported transport" in str(context.exception)

await mgr.stop()

assert mgr.get_running_transport_for_scheme("http") is None
transport.stop.assert_awaited_once_with()

async def test_stop_cancel(self):
context = InjectionContext()
context.update_settings({"transport.outbound_configs": ["http"]})
mgr = OutboundTransportManager(context)
mgr._process_task = async_mock.MagicMock(
done=async_mock.MagicMock(return_value=False), cancel=async_mock.MagicMock()
)
mgr.running_transports = {}
await mgr.stop()
mgr._process_task.cancel.assert_called_once()

async def test_enqueue_webhook(self):
context = InjectionContext()
mgr = OutboundTransportManager(context)
Expand Down Expand Up @@ -126,3 +154,42 @@ async def test_enqueue_webhook(self):
assert json.loads(queued.payload) == test_payload
assert queued.retries == test_attempts - 1
assert queued.state == QueuedOutboundMessage.STATE_PENDING

async def test_process_done_x(self):
mock_task = async_mock.MagicMock(
done=async_mock.MagicMock(return_value=True),
exception=async_mock.MagicMock(return_value=KeyError("No such key")),
)
context = InjectionContext()
mgr = OutboundTransportManager(context)

with async_mock.patch.object(
mgr, "_process_task", async_mock.MagicMock()
) as mock_mgr_process:
mock_mgr_process.done = async_mock.MagicMock(return_value=True)
mgr._process_done(mock_task)

async def test_process_finished_x(self):
mock_queued = async_mock.MagicMock(retries=1)
mock_task = async_mock.MagicMock(exc_info=(KeyError, KeyError("nope"), None),)
context = InjectionContext()
mgr = OutboundTransportManager(context)

with async_mock.patch.object(
mgr, "process_queued", async_mock.MagicMock()
) as mock_mgr_process:
mgr.finished_encode(mock_queued, mock_task)
mgr.finished_deliver(mock_queued, mock_task)
mgr.finished_deliver(mock_queued, mock_task)

async def test_process_loop_x(self):
mock_queued = async_mock.MagicMock(
state=QueuedOutboundMessage.STATE_DONE, error=KeyError()
)

context = InjectionContext()
mock_handle_not_delivered = async_mock.MagicMock()
mgr = OutboundTransportManager(context, mock_handle_not_delivered)
mgr.outbound_buffer.append(mock_queued)

await mgr._process_loop()
3 changes: 3 additions & 0 deletions aries_cloudagent/transport/queue/tests/test_basic_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ async def test_enqueue_dequeue(self):
with self.assertRaises(asyncio.TimeoutError):
await queue.dequeue(timeout=0)

queue.task_done()
await queue.join()

async def test_async_iter(self):
queue = BasicMessageQueue()

Expand Down
73 changes: 71 additions & 2 deletions aries_cloudagent/transport/tests/test_pack_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
from ...protocols.routing.v1_0.message_types import FORWARD
from ...wallet.base import BaseWallet
from ...wallet.basic import BasicWallet
from ...wallet.error import WalletError

from ..error import MessageParseError
from ..error import MessageEncodeError, MessageParseError
from ..pack_format import PackWireFormat
from .. import pack_format as test_module


class TestPackWireFormat(AsyncTestCase):
Expand All @@ -34,7 +36,6 @@ def setUp(self):

async def test_errors(self):
serializer = PackWireFormat()

bad_values = [None, "", "1", "[]", "{..."]

for message_json in bad_values:
Expand All @@ -43,6 +44,68 @@ async def test_errors(self):
self.context, message_json
)

x_message = {
"@id": TestPackWireFormat.test_message_id,
"~thread": {"thid": TestPackWireFormat.test_thread_id},
"~transport": {"return_route": "all"},
"content": "{}",
}

serializer.task_queue = None
with async_mock.patch.object(
serializer, "unpack", async_mock.CoroutineMock()
) as mock_unpack:
mock_unpack.return_value = "{missing-brace"
with self.assertRaises(MessageParseError) as context:
await serializer.parse_message(self.context, json.dumps(x_message))
assert "Message JSON parsing failed" in str(context.exception)

serializer = PackWireFormat()
serializer.task_queue = None
with async_mock.patch.object(
serializer, "unpack", async_mock.CoroutineMock()
) as mock_unpack:
mock_unpack.return_value = json.dumps([1, 2, 3])
with self.assertRaises(MessageParseError) as context:
await serializer.parse_message(self.context, json.dumps(x_message))
assert "Message JSON result is not an object" in str(context.exception)

with self.assertRaises(MessageParseError):
await serializer.unpack(InjectionContext(), "...", None)

async def test_pack_x(self):
serializer = PackWireFormat()

with self.assertRaises(MessageEncodeError):
await serializer.pack(self.context, None, None, None, None)

with self.assertRaises(MessageEncodeError):
await serializer.pack(InjectionContext(), None, ["key"], None, ["key"])

mock_wallet = async_mock.MagicMock(
pack_message=async_mock.CoroutineMock(side_effect=WalletError())
)
context = InjectionContext(enforce_typing=False)
context.injector.bind_instance(BaseWallet, mock_wallet)
with self.assertRaises(MessageEncodeError):
await serializer.pack(context, None, ["key"], None, ["key"])

context.injector.clear_binding(BaseWallet)
mock_wallet = async_mock.MagicMock(
pack_message=async_mock.CoroutineMock(
side_effect=[json.dumps("message").encode("utf-8"), WalletError()]
)
)
context.injector.bind_instance(BaseWallet, mock_wallet)
with async_mock.patch.object(
test_module, "Forward", async_mock.MagicMock()
) as mock_forward:
mock_forward.return_value = async_mock.MagicMock(
to_json=async_mock.MagicMock()
)
with self.assertRaises(MessageEncodeError):
await serializer.pack(context, None, ["key"], ["key"], ["key"])

async def test_unpacked(self):
serializer = PackWireFormat()
message_json = json.dumps(self.test_message)
Expand Down Expand Up @@ -90,6 +153,12 @@ async def test_encode_decode(self):
assert delivery.thread_id == self.test_thread_id
assert delivery.direct_response_mode == "all"

plain_json = json.dumps("plain")
assert (
await serializer.encode_message(self.context, plain_json, None, None, None)
== plain_json
)

async def test_forward(self):
local_did = await self.wallet.create_local_did(self.test_seed)
router_did = await self.wallet.create_local_did(self.test_routing_seed)
Expand Down