From 8ad5cf356a6f98835c6e1f046d6e04f5c5ec43f6 Mon Sep 17 00:00:00 2001 From: Jiri Podivin Date: Wed, 3 Feb 2021 17:39:10 +0100 Subject: [PATCH] Simple tests for validation_stdout callback. Signed-off-by: Jiri Podivin Change-Id: Ide2db5e6bc0443ed52a884024753e4123090947f --- .../test_validation_stdout.py | 163 +++++++++++++++++- 1 file changed, 162 insertions(+), 1 deletion(-) diff --git a/validations_common/tests/callback_plugins/test_validation_stdout.py b/validations_common/tests/callback_plugins/test_validation_stdout.py index f7f2c22..95ee390 100644 --- a/validations_common/tests/callback_plugins/test_validation_stdout.py +++ b/validations_common/tests/callback_plugins/test_validation_stdout.py @@ -19,15 +19,176 @@ test_validation_stdout Tests for `validation_stdout` callback plugin. """ +import os +import re +from unittest import mock +from ansible.plugins.callback import CallbackBase import validations_common.library.reportentry as validation +from validations_common.callback_plugins import validation_stdout from validations_common.tests import base -from unittest import mock + +def is_iso_time(time_string): + """ + Checks if string represents valid time in ISO format, + with the default delimiter. + Regex is somewhat convoluted, but general enough to last + at least until the 9999 AD. + Returns: + True if string matches the pattern. + False otherwise. + """ + match = re.match( + r'\d{4}-[01][0-9]-[0-3][0-9]T[0-3][0-9](:[0-5][0-9]){2}\.\d+Z', + time_string) + + if match: + return True + else: + return False class TestValidationStdout(base.TestCase): + """Tests of validation_stdout callback module. + """ def setUp(self): super(TestValidationStdout, self).setUp() self.module = mock.MagicMock() + + def test_callback_instantiation(self): + """ + Verifying that the CallbackModule is instantiated properly. + Test checks presence of CallbackBase in the inheritance chain, + in order to ensure that folowing tests are performed with + the correct assumptions. + """ + callback = validation_stdout.CallbackModule() + + self.assertEqual(type(callback).__mro__[1], CallbackBase) + + """ + Every ansible callback needs to define variable with name and version. + """ + self.assertIn('CALLBACK_NAME', dir(callback)) + self.assertIn('CALLBACK_VERSION', dir(callback)) + + self.assertEqual(callback.CALLBACK_NAME, 'validation_stdout') + + self.assertIsInstance(callback.CALLBACK_VERSION, float) + + """ + Additionally, the 'validation_stdout' callback performs several + other operations during instantiation. + """ + + self.assertEqual(callback.env, {}) + self.assertIsNone(callback.t0) + """ + Callback time sanity check only verifies general format + of the stored time to be iso format `YYYY-MM-DD HH:MM:SS.mmmmmm` + with 'T' as a separator. + For example: '2020-07-03T13:28:21.224103Z' + """ + self.assertTrue(is_iso_time(callback.current_time)) + + @mock.patch( + 'ansible.playbook.play.Play._uuid', + autospec=True, + return_value='bar') + @mock.patch( + 'ansible.playbook.play.Play.get_name', + autospec=True, + return_value='foo') + @mock.patch('ansible.playbook.play.Play') + def test_new_play(self, mock_play, mock_play_name, mock_play_uuid): + """ + From the callback point of view, + both Play and Task are virtually identical. + Test involving them are therefore also very similar. + """ + callback = validation_stdout.CallbackModule() + callback.env['playbook_name'] = 'fizz' + callback.env['playbook_path'] = 'buzz/fizz' + + play_dict = callback._new_play(mock_play) + + mock_play_name.assert_called_once() + mock_play_uuid.assert_called_once() + + """ + Callback time sanity check only verifies general format + of the stored time to be iso format `YYYY-MM-DD HH:MM:SS.mmmmmm` + with 'T' as a separator. + For example: '2020-07-03T13:28:21.224103Z' + """ + self.assertTrue(is_iso_time(play_dict['play']['duration']['start'])) + + self.assertEqual('fizz', play_dict['play']['validation_id']) + self.assertEqual('buzz/fizz', play_dict['play']['validation_path']) + + @mock.patch( + 'ansible.playbook.task.Task._uuid', + autospec=True, + return_value='bar') + @mock.patch( + 'ansible.playbook.task.Task.get_name', + autospec=True, + return_value='foo') + @mock.patch('ansible.playbook.task.Task') + def test_new_task(self, mock_task, mock_task_name, mock_task_uuid): + """ + From the callback point of view, + both Play and Task are virtually identical. + Test involving them are therefore also very similar. + """ + callback = validation_stdout.CallbackModule() + task_dict = callback._new_task(mock_task) + + mock_task_name.assert_called_once() + mock_task_uuid.assert_called_once() + + """ + Callback time sanity check only verifies general format + of the stored time to be iso format `YYYY-MM-DD HH:MM:SS.mmmmmm` + with 'T' as a separator. + For example: '2020-07-03T13:28:21.224103Z' + """ + self.assertTrue(is_iso_time(task_dict['task']['duration']['start'])) + + def test_val_task(self): + """ + _val_task and _val_task_host methods are virtually identical. + Their tests are too. + """ + task_name = 'foo' + expected_dict = { + 'task': { + 'name': task_name, + 'hosts': {} + } + } + callback = validation_stdout.CallbackModule() + + self.assertEqual( + expected_dict, + callback._val_task(task_name=task_name)) + + def test_val_task_host(self): + """ + _val_task and _val_task_host methods are virtually identical. + Their tests are too. + """ + task_name = 'foo' + expected_dict = { + 'task': { + 'name': task_name, + 'hosts': {} + } + } + callback = validation_stdout.CallbackModule() + + self.assertEqual( + expected_dict, + callback._val_task_host(task_name=task_name))