Skip to content
This repository was archived by the owner on Mar 13, 2022. It is now read-only.

Commit 2bb9a3a

Browse files
authored
Merge from issue/12-unit-tests-for-daemon into develop (#26)
Added unit tests for daemon
2 parents e0fda5a + 01fb59b commit 2bb9a3a

File tree

2 files changed

+204
-2
lines changed

2 files changed

+204
-2
lines changed

Diff for: daemon/daemon.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from fastapi import FastAPI, status, Request
2-
from fastapi.exceptions import HTTPException
3-
from fastapi.exceptions import RequestValidationError
2+
from fastapi.exceptions import HTTPException, RequestValidationError
43
from fastapi.params import Depends
54
from fastapi.responses import JSONResponse
65

Diff for: tests/test_daemon.py

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
from unittest import IsolatedAsyncioTestCase
2+
from unittest.mock import patch, MagicMock
3+
4+
from fastapi import HTTPException
5+
6+
from daemon import daemon
7+
from tests._utils import import_module, AsyncMock, mock_dict
8+
9+
10+
class TestDaemon(IsolatedAsyncioTestCase):
11+
def get_decorated_function(self, fastapi_patch: MagicMock, decorator_name, *decorator_args, **decorator_kwargs):
12+
functions = []
13+
decorator = MagicMock(side_effect=functions.append)
14+
getattr(fastapi_patch(), decorator_name).side_effect = (
15+
lambda *args, **kwargs: decorator if (args, kwargs) == (decorator_args, decorator_kwargs) else MagicMock()
16+
)
17+
fastapi_patch.reset_mock()
18+
19+
module = import_module("daemon.daemon")
20+
21+
decorator.assert_called_once()
22+
self.assertEqual(1, len(functions))
23+
return module, functions[0]
24+
25+
@patch("daemon.endpoints.register_collections")
26+
@patch("fastapi.FastAPI")
27+
async def test__global_vars(self, fastapi_patch: MagicMock, register_collections_patch: MagicMock):
28+
module = import_module("daemon.daemon")
29+
30+
fastapi_patch.assert_called_once_with(title="Python Daemon")
31+
self.assertEqual(fastapi_patch(), module.app)
32+
register_collections_patch.assert_called_once_with(fastapi_patch())
33+
self.assertEqual(register_collections_patch(), module.endpoints)
34+
35+
@patch("daemon.database.db")
36+
@patch("fastapi.FastAPI")
37+
async def test__db_session(self, fastapi_patch: MagicMock, db_patch: MagicMock):
38+
_, db_session = self.get_decorated_function(fastapi_patch, "middleware", "http")
39+
40+
events = []
41+
db_patch.create_session.side_effect = lambda: events.append(0)
42+
expected = MagicMock()
43+
call_next = AsyncMock(side_effect=lambda _: events.append(1) or expected)
44+
request = MagicMock()
45+
db_patch.commit = AsyncMock(side_effect=lambda: events.append(2))
46+
db_patch.close = AsyncMock(side_effect=lambda: events.append(3))
47+
48+
result = await db_session(request, call_next)
49+
50+
self.assertEqual([0, 1, 2, 3], events)
51+
call_next.assert_called_once_with(request)
52+
self.assertEqual(expected, result)
53+
54+
@patch("fastapi.FastAPI")
55+
async def test__on_startup__no_tables(self, fastapi_patch: MagicMock):
56+
module, on_startup = self.get_decorated_function(fastapi_patch, "on_event", "startup")
57+
58+
module.SQL_CREATE_TABLES = False
59+
db = module.db = AsyncMock()
60+
61+
await on_startup()
62+
63+
db.create_tables.assert_not_called()
64+
65+
@patch("fastapi.FastAPI")
66+
async def test__on_startup__create_tables(self, fastapi_patch: MagicMock):
67+
module, on_startup = self.get_decorated_function(fastapi_patch, "on_event", "startup")
68+
69+
module.SQL_CREATE_TABLES = True
70+
db = module.db = AsyncMock()
71+
72+
await on_startup()
73+
74+
db.create_tables.assert_called_once_with()
75+
76+
@patch("daemon.endpoint_collection.format_docs")
77+
@patch("daemon.schemas.daemon.EndpointCollectionModel")
78+
@patch("daemon.utils.responses")
79+
@patch("daemon.authorization.HTTPAuthorization")
80+
@patch("fastapi.params.Depends")
81+
@patch("fastapi.FastAPI")
82+
async def test__daemon_endpoints(
83+
self,
84+
fastapi_patch: MagicMock,
85+
depends_patch: MagicMock,
86+
httpauthorization_patch: MagicMock,
87+
responses_patch: MagicMock,
88+
endpoint_collection_model_patch: MagicMock,
89+
format_docs_patch: MagicMock,
90+
):
91+
format_docs_patch.side_effect = lambda f: setattr(f, "docs_formatted", True) or f # noqa: B010
92+
module, daemon_endpoints = self.get_decorated_function(
93+
fastapi_patch,
94+
"get",
95+
"/daemon/endpoints",
96+
name="List Daemon Endpoints",
97+
tags=["daemon"],
98+
dependencies=[[depends_patch(), depends_patch.reset_mock()][0]],
99+
responses=[responses_patch(), responses_patch.reset_mock()][0],
100+
)
101+
102+
httpauthorization_patch.assert_called_once_with()
103+
depends_patch.assert_called_once_with(httpauthorization_patch())
104+
responses_patch.assert_called_once_with(list[endpoint_collection_model_patch])
105+
self.assertEqual(True, daemon_endpoints.docs_formatted)
106+
107+
module.endpoints = MagicMock()
108+
self.assertEqual(module.endpoints, await daemon_endpoints())
109+
110+
@patch("daemon.daemon.JSONResponse")
111+
@patch("daemon.daemon.HTTPException")
112+
async def test__make_exception(self, httpexception_patch: MagicMock, jsonresponse_patch: MagicMock):
113+
status_code = MagicMock()
114+
kwargs = mock_dict(5, True)
115+
116+
result = daemon._make_exception(status_code, **kwargs)
117+
118+
httpexception_patch.assert_called_once_with(status_code)
119+
jsonresponse_patch.assert_called_once_with(
120+
{**kwargs, "error": f"{status_code} {httpexception_patch().detail}"},
121+
status_code,
122+
)
123+
self.assertEqual(jsonresponse_patch(), result)
124+
125+
@patch("daemon.exceptions.api_exception.APIException")
126+
@patch("fastapi.FastAPI")
127+
async def test__handle_api_exception(self, fastapi_patch: MagicMock, apiexception_patch: MagicMock):
128+
_, handle_api_exception = self.get_decorated_function(fastapi_patch, "exception_handler", apiexception_patch)
129+
exception = MagicMock()
130+
131+
result = await handle_api_exception(..., exception)
132+
133+
exception.make_response.assert_called_once_with()
134+
self.assertEqual(exception.make_response(), result)
135+
136+
@patch("fastapi.exceptions.HTTPException")
137+
@patch("fastapi.FastAPI")
138+
async def test__handle_http_exception(self, fastapi_patch: MagicMock, httpexception_patch: MagicMock):
139+
module, handle_http_exception = self.get_decorated_function(
140+
fastapi_patch,
141+
"exception_handler",
142+
httpexception_patch,
143+
)
144+
exception = MagicMock()
145+
_make_exception, module._make_exception = module._make_exception, MagicMock()
146+
147+
result = await handle_http_exception(..., exception)
148+
149+
module._make_exception.assert_called_once_with(exception.status_code)
150+
self.assertEqual(module._make_exception(), result)
151+
module._make_exception = _make_exception
152+
153+
@patch("fastapi.exceptions.RequestValidationError")
154+
@patch("fastapi.FastAPI")
155+
async def test__handle_unprocessable_entity(
156+
self,
157+
fastapi_patch: MagicMock,
158+
request_validation_error_patch: MagicMock,
159+
):
160+
module, handle_unprocessable_entity = self.get_decorated_function(
161+
fastapi_patch,
162+
"exception_handler",
163+
request_validation_error_patch,
164+
)
165+
exception = MagicMock()
166+
_make_exception, module._make_exception = module._make_exception, MagicMock()
167+
168+
result = await handle_unprocessable_entity(..., exception)
169+
170+
exception.errors.assert_called_once_with()
171+
module._make_exception.assert_called_once_with(422, detail=exception.errors())
172+
self.assertEqual(module._make_exception(), result)
173+
module._make_exception = _make_exception
174+
175+
@patch("fastapi.FastAPI")
176+
async def test__handle_internal_server_error(self, fastapi_patch: MagicMock):
177+
module, handle_internal_server_error = self.get_decorated_function(
178+
fastapi_patch,
179+
"exception_handler",
180+
Exception,
181+
)
182+
exception = MagicMock()
183+
_make_exception, module._make_exception = module._make_exception, MagicMock()
184+
185+
result = await handle_internal_server_error(..., exception)
186+
187+
module._make_exception.assert_called_once_with(500)
188+
self.assertEqual(module._make_exception(), result)
189+
module._make_exception = _make_exception
190+
191+
@patch("fastapi.FastAPI")
192+
async def test__handle_not_found(self, fastapi_patch: MagicMock):
193+
module, handle_not_found = self.get_decorated_function(
194+
fastapi_patch,
195+
"get",
196+
"/{_:path}",
197+
include_in_schema=False,
198+
)
199+
200+
with self.assertRaises(HTTPException) as context:
201+
await handle_not_found()
202+
203+
self.assertEqual(404, context.exception.status_code)

0 commit comments

Comments
 (0)