Skip to content

Commit

Permalink
extend unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Whitehead <cywolf@gmail.com>
  • Loading branch information
andrewwhitehead committed Oct 28, 2019
1 parent 2de840d commit 6fb6897
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 154 deletions.
2 changes: 1 addition & 1 deletion aries_cloudagent/admin/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,6 @@ async def complete_webhooks(self):
"""Wait for all pending webhooks to be dispatched, used in testing."""
if self.webhook_queue:
await self.webhook_queue.join()
self.webhook_queue.stop()
self.webhook_queue.reset()
if self.webhook_processor:
await self.webhook_processor.wait_done()
140 changes: 112 additions & 28 deletions aries_cloudagent/admin/tests/test_admin_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,99 @@

from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop, unused_port
from aiohttp import web
from asynctest import TestCase as AsyncTestCase
from asynctest.mock import patch

from ...config.injection_context import InjectionContext
from ...config.provider import ClassProvider
from ...messaging.outbound_message import OutboundMessage
from ...transport.outbound.queue.base import BaseOutboundMessageQueue
from ...transport.outbound.queue.basic import BasicOutboundMessageQueue

from ..server import AdminServer


class TestAdminServerApp(AioHTTPTestCase):
async def outbound_message_router(self, *args):
pass
class TestAdminServerBasic(AsyncTestCase):
async def setUp(self):
self.message_results = []

def get_admin_server(self) -> AdminServer:
def get_admin_server(self, settings: dict = None) -> AdminServer:
context = InjectionContext()
context.injector.bind_provider(
BaseOutboundMessageQueue, ClassProvider(BasicOutboundMessageQueue)
)
context.settings["admin.admin_insecure_mode"] = True
server = AdminServer(
if settings:
context.update_settings(settings)
return AdminServer(
"0.0.0.0", unused_port(), context, self.outbound_message_router
)
return server

@unittest_run_loop
async def test_start_bad_settings(self):
server = self.get_admin_server()
server.context.settings["admin.admin_insecure_mode"] = None

try:
await server.start()
except AssertionError:
return True

raise Exception
async def outbound_message_router(self, *args):
self.message_results.append(args)

@unittest_run_loop
async def test_start_stop(self):
server = self.get_admin_server()
with self.assertRaises(AssertionError):
await self.get_admin_server().start()

settings = {"admin.admin_insecure_mode": False}
with self.assertRaises(AssertionError):
await self.get_admin_server(settings).start()

settings = {
"admin.admin_insecure_mode": True,
"admin.admin_api_key": "test-api-key",
}
with self.assertRaises(AssertionError):
await self.get_admin_server(settings).start()

settings = {
"admin.admin_insecure_mode": False,
"admin.admin_api_key": "test-api-key",
}
server = self.get_admin_server(settings)
await server.start()
await server.stop()

async def test_responder_send(self):
message = OutboundMessage("{}")
admin_server = self.get_admin_server()
await admin_server.responder.send_outbound(message)
assert self.message_results == [(message,)]

@unittest_run_loop
async def test_responder_webhook(self):
with patch.object(AdminServer, "send_webhook", autospec=True) as sender:
admin_server = self.get_admin_server()
test_topic = "test_topic"
test_payload = {"test": "TEST"}
await admin_server.responder.send_webhook(test_topic, test_payload)
sender.assert_awaited_once_with(admin_server, test_topic, test_payload)


class TestAdminServerClient(AioHTTPTestCase):
async def setUpAsync(self):
self.message_results = []

async def get_application(self):
"""
Override the get_app method to return your application.
"""
return await self.get_admin_server().make_application()

async def outbound_message_router(self, *args):
self.message_results.append(args)

def get_admin_server(self) -> AdminServer:
context = InjectionContext()
context.injector.bind_provider(
BaseOutboundMessageQueue, ClassProvider(BasicOutboundMessageQueue)
)
context.settings["admin.admin_insecure_mode"] = True
server = AdminServer(
"0.0.0.0", unused_port(), context, self.outbound_message_router
)
return server

# the unittest_run_loop decorator can be used in tandem with
# the AioHTTPTestCase to simplify running
# tests that are asynchronous
Expand All @@ -62,7 +108,6 @@ async def test_swagger(self):
resp = await self.client.request("GET", "/api/doc")
assert resp.status == 200
text = await resp.text()
print(text)
assert "Swagger UI" in text

@unittest_run_loop
Expand All @@ -73,19 +118,50 @@ async def test_status(self):
resp = await self.client.request("POST", "/status/reset")
assert resp.status == 200

@unittest_run_loop
async def test_status(self):
resp = await self.client.request("GET", "/status")
result = await resp.json()
assert isinstance(result, dict)

@unittest_run_loop
async def test_websocket(self):
async with self.client.ws_connect("/ws") as ws:
result = await ws.receive_json()
assert result["topic"] == "settings"


class TestAdminServerSecure(AioHTTPTestCase):
TEST_API_KEY = "test-api-key"

async def get_application(self):
"""
Override the get_app method to return your application.
"""
return await self.get_admin_server().make_application()

async def outbound_message_router(self, *args):
self.message_results.append(args)

def get_admin_server(self) -> AdminServer:
context = InjectionContext()
context.injector.bind_provider(
BaseOutboundMessageQueue, ClassProvider(BasicOutboundMessageQueue)
)
context.settings["admin.admin_api_key"] = self.TEST_API_KEY
self.server = AdminServer(
"0.0.0.0", unused_port(), context, self.outbound_message_router
)
return self.server

@unittest_run_loop
async def test_status_insecure(self):
resp = await self.client.request("GET", "/status")
assert resp.status == 401

@unittest_run_loop
async def test_status_secure(self):
resp = await self.client.request(
"GET", "/status", headers={"x-api-key": self.TEST_API_KEY}
)
result = await resp.json()
assert isinstance(result, dict)


class TestAdminServerWebhook(AioHTTPTestCase):
async def setUpAsync(self):
self.hook_results = []
Expand All @@ -104,8 +180,9 @@ def get_admin_server(self) -> AdminServer:
context.injector.bind_provider(
BaseOutboundMessageQueue, ClassProvider(BasicOutboundMessageQueue)
)
context.settings["admin.admin_insecure_mode"] = True
server = AdminServer(
"localhost", unused_port(), context, self.outbound_message_router
"0.0.0.0", unused_port(), context, self.outbound_message_router
)
return server

Expand All @@ -121,9 +198,16 @@ async def get_application(self):
async def test_webhook(self):
server_addr = f"http://localhost:{self.server.port}"
admin_server = self.get_admin_server()
await admin_server.start()

admin_server.add_webhook_target(server_addr)
test_topic = "test_topic"
test_payload = {"test": "TEST"}
await admin_server.send_webhook(test_topic, test_payload)
await asyncio.wait_for(admin_server.complete_webhooks(), 5.0)
assert self.hook_results == [(test_topic, test_payload)]

admin_server.remove_webhook_target(server_addr)
assert admin_server.webhook_targets == {}

await admin_server.stop()
4 changes: 2 additions & 2 deletions aries_cloudagent/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ def wrap(
):
"""Wrap a method on a class or class instance."""
if not prop_name:
return
raise ValueError("missing prop_name")
if isinstance(prop_name, str):
method = getattr(obj, prop_name, None)
if method:
setattr(obj, prop_name, self(method, groups))
elif not ignore_missing:
raise KeyError(prop_name)
raise AttributeError(prop_name)
else:
for prop in prop_name:
self.wrap(obj, prop, groups)
Expand Down
7 changes: 7 additions & 0 deletions aries_cloudagent/tests/test_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,15 @@ def test_wrap(self):
"TestStats.test_method_decorator.<locals>.TestClass.test_wrap",
}

with self.assertRaises(AttributeError):
stats.wrap(instance, "test_missing")

with self.assertRaises(ValueError):
stats.wrap(instance, "")

async def test_disable(self):
stats = Collector()
assert stats.enabled
stats.enabled = False

stats.log("test", 1.0)
Expand Down
11 changes: 6 additions & 5 deletions aries_cloudagent/transport/outbound/queue/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ async def dequeue(self, *, timeout: int = None):
asyncio.TimeoutError if the timeout is reached
"""
if not self.stop_event.is_set():
stopped = asyncio.ensure_future(self.stop_event.wait())
dequeued = asyncio.ensure_future(self.queue.get())
stop_event, queue = self.stop_event, self.queue
if not stop_event.is_set():
stopped = asyncio.ensure_future(stop_event.wait())
dequeued = asyncio.ensure_future(queue.get())
done, pending = await asyncio.wait(
(stopped, dequeued),
timeout=timeout,
Expand All @@ -67,7 +68,7 @@ async def dequeue(self, *, timeout: int = None):
elif not stopped.done():
raise asyncio.TimeoutError

if self.stop_event.is_set():
if stop_event.is_set():
raise asyncio.CancelledError

return None
Expand All @@ -88,4 +89,4 @@ def reset(self):
"""Empty the queue and reset the stop event."""
self.stop()
self.queue = self.make_queue()
self.stop_event.clear()
self.stop_event = asyncio.Event()
21 changes: 21 additions & 0 deletions aries_cloudagent/transport/outbound/tests/test_http_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from aiohttp import web

from ....messaging.outbound_message import OutboundMessage
from ....stats import Collector

from ..http import HttpTransport

Expand Down Expand Up @@ -37,3 +38,23 @@ async def send_message(transport, message):
message = OutboundMessage("{}", endpoint=server_addr)
await asyncio.wait_for(send_message(transport, message), 5.0)
assert self.message_results == [{}]

@unittest_run_loop
async def test_stats(self):
server_addr = f"http://localhost:{self.server.port}"

async def send_message(transport, message):
async with transport:
await transport.handle_message(message)

transport = HttpTransport()
transport.collector = Collector()
message = OutboundMessage(b"{}", endpoint=server_addr)
await asyncio.wait_for(send_message(transport, message), 5.0)

results = transport.collector.extract()
assert results["count"] == {
"outbound-http:dns_resolve": 1,
"outbound-http:connect": 1,
"outbound-http:POST": 1,
}

0 comments on commit 6fb6897

Please sign in to comment.