mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-05-23 05:56:19 +03:00
Add tests
This commit is contained in:
parent
b3c62f5fd7
commit
e6c9181fc5
|
@ -7,11 +7,11 @@ monitors:
|
||||||
example:
|
example:
|
||||||
method: "GET"
|
method: "GET"
|
||||||
url: "http://example.com"
|
url: "http://example.com"
|
||||||
|
timeout: 5
|
||||||
check_every: 5
|
check_every: 5
|
||||||
expected_codes: [200]
|
|
||||||
|
|
||||||
httpbin:
|
httpbin:
|
||||||
method: "GET"
|
method: "GET"
|
||||||
url: "http://httpbin.org/get"
|
url: "http://httpbin.org/get"
|
||||||
|
timeout: 5
|
||||||
check_every: 5
|
check_every: 5
|
||||||
expected_codes: [200]
|
|
||||||
|
|
|
@ -16,27 +16,32 @@ class Dispatcher:
|
||||||
|
|
||||||
def __init__(self, monitors: List[Monitor]) -> None:
|
def __init__(self, monitors: List[Monitor]) -> None:
|
||||||
self._monitors = monitors
|
self._monitors = monitors
|
||||||
self._monitor_tasks: List[asyncio.Task] = [] # type: ignore
|
self._monitor_tasks: List[asyncio.Task] = []
|
||||||
self._stopping = False
|
self._stopping = False
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
asyncio.run(self._do_work())
|
asyncio.run(self.start())
|
||||||
|
|
||||||
async def _do_work(self) -> None:
|
async def start(self) -> None:
|
||||||
logger.info('Dispatcher is starting up')
|
logger.info('Dispatcher is starting up')
|
||||||
|
|
||||||
for monitor in self._monitors:
|
for monitor in self._monitors:
|
||||||
self._monitor_tasks.append(asyncio.create_task(self._run_monitor(monitor)))
|
self._monitor_tasks.append(
|
||||||
logger.info('Monitoring task has been started %s', monitor.full_name)
|
asyncio.create_task(self._run_monitor(monitor)),
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
'Monitoring task has been started %s',
|
||||||
|
monitor.full_name,
|
||||||
|
)
|
||||||
|
|
||||||
asyncio.get_event_loop().add_signal_handler(signal.SIGTERM, self._stop)
|
asyncio.get_event_loop().add_signal_handler(signal.SIGTERM, self.stop)
|
||||||
asyncio.get_event_loop().add_signal_handler(signal.SIGINT, self._stop)
|
asyncio.get_event_loop().add_signal_handler(signal.SIGINT, self.stop)
|
||||||
|
|
||||||
await asyncio.gather(*self._monitor_tasks, return_exceptions=True)
|
await asyncio.gather(*self._monitor_tasks, return_exceptions=True)
|
||||||
|
|
||||||
self._stop()
|
self.stop()
|
||||||
|
|
||||||
def _stop(self) -> None:
|
def stop(self) -> None:
|
||||||
if self._stopping:
|
if self._stopping:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
"""Http client module."""
|
"""Http client module."""
|
||||||
|
|
||||||
from aiohttp import ClientSession, ClientResponse
|
from aiohttp import ClientSession, ClientTimeout, ClientResponse
|
||||||
|
|
||||||
|
|
||||||
class HttpClient:
|
class HttpClient:
|
||||||
|
|
||||||
async def request(self, method: str, url: str) -> ClientResponse:
|
async def request(self, method: str, url: str, timeout: int) -> ClientResponse:
|
||||||
async with ClientSession() as session:
|
async with ClientSession(timeout=ClientTimeout(timeout)) as session:
|
||||||
async with session.request(method, url) as response:
|
async with session.request(method, url) as response:
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Monitors module."""
|
"""Monitors module."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
|
|
||||||
from .http import HttpClient
|
from .http import HttpClient
|
||||||
|
@ -30,7 +31,7 @@ class HttpMonitor(Monitor):
|
||||||
self._client = http_client
|
self._client = http_client
|
||||||
self._method = options.pop('method')
|
self._method = options.pop('method')
|
||||||
self._url = options.pop('url')
|
self._url = options.pop('url')
|
||||||
self._expected_codes = options.pop('expected_codes')
|
self._timeout = options.pop('timeout')
|
||||||
super().__init__(check_every=options.pop('check_every'))
|
super().__init__(check_every=options.pop('check_every'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -38,5 +39,20 @@ class HttpMonitor(Monitor):
|
||||||
return '{0}.{1}(url="{2}")'.format(__name__, self.__class__.__name__, self._url)
|
return '{0}.{1}(url="{2}")'.format(__name__, self.__class__.__name__, self._url)
|
||||||
|
|
||||||
async def check(self) -> None:
|
async def check(self) -> None:
|
||||||
response = await self._client.request(method=self._method, url=self._url)
|
time_start = time.time()
|
||||||
self.logger.info('Return response code: %s', response.status)
|
|
||||||
|
response = await self._client.request(
|
||||||
|
method=self._method,
|
||||||
|
url=self._url,
|
||||||
|
timeout=self._timeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
time_end = time.time()
|
||||||
|
time_took = time_end - time_start
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
'Response code: %s, content length: %s, request took: %s seconds',
|
||||||
|
response.status,
|
||||||
|
response.content_length,
|
||||||
|
round(time_took, 3)
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
"""Tests module."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import dataclasses
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from .containers import ApplicationContainer
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG = {
|
||||||
|
'log': {
|
||||||
|
'level': 'INFO',
|
||||||
|
'formant': '[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s',
|
||||||
|
},
|
||||||
|
'monitors': {
|
||||||
|
'example': {
|
||||||
|
'method': 'GET',
|
||||||
|
'url': 'http://fake-example.com',
|
||||||
|
'timeout': 1,
|
||||||
|
'check_every': 1,
|
||||||
|
},
|
||||||
|
'httpbin': {
|
||||||
|
'method': 'GET',
|
||||||
|
'url': 'http://fake-httpbin.org/get',
|
||||||
|
'timeout': 1,
|
||||||
|
'check_every': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class RequestStub:
|
||||||
|
status: int
|
||||||
|
content_length: int
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def container():
|
||||||
|
container = ApplicationContainer()
|
||||||
|
container.config.from_dict(CONFIG)
|
||||||
|
return container
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_example_monitor(container, caplog):
|
||||||
|
caplog.set_level('INFO')
|
||||||
|
|
||||||
|
http_client_mock = mock.AsyncMock()
|
||||||
|
http_client_mock.request.return_value = RequestStub(
|
||||||
|
status=200,
|
||||||
|
content_length=635,
|
||||||
|
)
|
||||||
|
|
||||||
|
with container.http_client.override(http_client_mock):
|
||||||
|
example_monitor = container.example_monitor()
|
||||||
|
await example_monitor.check()
|
||||||
|
|
||||||
|
assert 'http://fake-example.com' in caplog.text
|
||||||
|
assert 'Response code: 200' in caplog.text
|
||||||
|
assert 'content length: 635' in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_httpbin_monitor(container, caplog):
|
||||||
|
caplog.set_level('INFO')
|
||||||
|
|
||||||
|
http_client_mock = mock.AsyncMock()
|
||||||
|
http_client_mock.request.return_value = RequestStub(
|
||||||
|
status=200,
|
||||||
|
content_length=482,
|
||||||
|
)
|
||||||
|
|
||||||
|
with container.http_client.override(http_client_mock):
|
||||||
|
httpbin_monitor = container.httpbin_monitor()
|
||||||
|
await httpbin_monitor.check()
|
||||||
|
|
||||||
|
assert 'http://fake-httpbin.org/get' in caplog.text
|
||||||
|
assert 'Response code: 200' in caplog.text
|
||||||
|
assert 'content length: 482' in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_dispatcher(container, caplog, event_loop):
|
||||||
|
caplog.set_level('INFO')
|
||||||
|
|
||||||
|
example_monitor_mock = mock.AsyncMock()
|
||||||
|
httpbin_monitor_mock = mock.AsyncMock()
|
||||||
|
|
||||||
|
with container.example_monitor.override(example_monitor_mock), \
|
||||||
|
container.httpbin_monitor.override(httpbin_monitor_mock):
|
||||||
|
|
||||||
|
dispatcher = container.dispatcher()
|
||||||
|
event_loop.create_task(dispatcher.start())
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
dispatcher.stop()
|
||||||
|
|
||||||
|
assert example_monitor_mock.check.called
|
||||||
|
assert httpbin_monitor_mock.check.called
|
|
@ -1,3 +1,6 @@
|
||||||
dependency-injector
|
dependency-injector
|
||||||
aiohttp
|
aiohttp
|
||||||
pyyaml
|
pyyaml
|
||||||
|
pytest
|
||||||
|
pytest-asyncio
|
||||||
|
pytest-cov
|
||||||
|
|
Loading…
Reference in New Issue
Block a user