From 16723317002ef55681cbb318836c787f27464cfb Mon Sep 17 00:00:00 2001 From: Scott Wallace Date: Wed, 28 Oct 2020 17:31:29 +0000 Subject: [PATCH] Resolve #8: Add beginnings of a test framework --- alertify.py | 6 +- src/alertify/config.py | 2 +- src/alertify/gotify.py | 2 +- src/alertify/healthcheck.py | 3 +- src/alertify/server.py | 1 + src/conftest.py | 0 src/tests/alertify/test___init__.py | 22 +++++ src/tests/alertify/test_config.py | 54 +++++++++++++ src/tests/alertify/test_gotify.py | 106 +++++++++++++++++++++++++ src/tests/alertify/test_healthcheck.py | 54 +++++++++++++ src/tests/alertify/test_messaging.py | 49 ++++++++++++ src/tests/alertify/test_server.py | 32 ++++++++ 12 files changed, 324 insertions(+), 7 deletions(-) create mode 100644 src/conftest.py create mode 100644 src/tests/alertify/test___init__.py create mode 100644 src/tests/alertify/test_config.py create mode 100644 src/tests/alertify/test_gotify.py create mode 100644 src/tests/alertify/test_healthcheck.py create mode 100644 src/tests/alertify/test_messaging.py create mode 100644 src/tests/alertify/test_server.py diff --git a/alertify.py b/alertify.py index 906477a..95e9669 100644 --- a/alertify.py +++ b/alertify.py @@ -59,14 +59,14 @@ if __name__ == '__main__': # forwarder = alertify.Alertify(args.config) forwarder = alertify.Alertify() - #----------------------------- + # ----------------------------- # Calculate logging level - #----------------------------- + # ----------------------------- # Config :: Verbose: 0 = WARNING, 1 = INFO, 2 = DEBUG # Logging :: Loglevel: 30 = WARNING, 20 = INFO, 10 = DEBUG logger = logging.getLogger() logger.setLevel(30 - (forwarder.config.verbose * 10)) - #----------------------------- + # ----------------------------- if args.healthcheck: # Invert the sense of 'healthy' for Unix CLI usage diff --git a/src/alertify/config.py b/src/alertify/config.py index 86cd9bb..e4fbf1c 100644 --- a/src/alertify/config.py +++ b/src/alertify/config.py @@ -59,7 +59,7 @@ class Config: @classmethod def keys(cls): """ - Method to return the defaults as a list of keys + Method to return the defaults as a list of dict_keys """ return [ attr[0] diff --git a/src/alertify/gotify.py b/src/alertify/gotify.py index 2ae6e0a..0dbb841 100644 --- a/src/alertify/gotify.py +++ b/src/alertify/gotify.py @@ -64,7 +64,7 @@ class Gotify: """ Method to delete a message from the Gotify server """ - logging.debug('Deleting message ID: %s', msg_id) + logging.info('Deleting message ID: %s', msg_id) return self._call('DELETE', f'/message/{msg_id}') def find_byfingerprint(self, message): diff --git a/src/alertify/healthcheck.py b/src/alertify/healthcheck.py index 5be876a..541f19b 100644 --- a/src/alertify/healthcheck.py +++ b/src/alertify/healthcheck.py @@ -15,10 +15,9 @@ class Healthcheck: """ Simple method to return a boolean state of the general health """ - return all( [ - self.gotify.healthcheck(), + self.gotify_alive(), ] ) diff --git a/src/alertify/server.py b/src/alertify/server.py index 6f6921b..fd2658e 100644 --- a/src/alertify/server.py +++ b/src/alertify/server.py @@ -31,6 +31,7 @@ class Server: try: with HTTPServer(('', self.port), http_handler) as webserver: webserver.serve_forever() + return True except KeyboardInterrupt: logging.info('Exiting') diff --git a/src/conftest.py b/src/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/alertify/test___init__.py b/src/tests/alertify/test___init__.py new file mode 100644 index 0000000..f45cfc0 --- /dev/null +++ b/src/tests/alertify/test___init__.py @@ -0,0 +1,22 @@ +"""Test""" +import unittest + + +class AlertifyTest(unittest.TestCase): + """ + Tests for methods in the Alertify class. + """ + + @classmethod + def setUpClass(cls): + pass + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + pass + + def tearDown(self): + pass diff --git a/src/tests/alertify/test_config.py b/src/tests/alertify/test_config.py new file mode 100644 index 0000000..242285e --- /dev/null +++ b/src/tests/alertify/test_config.py @@ -0,0 +1,54 @@ +"""Test""" +import unittest + +from alertify import config # pylint: disable=import-error + + +class ConfigTest(unittest.TestCase): + """ + Tests for methods in the Config class. + """ + + @classmethod + def setUpClass(cls): + cls.defaults = { + 'delete_onresolve': bool(False), + 'disable_resolved': bool(False), + 'gotify_key_app': str(), + 'gotify_key_client': str(), + 'gotify_port': int(80), + 'gotify_server': str('localhost'), + 'listen_port': int(8080), + 'verbose': int(0), + } + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_items(self): + """Test""" + self.assertEqual( + config.Config().items(), + self.defaults.items(), + ) + + def test_keys(self): + """Test""" + self.assertListEqual( + config.Config.keys(), + list(self.defaults.keys()), + ) + + def test_defaults(self): + """Test""" + self.assertDictEqual( + config.Config.defaults(), + self.defaults, + ) diff --git a/src/tests/alertify/test_gotify.py b/src/tests/alertify/test_gotify.py new file mode 100644 index 0000000..c6e4918 --- /dev/null +++ b/src/tests/alertify/test_gotify.py @@ -0,0 +1,106 @@ +""" +Module to handle unit tests for the alertify.gotify module +""" +import unittest +from unittest.mock import patch + +from alertify import gotify # pylint: disable=import-error + + +class GotifyTest(unittest.TestCase): + """ + Tests for methods in the Gotify class. + """ + + @classmethod + def setUpClass(cls): + cls.gotify_client = gotify.Gotify('', 0, '', '') + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('http.client.HTTPConnection.request') + @patch('http.client.HTTPConnection.getresponse') + @patch('http.client.HTTPResponse.read') + def test_delete(self, mock_request, mock_getresponse, mock_read): + """Test""" + mock_request.return_value.status = {} + mock_getresponse.return_value.status = 200 + mock_getresponse.return_value.reason = 'OK' + mock_read.return_value = {} + + self.assertDictEqual( + self.gotify_client.delete('123'), + { + 'status': 200, + 'reason': 'OK', + 'json': None, + }, + ) + + @patch('alertify.gotify.Gotify.messages') + def test_find_byfingerprint(self, mock_messages): + """Test""" + mock_messages.return_value = [ + { + 'id': 42, + 'extras': {'alertify': {'fingerprint': 'deadbeefcafebabe'}}, + } + ] + + self.assertEqual( + self.gotify_client.find_byfingerprint({'fingerprint': 'deadbeefcafebabe'}), + 42, + ) + + def test_messages(self): + """Test""" + self.assertListEqual( + self.gotify_client.messages(), + [], + ) + + @patch('http.client.HTTPConnection.request') + @patch('http.client.HTTPConnection.getresponse') + @patch('http.client.HTTPResponse.read') + def test_send_alert(self, mock_request, mock_getresponse, mock_read): + """Test""" + mock_request.return_value.status = {} + mock_getresponse.return_value.status = 200 + mock_getresponse.return_value.reason = 'OK' + mock_read.return_value = {} + + self.assertDictEqual( + self.gotify_client.send_alert({}), + { + 'status': 200, + 'reason': 'OK', + 'json': None, + }, + ) + + @patch('http.client.HTTPConnection.request') + @patch('http.client.HTTPConnection.getresponse') + @patch('http.client.HTTPResponse.read') + def test_healthcheck(self, mock_request, mock_getresponse, mock_read): + """Test""" + mock_request.return_value.status = {} + mock_getresponse.return_value.status = 200 + mock_getresponse.return_value.reason = 'OK' + mock_read.return_value = {} + + self.assertDictEqual( + self.gotify_client.healthcheck(), + { + 'status': 200, + 'reason': 'OK', + 'json': None, + }, + ) diff --git a/src/tests/alertify/test_healthcheck.py b/src/tests/alertify/test_healthcheck.py new file mode 100644 index 0000000..42223c2 --- /dev/null +++ b/src/tests/alertify/test_healthcheck.py @@ -0,0 +1,54 @@ +"""Test""" +import unittest +from unittest.mock import patch + +from alertify import healthcheck, gotify # pylint: disable=import-error + + +class HealthcheckTest(unittest.TestCase): + """ + Tests for methods in the Healthcheck class. + """ + + @classmethod + def setUpClass(cls): + cls.healthcheck = healthcheck.Healthcheck(gotify.Gotify('', 0, '', '')) + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('alertify.healthcheck.Healthcheck.gotify_alive') + def test_report(self, mock_healthcheck): + """Test""" + mock_healthcheck.return_value = { + 'status': 200, + 'reason': 'OK', + 'json': None, + } + + self.assertTrue(self.healthcheck.report()) + + @patch('alertify.healthcheck.Healthcheck.gotify_alive') + def test_gotify_alive(self, mock_healthcheck): + """Test""" + mock_healthcheck.return_value = { + 'status': 200, + 'reason': 'OK', + 'json': None, + } + + self.assertDictEqual( + self.healthcheck.gotify_alive(), + { + 'status': 200, + 'reason': 'OK', + 'json': None, + }, + ) diff --git a/src/tests/alertify/test_messaging.py b/src/tests/alertify/test_messaging.py new file mode 100644 index 0000000..73517e2 --- /dev/null +++ b/src/tests/alertify/test_messaging.py @@ -0,0 +1,49 @@ +"""Test""" +import unittest +from unittest.mock import patch + +from alertify import messaging, gotify # pylint: disable=import-error + + +class MessageHandlerTest(unittest.TestCase): + """ + Tests for methods in the MessageHandler class. + """ + + @classmethod + def setUpClass(cls): + cls.messaging = messaging.MessageHandler(gotify.Gotify('', 0, '', '')) + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('alertify.gotify.Gotify.send_alert') + def test_process(self, mock_send_alert): + """Test""" + mock_send_alert.return_value = { + 'status': 200, + 'reason': 'OK', + 'json': None, + } + + self.assertDictEqual( + self.messaging.process( + { + 'status': 'firing', + 'labels': {}, + 'annotations': {}, + } + ), + { + 'status': 200, + 'reason': 'OK', + 'json': None, + }, + ) diff --git a/src/tests/alertify/test_server.py b/src/tests/alertify/test_server.py new file mode 100644 index 0000000..9920560 --- /dev/null +++ b/src/tests/alertify/test_server.py @@ -0,0 +1,32 @@ +"""Test""" +import unittest +from unittest.mock import patch + +from alertify import server # pylint: disable=import-error + + +class ServerTest(unittest.TestCase): + """ + Tests for methods in the Server class. + """ + + @classmethod + def setUpClass(cls): + cls.server = server.Server(0, None, None) + + @classmethod + def tearDownClass(cls): + pass + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('http.server.HTTPServer.serve_forever') + def test_listen_and_run(self, mock_serve_forever): + """Test""" + mock_serve_forever.return_value = True + + self.assertTrue(self.server.listen_and_run())