diff --git a/.gitignore b/.gitignore index 0d6a243..a5a03cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .vscode dist -*.egg-info \ No newline at end of file +*.egg-info +__pycache__ +venv +.tox +tox.ini \ No newline at end of file diff --git a/gotify_message/gotify_connector.py b/gotify_message/gotify_connector.py new file mode 100644 index 0000000..c38055d --- /dev/null +++ b/gotify_message/gotify_connector.py @@ -0,0 +1,96 @@ +import logging +import requests +import json + +LOG = logging.getLogger(__name__) + + +class GotifyConnector: + URL = None + TOKEN = None + + def __init__( + self, + url: str = None, + token: str = None + ): + + self.url = (url or self.URL) + self.token = (token or self.TOKEN) + self._check_status() + + def _get(self, resource, timeout: int = None) -> dict: + headers = {"X-Gotify-Key": self.token} + url = self.url + resource + response = requests.get(url, headers=headers, timeout=timeout) + + if response.ok: + return response.json() + else: + error = ( + f"'{url}' response error:\n" + + json.dumps(response.json(), indent=3) + ) + LOG.error(error) + return None + + def _post( + self, + resource: dict = None, + payload: dict = None, + headers: dict = None, + ) -> dict: + + _headers = { + "X-Gotify-Key": self.token, + "Content-type": "application/json" + } + if headers: + _headers |= headers + url = self.url + resource + response = requests.post(url, headers=_headers, json=payload) + + if response.ok: + return response.json() + else: + error = ( + f"'{url}' response error:\n" + + json.dumps(response.json(), indent=3) + ) + LOG.error(error) + return None + + @property + def health(self) -> str: + response = self._get("/health", timeout=10) + status = response.get("health") + return status + + @property + def database(self) -> str: + response = self._get("/health", timeout=10) + status = response.get("database") + return status + + def _check_status(self): + if self.health != "green": + log_msg = ( + f"Gotify service {self.url} health probblem: {self.health}" + ) + LOG.warning(log_msg) + else: + log_msg = ( + f"Gotify service {self.url} health status: {self.health}" + ) + LOG.debug(log_msg) + + if self.database != "green": + log_msg = ( + f"Gotify service {self.url} database probblem: {self.database}" + ) + LOG.warning(log_msg) + else: + log_msg = ( + f"Gotify service {self.url} database status: {self.database}" + ) + LOG.debug(log_msg) diff --git a/gotify_message/gotify_notification.py b/gotify_message/gotify_notification.py index eccfe90..1aadd38 100644 --- a/gotify_message/gotify_notification.py +++ b/gotify_message/gotify_notification.py @@ -1,14 +1,14 @@ -import requests import json +from .gotify_connector import GotifyConnector -class GotifyNotification: +class GotifyNotification(GotifyConnector): """Basic gotify notification class :param url: gotify server url :type url: str - :param app_token: token to which application send a message - :type app_token: str + :param token: token to which application send a message + :type token: str :param title: title of the message :type title: str :param message: message @@ -16,24 +16,20 @@ class GotifyNotification: :param priority: message priority, defaults to 5 :type priority: int, optional """ - CONTENT_TYPE = 'plain' def __init__( self, - url, - app_token: str, + url: str = None, + token: str = None, title: str = None, message: str = None, priority: int = 5 ): """Constructor method""" - self.url = url + '/message' - self.headers = { - "X-Gotify-Key": app_token, - "Content-type": 'application/json' - } + super().__init__(url, token) + self.payload = { "title": title, "priority": priority, @@ -46,20 +42,22 @@ def __init__( } self.delivered = False - def send(self, - message: str = None, - title: str = None, - priority: int = None) -> requests.models.Response: + def send( + self, + message: str = None, + title: str = None, + priority: int = None + ) -> bool: """sends message to gotify server - :param title: title of the message - :type title: str :param message: message :type message: str + :param title: title of the message + :type title: str :param priority: message priority, defaults to 5 :type priority: int, optional - :return: _description_ - :rtype: response.Request + :return: True is message delivered + :rtype: bool """ if message: @@ -69,14 +67,10 @@ def send(self, if priority: self.payload['priority'] = priority - response = requests.post( - self.url, - headers=self.headers, - json=self.payload - ) - if response.ok: + if self._post("/message", self.payload): self.delivered = True - return response + + return self.delivered @property def json(self) -> str: diff --git a/tests/pytest1.py b/tests/pytest1.py new file mode 100644 index 0000000..5edbd8e --- /dev/null +++ b/tests/pytest1.py @@ -0,0 +1,103 @@ +import unittest +import pytest +from unittest import mock +from gotify_message.gotify_connector import requests +from gotify_message.gotify_connector import GotifyConnector + +URL = "http://10.0.0.7:8090" +TOKEN = "tokenASDASDA" + + +@pytest.fixture +def url(): + return URL + +@pytest.fixture +def token(): + return TOKEN + +@pytest.fixture +def health_response(): + return {'health': 'green', 'database': 'green'} + +def mock_response(fail = None): + def request(method, **kwargs): + response = requests.Response() + request = requests.Request(method) + response.status_code = 200 + for attr in kwargs: + if hasattr(request, attr): + setattr(request, attr, kwargs[attr]) + response.request = request + if fail: + response._content = b'{"health":"red","database":"red"}' + else: + response._content = b'{"health":"green","database":"green"}' + return response + return request + + +@pytest.fixture +def gotify_connector(url, token, health_response): + with mock.patch("requests.get", new=mock.MagicMock()): + requests.get().json.return_value = health_response + requests.get().ok = True + yield GotifyConnector(url, token) + +@pytest.fixture +def gotify_connector_mock_response(url, token): + with mock.patch("requests.get", new=mock_response()): + yield GotifyConnector(url, token) + +@pytest.fixture +def gotify_connector_mock_response_fail(url, token): + with mock.patch("requests.get", side_effect=mock_response(fail=True)): + yield GotifyConnector(url, token) + +class TestConnector: + + def test_constructor(self, gotify_connector): + assert gotify_connector.url == "http://10.0.0.7:8090" + assert gotify_connector.token == "tokenASDASDA" + assert gotify_connector.health == "green" + assert gotify_connector.database == "green" + + def test_constructor_2(self): + with mock.patch("requests.get"): + requests.get().json.return_value = {'health': 'green', 'database': 'green'} + requests.get().ok = True + gotify_connector = GotifyConnector("http://10.0.0.7:8090","tokenASDASDA") + assert gotify_connector.url == "http://10.0.0.7:8090" + assert gotify_connector.token == "tokenASDASDA" + assert gotify_connector.health == "green" + assert gotify_connector.database == "green" + + def test_constructor_3(self): + with mock.patch("requests.get"): + requests.get.side_effect = requests.exceptions.HTTPError + with pytest.raises(requests.exceptions.HTTPError): + gotify_connector = GotifyConnector("http://10.0.0.7:8090","tokenASDASDA") + + + def test_constructor_mock_response(self, gotify_connector_mock_response): + assert gotify_connector_mock_response.url == "http://10.0.0.7:8090" + assert gotify_connector_mock_response.token == "tokenASDASDA" + assert gotify_connector_mock_response.health == "green" + assert gotify_connector_mock_response.database == "green" + + def test_constructor_mock_response_fail(self, gotify_connector_mock_response_fail): + assert gotify_connector_mock_response_fail.url == "http://10.0.0.7:8090" + assert gotify_connector_mock_response_fail.token == "tokenASDASDA" + assert gotify_connector_mock_response_fail.health == "red" + assert gotify_connector_mock_response_fail.database == "red" + + @mock.patch("requests.get", side_effect=mock_response(fail=True)) + def test_constructor_1(self, m__get): + client = GotifyConnector("http://10.0.0.7:8090", "daskjdsakjn") + assert client.url == "http://10.0.0.7:8090" + assert client.token == "daskjdsakjn" + assert client.health == "red" + assert client.database == "red" + + + diff --git a/tests/test_connector.py b/tests/test_connector.py new file mode 100644 index 0000000..e0d2339 --- /dev/null +++ b/tests/test_connector.py @@ -0,0 +1,44 @@ +from pytest import fixture,raises +from mock import patch +from gotify_message.gotify_connector import requests +from gotify_message.gotify_connector import GotifyConnector + + +URL="http://1.2.3.4:8888" +TOKEN="lskd12314sadf1" + + + + +@fixture +@patch("requests.get") +def gotify_connector2(m__get): + m__get().json.return_value = {'health': 'green', 'database': 'green'} + m__get().ok = True + yield GotifyConnector(URL, TOKEN) + + +def mock_get(**kwargs): + request = requests.Request(**kwargs) + response = requests.Response() + response.status_code = 200 + response._content = {'health': 'green', 'database': 'green'} + return request + +@fixture +def gotify_connector(): + with patch("requests.get"): + requests.get().json.return_value = {'health': 'green', 'database': 'green'} + requests.get().ok= True + yield GotifyConnector(URL, TOKEN) + +def test_connector(gotify_connector): + assert gotify_connector.health == "green" + assert gotify_connector.database == "green" + + +def test_1(): + with patch("requests.get", new=mock_get): + requests.get(method="GET") + + diff --git a/tests/unittest.py b/tests/unittest.py new file mode 100644 index 0000000..1bce47b --- /dev/null +++ b/tests/unittest.py @@ -0,0 +1,72 @@ +from unittest import TestCase, mock +from gotify_message import GotifyNotification +from gotify_message.gotify_connector import GotifyConnector +from gotify_message.gotify_connector import requests + + +class TestGotifyNotification(TestCase): + URL = "http://10.0.0.7:8090" + RESOURCE = "/message" + HEADERS = { + "X-Gotify-Key": "AiOLxxDxYOCc7bY", + "Content-type": 'application/json' + } + PAYLOAD = { + "title": "test_title", + "priority": 8, + "message": "test_message", + "extras": { + "client::display": { + "contentType": "text/plain" + } + } + } + + @mock.patch("requests.post") + @mock.patch("requests.get") + def test_notification(self, m__post, m__get): + + m__get().ok = True + m__get().json.return_value = {'health': 'green', 'database': 'green'} + + m__post().ok = True + m__post().json.return_value = {'health': 'green', 'database': 'green'} + + + message = GotifyNotification( + "http://10.0.0.7:8090", + "AiOLxxDxYOCc7bY", + "test_title", + "test_message", 8 + ) + assert message.url == self.URL + assert message.payload == self.PAYLOAD + assert message.delivered is False + + + message.send() + requests.post.assert_called_with( + self.URL + self.RESOURCE, + headers=self.HEADERS, + json=self.PAYLOAD + ) + assert requests.post().ok is True + assert message.delivered is True + + def test_arguments_number(self): + with self.assertRaises(TypeError): + GotifyNotification(12345) + + +class TestGotifyConnector(TestCase): + + @mock.patch("requests.get") + def test_constructor(self, m__get): + m__get().ok = True + m__get().json.return_value = {'health': 'green', 'database': 'green'} + client = GotifyConnector("http://1.1.1.1:8888", "tokenASDASDA") + assert client.token == "tokenASDASDA" + + +if __name__ == '__main__': + unittest.main()