diff options
Diffstat (limited to 'dovetail/tests')
-rw-r--r-- | dovetail/tests/unit/cli/__init__.py | 0 | ||||
-rw-r--r-- | dovetail/tests/unit/cli/commands/__init__.py | 0 | ||||
-rw-r--r-- | dovetail/tests/unit/cli/commands/test_cli_testcase.py | 228 | ||||
-rw-r--r-- | dovetail/tests/unit/cli/test_cli_base.py | 55 | ||||
-rw-r--r-- | dovetail/tests/unit/cmd_config.yml | 41 | ||||
-rw-r--r-- | dovetail/tests/unit/test_container.py | 489 | ||||
-rw-r--r-- | dovetail/tests/unit/test_parser.py | 45 | ||||
-rw-r--r-- | dovetail/tests/unit/test_report.py | 1671 | ||||
-rw-r--r-- | dovetail/tests/unit/test_run.py | 655 | ||||
-rw-r--r-- | dovetail/tests/unit/test_test_runner.py | 712 | ||||
-rw-r--r-- | dovetail/tests/unit/test_testcase.py | 658 | ||||
-rw-r--r-- | dovetail/tests/unit/test_testcase.yaml | 11 | ||||
-rw-r--r-- | dovetail/tests/unit/utils/__init__.py | 0 | ||||
-rw-r--r-- | dovetail/tests/unit/utils/test_dovetail_config.py | 53 | ||||
-rw-r--r-- | dovetail/tests/unit/utils/test_dovetail_logger.py | 98 | ||||
-rw-r--r-- | dovetail/tests/unit/utils/test_dovetail_utils.py | 1402 | ||||
-rw-r--r-- | dovetail/tests/unit/utils/test_openstack_utils.py | 87 |
17 files changed, 6198 insertions, 7 deletions
diff --git a/dovetail/tests/unit/cli/__init__.py b/dovetail/tests/unit/cli/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dovetail/tests/unit/cli/__init__.py diff --git a/dovetail/tests/unit/cli/commands/__init__.py b/dovetail/tests/unit/cli/commands/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dovetail/tests/unit/cli/commands/__init__.py diff --git a/dovetail/tests/unit/cli/commands/test_cli_testcase.py b/dovetail/tests/unit/cli/commands/test_cli_testcase.py new file mode 100644 index 00000000..324db640 --- /dev/null +++ b/dovetail/tests/unit/cli/commands/test_cli_testcase.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import io +import unittest +from mock import patch, call, Mock +import yaml + +from dovetail import constants +from dovetail.cli.commands.cli_testcase import CliTestcase + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class CliTestcaseTesting(unittest.TestCase): + + @patch('os.path') + @patch('os.pardir') + @patch('dovetail.cli.commands.cli_testcase.dt_utils') + def test_run(self, mock_utils, mock_pardir, mock_path): + run_args = ('arga', 'argb') + options = ' '.join(run_args) + repo_dir = 'repo_dir' + mock_path.abspath.return_value = repo_dir + + testcase = CliTestcase() + testcase.run(options) + + mock_path.dirname.assert_called_once() + cmd = 'python3 %s/run.py %s' % (repo_dir, options) + mock_utils.exec_cmd.assert_called_once_with( + cmd, exit_on_error=True, exec_msg_on=False, info=True) + + @patch('dovetail.cli.commands.cli_testcase.constants') + @patch('os.path') + @patch('dovetail.cli.commands.cli_testcase.click') + def test_show_testcase_not_exist(self, mock_click, mock_path, + mock_constants): + testcase_name = 'name' + testcase_path = 'path' + mock_constants.TESTCASE_PATH = 'path' + testcase_whole_path = '{}/{}.yaml'.format(testcase_name, + testcase_path) + mock_path.join.return_value = testcase_whole_path + mock_path.isfile.return_value = False + + testcase = CliTestcase() + testcase.show_testcase(testcase_name) + + mock_path.join.assert_called_once_with( + testcase_path, '{}.yml'.format(testcase_name)) + mock_path.isfile.assert_called_once_with(testcase_whole_path) + mock_click.echo.assert_called_once_with( + 'testcase %s not exist or not supported' % testcase_name) + + @patch('builtins.open') + @patch('dovetail.cli.commands.cli_testcase.constants') + @patch('os.path') + @patch('dovetail.cli.commands.cli_testcase.click') + def test_show_testcase(self, mock_click, mock_path, mock_constants, + mock_open): + testcase_name = 'name' + testcase_path = 'path' + mock_constants.TESTCASE_PATH = 'path' + testcase_whole_path = '{}/{}.yaml'.format(testcase_name, + testcase_path) + mock_path.join.return_value = testcase_whole_path + mock_path.isfile.return_value = True + file_data = u'file data' + mock_open.return_value.__enter__.return_value = io.StringIO(file_data) + + testcase = CliTestcase() + testcase.show_testcase(testcase_name) + + mock_open.assert_called_once_with(testcase_whole_path, 'r') + mock_path.join.assert_called_once_with( + testcase_path, '{}.yml'.format(testcase_name)) + mock_path.isfile.assert_called_once_with(testcase_whole_path) + mock_click.echo.assert_called_once_with(file_data) + + @patch('builtins.open') + @patch('dovetail.cli.commands.cli_testcase.constants') + @patch('os.path') + @patch('dovetail.cli.commands.cli_testcase.click') + def test_show_testcase_exception(self, mock_click, mock_path, + mock_constants, mock_open): + testcase_name = 'name' + testcase_path = 'path' + mock_constants.TESTCASE_PATH = 'path' + testcase_whole_path = '{}/{}.yaml'.format(testcase_name, + testcase_path) + mock_path.join.return_value = testcase_whole_path + mock_path.isfile.return_value = True + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + exception = yaml.YAMLError() + file_obj.read.side_effect = exception + + testcase = CliTestcase() + testcase.show_testcase(testcase_name) + + mock_open.assert_called_once_with(testcase_whole_path, 'r') + mock_path.join.assert_called_once_with( + testcase_path, '{}.yml'.format(testcase_name)) + mock_path.isfile.assert_called_once_with(testcase_whole_path) + mock_click.echo.assert_called_once_with(exception) + + @patch.object(CliTestcase, 'testsuite_load') + @patch.object(CliTestcase, 'list_one_testsuite') + def test_list_suites_single(self, mock_list_one, mock_load): + testsuite = 'suite' + + testcase = CliTestcase() + testcase.list_testsuites(testsuite) + + mock_load.assert_called_once_with() + mock_list_one.assert_called_once_with(testsuite) + + @patch.object(CliTestcase, 'testsuite_load') + @patch('dovetail.cli.commands.cli_testcase.click') + @patch('dovetail.testcase.Testsuite.get_all') + def test_list_suites_no_suites(self, mock_get_all, mock_click, mock_load): + testsuite = None + mock_get_all.return_value = None + + testcase = CliTestcase() + testcase.list_testsuites(testsuite) + + mock_load.assert_called_once_with() + mock_get_all.assert_called_once_with() + mock_click.echo.assert_called_once_with( + 'No testsuite defined yet in dovetail!!!') + + @patch.object(CliTestcase, 'testsuite_load') + @patch.object(CliTestcase, 'list_one_testsuite') + @patch('dovetail.cli.commands.cli_testcase.click') + @patch('dovetail.testcase.Testsuite.get_all') + def test_list_suites_many(self, mock_get_all, mock_click, mock_list_one, + mock_load): + testsuite = None + suite_name = 'suite' + mock_get_all.return_value = {suite_name: 'A'} + + testcase = CliTestcase() + testcase.list_testsuites(testsuite) + + mock_load.assert_called_once_with() + mock_get_all.assert_called_once_with() + mock_click.echo.assert_has_calls([ + call('--------------------------'), + call('Test Suite {}'.format(suite_name)), + call('--------------------------')]) + mock_list_one.assert_called_once_with(suite_name) + + @patch('dovetail.cli.commands.cli_testcase.click') + @patch('dovetail.testcase.Testsuite.get') + def test_list_one_testsuite_not_exist(self, mock_get, mock_click): + testsuite = 'suite' + mock_get.return_value = None + + testcase = CliTestcase() + testcase.list_one_testsuite(testsuite) + + mock_get.assert_called_once_with(testsuite) + mock_click.echo.assert_called_once_with( + 'testsuite {} does not exist'.format(testsuite)) + + @patch('dovetail.cli.commands.cli_testcase.click') + @patch('dovetail.testcase.Testsuite.get') + @patch('dovetail.cli.commands.cli_testcase.dt_utils') + def test_list_one_testsuite(self, mock_utils, mock_get, mock_click): + testsuite = 'suite' + testsuite_obj = Mock() + mock_get.return_value = testsuite_obj + testcase_a = 'testcaseA' + testcase_b = 'testcaseB' + mock_utils.get_value_from_dict.side_effect = [ + [testcase_a], [testcase_b]] + + testcase = CliTestcase() + testcase.list_one_testsuite(testsuite) + + mock_get.assert_called_once_with(testsuite) + mock_utils.get_value_from_dict.assert_has_calls([ + call('testcases_list.mandatory', testsuite_obj), + call('testcases_list.optional', testsuite_obj)]) + mock_click.echo.assert_has_calls([ + call('- mandatory'), + call(' {}'.format(testcase_a)), + call('- optional'), + call(' {}'.format(testcase_b))]) + + @patch('dovetail.cli.commands.cli_testcase.click') + @patch('dovetail.testcase.Testsuite.get') + @patch('dovetail.cli.commands.cli_testcase.dt_utils') + def test_list_one_testsuite_no_testcases(self, mock_utils, mock_get, + mock_click): + testsuite = 'suite' + testsuite_obj = Mock() + mock_get.return_value = testsuite_obj + mock_utils.get_value_from_dict.return_value = [] + + testcase = CliTestcase() + testcase.list_one_testsuite(testsuite) + + mock_get.assert_called_once_with(testsuite) + mock_utils.get_value_from_dict.assert_has_calls([ + call('testcases_list.mandatory', testsuite_obj), + call('testcases_list.optional', testsuite_obj)]) + mock_click.echo.assert_called_once_with( + 'No testcase in testsuite {}'.format(testsuite)) + + @patch('dovetail.cli.commands.cli_testcase.dt_cfg') + @patch('dovetail.testcase.Testsuite.load') + @patch.object(constants, 'CONF_PATH') + def test_testsuite_load(self, mock_path, mock_load, mock_config): + testcase = CliTestcase() + testcase.testsuite_load() + + mock_config.load_config_files.assert_called_once_with(mock_path) + mock_load.assert_called_once_with() diff --git a/dovetail/tests/unit/cli/test_cli_base.py b/dovetail/tests/unit/cli/test_cli_base.py new file mode 100644 index 00000000..9b06426c --- /dev/null +++ b/dovetail/tests/unit/cli/test_cli_base.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import unittest +from mock import patch + +from click.testing import CliRunner +from dovetail.cli import cli_base + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +@patch.object(cli_base, '_testcase') +class CliBaseTesting(unittest.TestCase): + + def test_cli(self, mock_testcase): + runner = CliRunner() + result = runner.invoke(cli_base.cli, []) + + self.assertEqual(result.exit_code, 0) + + def test_testcase_list(self, mock_testcase): + testsuite = 'suite' + + runner = CliRunner() + result = runner.invoke(cli_base.testcase_list, [testsuite]) + + mock_testcase.list_testsuites.assert_called_once_with(testsuite) + self.assertEqual(result.exit_code, 0) + + def test_testcase_show(self, mock_testcase): + testcase = 'case' + + runner = CliRunner() + result = runner.invoke(cli_base.testcase_show, [testcase]) + + mock_testcase.show_testcase.assert_called_once_with(testcase) + self.assertEqual(result.exit_code, 0) + + def test_testcase_run(self, mock_testcase): + run_args = ('arga', 'argb') + + runner = CliRunner() + result = runner.invoke(cli_base.testcase_run, run_args) + + expected = ' '.join(run_args) + mock_testcase.run.assert_called_once_with(expected) + self.assertEqual(result.exit_code, 0) diff --git a/dovetail/tests/unit/cmd_config.yml b/dovetail/tests/unit/cmd_config.yml new file mode 100644 index 00000000..405aabce --- /dev/null +++ b/dovetail/tests/unit/cmd_config.yml @@ -0,0 +1,41 @@ +############################################################################## +# Copyright (c) 2019 opnfv. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +--- +cli: + arguments: + config: + docker_tag: + flags: 'docker_tag' + path: + - 'functest/docker_tag' + control: + + options: + config: + control: + testsuite: + flags: + - '--testsuite' + debug: + flags: + - '--debug' + is_flag: 'True' + report: + flags: + - '--report' + is_flag: 'True' + opnfvci: + flags: + - '--opnfv-ci' + is_flag: 'True' + noapivalidation: + flags: + - '--no-api-validation' + is_flag: 'True' diff --git a/dovetail/tests/unit/test_container.py b/dovetail/tests/unit/test_container.py new file mode 100644 index 00000000..86da9d3c --- /dev/null +++ b/dovetail/tests/unit/test_container.py @@ -0,0 +1,489 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import unittest +from mock import patch, call, Mock +import docker + +from dovetail.container import Container + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class ContainerTesting(unittest.TestCase): + + def setUp(self): + self.patcher1 = patch.object(docker, 'from_env') + testcase = patch.object(Container, 'testcase') + testcase.testcase = {'validate': { + 'type': 'bottlenecks'}} + test_name_obj = Mock() + test_name_obj.return_value = 'name' + testcase.name = test_name_obj + val_type_obj = Mock() + val_type_obj.return_value = 'bottlenecks' + testcase.validate_type = val_type_obj + self.client = self.patcher1.start().return_value + self.container = Container(testcase) + self.logger = Mock() + self.container.logger = self.logger + + def tearDown(self): + self.patcher1.stop() + + @patch('dovetail.container.dt_cfg') + @patch.object(Container, 'copy_file') + def test_copy_files_in_container(self, mock_copy, mock_config): + source_file = 'source' + destination_file = 'destination_file' + mock_config.dovetail_config = { + 'bottlenecks': { + 'copy_file_in_container': [{ + 'src_file': source_file, + 'dest_file': destination_file}]}} + + self.container.copy_files_in_container() + + mock_copy.assert_called_once_with( + source_file, destination_file) + + @patch('dovetail.container.dt_cfg') + @patch.object(Container, 'copy_file') + def test_copy_files_in_container_no_file(self, mock_copy, mock_config): + mock_config.dovetail_config = { + 'bottlenecks': { + 'copy_file_in_container': []}} + + self.container.copy_files_in_container() + + mock_copy.assert_not_called() + + @patch('dovetail.container.dt_cfg') + @patch.object(Container, 'copy_file') + def test_copy_files_in_container_no_key(self, mock_copy, mock_config): + mock_config.dovetail_config = { + 'bottlenecks': {}} + + self.container.copy_files_in_container() + + mock_copy.assert_not_called() + + def test_copy_file_error(self): + expected = (1, 'src_path or dest_path is empty') + result = self.container.copy_file(None, None) + + self.assertEqual(expected, result) + + @patch.object(Container, 'exec_cmd') + def test_copy_file(self, mock_exec): + expected = (0, 'success') + mock_exec.return_value = expected + result = self.container.copy_file('source', 'dest') + + mock_exec.assert_called_once_with( + 'cp source dest', False) + self.assertEqual(expected, result) + + def test_exec_cmd_error(self): + expected = (1, 'sub_cmd is empty') + result = self.container.exec_cmd('') + + self.assertEqual(expected, result) + + @patch('dovetail.container.dt_cfg') + @patch('dovetail.container.dt_utils') + def test_exec_cmd(self, mock_utils, mock_config): + expected = (0, 'success') + mock_utils.get_value_from_dict.return_value = 'shell' + mock_config.dovetail_config = {'bottlenecks': 'value'} + container_obj = Mock() + container_obj.exec_run.return_value = expected + self.container.container = container_obj + + result = self.container.exec_cmd('command') + + self.assertEqual(expected, result) + + @patch('dovetail.container.dt_cfg') + @patch('dovetail.container.dt_utils') + @patch('sys.exit') + def test_exec_cmd_exception(self, mock_exit, mock_utils, mock_config): + mock_utils.get_value_from_dict.return_value = 'shell' + mock_config.dovetail_config = {'bottlenecks': 'value'} + container_obj = Mock() + response_obj = Mock() + response_obj.status_code = 1 + container_obj.exec_run.side_effect = \ + docker.errors.APIError('error', response=response_obj) + self.container.container = container_obj + + expected = (1, 'error') + result = self.container.exec_cmd('command', exit_on_error=True) + + self.assertEqual(expected, result) + mock_exit.assert_called_once_with(1) + + @patch('dovetail.container.dt_cfg') + @patch('dovetail.container.dt_utils') + def test_exec_cmd_no_shell(self, mock_utils, mock_config): + expected = (1, 'shell is empty') + mock_utils.exec_cmd.return_value = expected + mock_utils.get_value_from_dict.return_value = None + mock_config.dovetail_config = {'bottlenecks': 'value'} + result = self.container.exec_cmd('command') + + self.assertEqual(expected, result) + + @patch('dovetail.container.dt_cfg') + @patch('dovetail.container.dt_utils') + @patch.object(Container, 'get_container') + def test_clean(self, mock_check, mock_utils, mock_config): + container_name = 'container' + mock_config.dovetail_config = {'bottlenecks': 'value'} + mock_utils.get_value_from_dict.return_value = [container_name] + self.container.container = Mock() + mock_check.return_value = Mock() + + self.container.clean() + + mock_utils.get_value_from_dict.assert_called_once_with( + 'extra_container', 'value') + mock_check.assert_called_once_with(container_name) + + @patch('dovetail.container.dt_cfg') + @patch('dovetail.container.dt_utils') + @patch.object(Container, 'get_container') + def test_clean_extra_error(self, mock_check, mock_utils, mock_config): + container_name = 'container' + mock_config.dovetail_config = {'bottlenecks': 'value'} + mock_utils.get_value_from_dict.return_value = [container_name] + container_obj = Mock() + container_obj.remove.side_effect = docker.errors.APIError('error') + self.container.container = Mock() + mock_check.return_value = container_obj + + self.container.clean() + + mock_utils.get_value_from_dict.assert_called_once_with( + 'extra_container', 'value') + mock_check.assert_called_once_with(container_name) + + @patch('dovetail.container.dt_cfg') + @patch('dovetail.container.dt_utils') + def test_clean_no_extra_container(self, mock_utils, mock_config): + mock_utils.get_value_from_dict.return_value = None + container_obj = Mock() + container_obj.remove.side_effect = docker.errors.APIError('error') + self.container.container = container_obj + self.container.clean() + mock_utils.get_value_from_dict.assert_called_once() + + def test_get_container_exist_true(self): + container_name = 'container' + expected = Mock() + self.client.containers.get.return_value = expected + + result = self.container.get_container(container_name) + + self.assertEqual(expected, result) + + def test_get_container_none(self): + container_name = 'container' + self.client.containers.get.side_effect = \ + docker.errors.APIError('error') + + result = self.container.get_container(container_name) + + self.assertEqual(None, result) + + def test_pull_image_none(self): + result = self.container.pull_image(None) + self.assertEqual(None, result) + + @patch.object(Container, 'pull_image_only') + @patch.object(Container, 'get_image_id') + def test_pull_image_no_pull(self, mock_get, mock_pull): + docker_image = 'image' + mock_pull.return_value = None + + result = self.container.pull_image(docker_image) + + mock_get.assert_called_once_with(docker_image) + mock_pull.assert_called_once_with(docker_image) + self.assertEqual(None, result) + + @patch.object(Container, 'pull_image_only') + @patch.object(Container, 'get_image_id') + def test_pull_image_no_new_id(self, mock_get, mock_pull): + docker_image = 'image' + mock_get.return_value = None + mock_pull.return_value = Mock() + + result = self.container.pull_image(docker_image) + + mock_pull.assert_called_once_with(docker_image) + mock_get.assert_has_calls([ + call(docker_image), call(docker_image)]) + self.logger.error.assert_called_once_with( + 'Failed to get the id of image {}.'.format(docker_image)) + self.assertEqual(None, result) + + @patch.object(Container, 'pull_image_only') + @patch.object(Container, 'get_image_id') + def test_pull_image_no_old_id(self, mock_get, mock_pull): + docker_image = 'image' + mock_get.side_effect = [None, Mock()] + mock_pull.return_value = Mock() + + result = self.container.pull_image(docker_image) + + mock_pull.assert_called_once_with(docker_image) + mock_get.assert_has_calls([ + call(docker_image), call(docker_image)]) + self.assertEqual(docker_image, result) + + @patch.object(Container, 'pull_image_only') + @patch.object(Container, 'get_image_id') + def test_pull_image_same_id(self, mock_get, mock_pull): + docker_image = 'image' + mock_get.return_value = Mock() + mock_pull.return_value = Mock() + + result = self.container.pull_image(docker_image) + + mock_pull.assert_called_once_with(docker_image) + mock_get.assert_has_calls([ + call(docker_image), call(docker_image)]) + self.logger.debug.assert_called_once_with( + 'Image {} has no changes, no need to remove.'.format(docker_image)) + self.assertEqual(docker_image, result) + + @patch.object(Container, 'remove_image') + @patch.object(Container, 'pull_image_only') + @patch.object(Container, 'get_image_id') + def test_pull_image_different_id(self, mock_get, mock_pull, mock_remove): + docker_image = 'image' + old_obj = Mock() + mock_get.side_effect = [old_obj, Mock()] + mock_pull.return_value = Mock() + + result = self.container.pull_image(docker_image) + + mock_pull.assert_called_once_with(docker_image) + mock_get.assert_has_calls([ + call(docker_image), call(docker_image)]) + mock_remove.assert_called_once_with(old_obj) + self.assertEqual(docker_image, result) + + def test_pull_image_only(self): + docker_image = 'image' + + result = self.container.pull_image_only(docker_image) + + self.logger.debug.assert_called_once_with( + 'Success to pull docker image {}!'.format(docker_image)) + self.assertEqual(True, result) + + def test_pull_image_only_error(self): + docker_image = 'image' + self.client.images.pull.side_effect = docker.errors.APIError('error') + + result = self.container.pull_image_only(docker_image) + + self.logger.error.assert_called_once_with( + 'Failed to pull docker image {}!'.format(docker_image)) + self.assertEqual(False, result) + + def test_remove_image(self): + image_id = 'image_id' + self.client.containers.list.side_effect = \ + docker.errors.APIError('error') + + result = self.container.remove_image(image_id) + + self.logger.debug.assert_has_calls([ + call('Remove image {}.'.format(image_id)), + call('Remove image {} successfully.'.format(image_id))]) + self.assertEqual(True, result) + + def test_remove_image_ancestors(self): + image_id = 'image_id' + self.client.containers.list.return_value = ['cont_a'] + + result = self.container.remove_image(image_id) + + self.logger.debug.assert_called_once_with( + 'Image {} has containers, skip.'.format(image_id)) + self.assertEqual(True, result) + + def test_remove_image_error(self): + image_id = 'image_id' + self.client.containers.list.return_value = [] + self.client.images.remove.side_effect = \ + docker.errors.ImageNotFound('error') + + result = self.container.remove_image(image_id) + + self.logger.debug.assert_called_once_with( + 'Remove image {}.'.format(image_id)) + self.logger.error.assert_called_once_with( + 'Failed to remove image {}.'.format(image_id)) + self.assertEqual(False, result) + + def test_get_image_id(self): + image_name = 'image_id' + mock_img = Mock() + mock_img.id = image_name + self.client.images.get.return_value = mock_img + + result = self.container.get_image_id(image_name) + + self.assertEqual(image_name, result) + + def test_get_image_id_error(self): + image_name = 'image_id' + self.client.images.get.side_effect = \ + docker.errors.ImageNotFound('error') + + result = self.container.get_image_id(image_name) + + self.assertEqual(None, result) + + @patch('dovetail.container.dt_utils') + def test_get_config(self, mock_utils): + expected = 'value' + mock_utils.get_value_from_dict.return_value = expected + + result = self.container._get_config('a', 'b', 'c') + + mock_utils.get_value_from_dict.assert_called_once_with('a', 'c') + self.assertEqual(expected, result) + + @patch('dovetail.container.dt_utils') + def test_get_config_none(self, mock_utils): + mock_utils.get_value_from_dict.return_value = None + + result = self.container._get_config('a', 'b', 'c') + + mock_utils.get_value_from_dict.assert_has_calls([ + call('a', 'c'), call('a', 'b')]) + self.logger.error.assert_called_once_with( + "Couldn't find key {}.".format('a')) + self.assertEqual(None, result) + + @patch('dovetail.container.dt_cfg') + @patch.object(Container, '_get_config') + def test_get_docker_image(self, mock_get_conf, mock_config): + mock_config.dovetail_config = {'bottlenecks': 'value'} + mock_get_conf.side_effect = ['name', 'tag'] + + expected = 'name:tag' + result = self.container.get_docker_image() + + mock_get_conf.assert_has_calls([ + call('image_name', 'value', {'type': 'bottlenecks'}), + call('docker_tag', 'value', {'type': 'bottlenecks'})]) + self.assertEqual(expected, result) + + @patch('dovetail.container.dt_logger') + def test_create_log(self, mock_logger): + log_obj = Mock() + log_obj.getLogger.return_value = self.logger + mock_logger.Logger.return_value = log_obj + + self.container.create_log() + + self.assertEqual(self.logger, self.container.logger) + + @patch('dovetail.container.dt_utils') + @patch('dovetail.container.dt_cfg') + def test_create(self, mock_config, mock_utils): + docker_image = 'docker_image' + container_id = 'container_id' + mock_utils.get_value_from_dict.side_effect = [ + {'key': 'value'}, 'shell', 'envs', ['volume_one', 'volume_two']] + mock_utils.get_mount_list.side_effect = [['mount', 'list'], 'success'] + mock_utils.get_hosts_info.return_value = 'host_info' + container_obj = Mock() + container_obj.id = container_id + self.client.containers.run.return_value = container_obj + project_config = {} + mock_config.dovetail_config = {'bottlenecks': project_config} + + expected = container_id + result, msg = self.container.create(docker_image) + + mock_utils.get_value_from_dict.assert_has_calls([ + call('opts', project_config), + call('shell', project_config), + call('envs', project_config), + call('volumes', project_config)]) + mock_utils.get_hosts_info.assert_called_once_with(self.logger) + self.assertEqual(expected, result) + self.assertEqual('Successfully to create container.', msg) + + @patch('dovetail.container.dt_utils') + @patch('dovetail.container.dt_cfg') + def test_create_no_shell(self, mock_config, mock_utils): + docker_image = 'docker_image' + mock_config.dovetail_config = {'bottlenecks': 'value'} + mock_utils.get_value_from_dict.side_effect = ['opts', None] + mock_utils.get_hosts_info.return_value = 'host_info' + + result, msg = self.container.create(docker_image) + + mock_utils.get_value_from_dict.assert_has_calls([ + call('opts', 'value'), + call('shell', 'value')]) + self.assertEqual(None, result) + self.assertEqual("Lacking of key word 'shell' in config file.", msg) + + @patch('dovetail.container.dt_utils') + @patch('dovetail.container.dt_cfg') + def test_create_mounts_none(self, mock_config, mock_utils): + docker_image = 'docker_image' + project_config = {} + mock_config.dovetail_config = {'bottlenecks': project_config} + mock_utils.get_value_from_dict.side_effect = [ + {'key': 'value'}, 'shell', ['envs'], ['volume_one']] + mock_utils.get_mount_list.side_effect = [[None, 'error']] + mock_utils.get_hosts_info.return_value = 'host_info' + + result, msg = self.container.create(docker_image) + + mock_utils.get_value_from_dict.assert_has_calls([ + call('opts', project_config), call('shell', project_config), + call('envs', project_config), call('volumes', project_config)]) + self.assertEqual(None, result) + self.assertEqual('error', msg) + + @patch('dovetail.container.dt_utils') + @patch('dovetail.container.dt_cfg') + def test_create_error(self, mock_config, mock_utils): + docker_image = 'docker_image' + mock_utils.get_value_from_dict.side_effect = [ + {'key': 'value'}, 'shell', ['envs'], ['volume_one']] + mock_utils.get_mount_list.side_effect = [['mount', 'list'], 'success'] + mock_utils.get_hosts_info.return_value = 'host_info' + mock_utils.check_https_enabled.return_value = True + self.client.containers.run.side_effect = \ + docker.errors.ImageNotFound('error') + project_config = {} + mock_config.dovetail_config = {'bottlenecks': project_config} + result, msg = self.container.create(docker_image) + + mock_utils.get_value_from_dict.assert_has_calls([ + call('opts', project_config), + call('shell', project_config), + call('envs', project_config), + call('volumes', project_config)]) + mock_utils.get_hosts_info.assert_called_once_with(self.logger) + self.assertEqual(None, result) + self.assertEqual('error', str(docker.errors.ImageNotFound('error'))) diff --git a/dovetail/tests/unit/test_parser.py b/dovetail/tests/unit/test_parser.py index 53484400..4f164772 100644 --- a/dovetail/tests/unit/test_parser.py +++ b/dovetail/tests/unit/test_parser.py @@ -39,31 +39,62 @@ class TestParser(unittest.TestCase): def test_parser_cmd(self, mock_logger): """Test whether the command is correctly parsed.""" - mock_cmd = "python /functest/ci/run_tests.py "\ + mock_cmd = "python3 /functest/ci/run_tests.py "\ "-t {{validate_testcase}} -r" with open(os.path.join(self.test_path, 'test_testcase.yaml')) as f: mock_testcase_yaml = yaml.safe_load(f) MockTestcase = type('Testcase', (object,), {}) mock_testcase = MockTestcase() - mock_testcase.testcase = mock_testcase_yaml.values()[0] + mock_testcase.testcase = list(mock_testcase_yaml.values())[0] output = parser.Parser.parse_cmd(mock_cmd, mock_testcase) - expected_output = ("python /functest/ci/run_tests.py -t " + expected_output = ("python3 /functest/ci/run_tests.py -t " "tempest_smoke_serial -r") self.assertEqual(expected_output, output) def test_parser_cmd_fail(self, mock_logger): """Test whether the command is correctly parsed.""" - mock_cmd = "python /functest/ci/run_tests.py "\ + mock_cmd = "python3 /functest/ci/run_tests.py "\ "-t {{validate_testcase}} -r" mock_testcase_yaml = {} MockTestcase = type('Testcase', (object,), {}) mock_testcase = MockTestcase() mock_testcase.testcase = mock_testcase_yaml.values() output = parser.Parser.parse_cmd(mock_cmd, mock_testcase) - expected_output = ("python /functest/ci/run_tests.py -t " + expected_output = ("python3 /functest/ci/run_tests.py -t " "None -r") self.assertEqual(expected_output, output) + @mock.patch('dovetail.parser.jinja2') + def test_parse_cmd_exception(self, mock_jinja, mock_logger): + errorMSG = 'Exception was raised' + exception = Exception(errorMSG) + command = 'cmd' + undefined_obj = mock.Mock() + mock_jinja.StrictUndefined = undefined_obj + mock_jinja.Template.side_effect = exception -if __name__ == '__main__': - unittest.main() + expected = None + dovetail_parser = parser.Parser() + exception_obj = mock.Mock() + dovetail_parser.logger.exception = exception_obj + result = dovetail_parser.parse_cmd(command, 'testcase') + + mock_jinja.Template.assert_called_once_with(command, + undefined=undefined_obj) + exception_obj.assert_called_once_with( + 'Failed to parse cmd {}, exception: {}'.format(command, errorMSG)) + self.assertEqual(expected, result) + + @mock.patch('dovetail.parser.dt_logger.Logger') + def test_create_log(self, mock_dt_logger, mock_logger): + mock_dt_logger_obj = mock.Mock() + logger_obj = mock.Mock() + mock_dt_logger_obj.getLogger.return_value = logger_obj + mock_dt_logger.return_value = mock_dt_logger_obj + + dovetail_parser = parser.Parser() + dovetail_parser.create_log() + + mock_dt_logger.assert_called_once_with('dovetail.parser.Parser') + mock_dt_logger_obj.getLogger.assert_called_once_with() + self.assertEqual(dovetail_parser.logger, logger_obj) diff --git a/dovetail/tests/unit/test_report.py b/dovetail/tests/unit/test_report.py new file mode 100644 index 00000000..41d70d2f --- /dev/null +++ b/dovetail/tests/unit/test_report.py @@ -0,0 +1,1671 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import json +import os +import unittest +import yaml +from mock import patch, call, Mock + +import dovetail.report as dt_report + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class ReportTesting(unittest.TestCase): + + def setUp(self): + test_path = os.path.dirname(os.path.realpath(__file__)) + with open(os.path.join(test_path, 'test_testcase.yaml')) as f: + self.testcase_yaml = yaml.safe_load(f) + + def tearDown(self): + pass + + def teardown_method(self, method): + dt_report.FunctestCrawler.logger = None + dt_report.FunctestK8sCrawler.logger = None + dt_report.YardstickCrawler.logger = None + dt_report.BottlenecksCrawler.logger = None + dt_report.OnapVtpCrawler.logger = None + dt_report.OnapVvpCrawler.logger = None + dt_report.FunctestChecker.logger = None + dt_report.FunctestK8sChecker.logger = None + dt_report.YardstickChecker.logger = None + dt_report.BottlenecksChecker.logger = None + dt_report.OnapVtpChecker.logger = None + dt_report.OnapVvpChecker.logger = None + dt_report.Report.logger = None + dt_report.Report.results = { + 'functest': {}, 'yardstick': {}, 'functest-k8s': {}, + 'bottlenecks': {}, 'shell': {}, 'onap-vtp': {}, + 'onap-vvp': {}} + + def _produce_report_initial_text(self, report_data): + report_txt = '' + report_txt += '\n\nDovetail Report\n' + report_txt += 'Version: %s\n' % report_data['version'] + report_txt += 'Build Tag: %s\n' % report_data['build_tag'] + report_txt += 'Test Date: %s\n' % report_data['test_date'] + report_txt += 'Duration: %.2f s\n\n' % report_data['duration'] + return report_txt + + @patch('dovetail.report.dt_logger') + def test_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.Report.create_log() + + self.assertEqual(getlogger_obj, dt_report.Report.logger) + + @patch('dovetail.report.os.path') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.dt_utils') + @patch.object(dt_report.Report, 'get_result') + @patch.object(dt_report.Report, 'check_result') + def test_check_tc_result(self, mock_check, mock_get, mock_utils, + mock_config, mock_path): + report = dt_report.Report() + logger_obj = Mock() + report.logger = logger_obj + testcase_obj = Mock() + inner_testcase_obj = Mock() + testcase_obj.testcase = inner_testcase_obj + mock_config.dovetail_config = {'result_dir': 'result_dir'} + mock_utils.get_value_from_dict.return_value = ['check_results_file'] + mock_path.join.return_value = 'results_file' + mock_path.isfile.return_value = True + mock_get.return_value = 'result' + + result = report.check_tc_result(testcase_obj) + + mock_utils.get_value_from_dict.assert_called_once_with( + 'report.check_results_files', inner_testcase_obj) + mock_path.join.assert_called_once_with( + 'result_dir', 'check_results_file') + mock_path.isfile.assert_called_once_with('results_file') + logger_obj.info.assert_called_once_with( + 'Results have been stored with files: [\'results_file\'].') + mock_get.assert_called_once_with(testcase_obj, ['results_file']) + mock_check.assert_called_once_with(testcase_obj, 'result') + self.assertEqual('result', result) + + @patch('dovetail.report.os.path') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.dt_utils') + @patch.object(dt_report.Report, 'get_result') + @patch.object(dt_report.Report, 'check_result') + def test_check_tc_result_no_file(self, mock_check, mock_get, mock_utils, + mock_config, mock_path): + report = dt_report.Report() + logger_obj = Mock() + report.logger = logger_obj + testcase_obj = Mock() + inner_testcase_obj = Mock() + testcase_obj.testcase = inner_testcase_obj + mock_config.dovetail_config = {'result_dir': 'result_dir'} + mock_utils.get_value_from_dict.return_value = ['check_results_file'] + mock_path.join.return_value = 'results_file' + mock_path.isfile.return_value = False + + result = report.check_tc_result(testcase_obj) + + mock_utils.get_value_from_dict.assert_called_once_with( + 'report.check_results_files', inner_testcase_obj) + mock_path.join.assert_called_once_with( + 'result_dir', 'check_results_file') + mock_path.isfile.assert_called_once_with('results_file') + logger_obj.error.assert_called_once_with( + 'Failed to store results with file results_file.') + mock_check.assert_called_once_with(testcase_obj) + self.assertEqual(None, result) + + @patch('dovetail.report.os.path') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.dt_utils') + @patch.object(dt_report.Report, 'get_result') + @patch.object(dt_report.Report, 'check_result') + def test_check_tc_result_no_check(self, mock_check, mock_get, mock_utils, + mock_config, mock_path): + report = dt_report.Report() + logger_obj = Mock() + report.logger = logger_obj + testcase_obj = Mock() + inner_testcase_obj = Mock() + testcase_obj.testcase = inner_testcase_obj + testcase_obj.name.return_value = 'name' + mock_config.dovetail_config = {'result_dir': 'result_dir'} + mock_utils.get_value_from_dict.return_value = None + + result = report.check_tc_result(testcase_obj) + + mock_utils.get_value_from_dict.assert_called_once_with( + 'report.check_results_files', inner_testcase_obj) + logger_obj.error.assert_called_once_with( + "Failed to get 'check_results_files' from config " + "file of test case name") + mock_check.assert_called_once_with(testcase_obj) + self.assertEqual(None, result) + + @patch('dovetail.report.CheckerFactory') + def test_check_result(self, mock_factory): + testcase_obj = Mock() + testcase_obj.validate_type.return_value = 'type' + checker_obj = Mock() + mock_factory.create.return_value = checker_obj + + dt_report.Report.check_result(testcase_obj) + + testcase_obj.validate_type.assert_called_once_with() + mock_factory.create.assert_called_once_with('type') + checker_obj.check.assert_called_once_with(testcase_obj, None) + + @patch('dovetail.report.os.getenv') + @patch.object(dt_report.Report, 'get_checksum') + @patch('dovetail.report.Testcase') + @patch('dovetail.report.datetime.datetime') + @patch('dovetail.report.dt_cfg') + def test_generate_json(self, mock_config, mock_datetime, mock_testcase, + mock_checksum, mock_env): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_list = ['ta.tb.tc', 'td.te.tf'] + duration = 42 + mock_config.dovetail_config = { + 'build_tag': 'build_tag', + 'version': '2018.09' + } + mock_env.return_value = 'enabled' + utc_obj = Mock() + utc_obj.strftime.return_value = '2018-01-13 13:13:13 UTC' + mock_datetime.utcnow.return_value = utc_obj + testcase_obj = Mock() + testcase_obj.passed.return_value = 'PASS' + testcase_obj.objective.return_value = 'objective' + mock_checksum.return_value = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' + testcase_obj.is_mandatory = True + testcase_obj.portal_key_file.return_value = 'a/b.log' + testcase_obj.vnf_type.return_value = 'tosca' + testcase_obj.sub_testcase.return_value = ['subt_a'] + testcase_obj.sub_testcase_passed.return_value = 'PASS' + mock_testcase.get.side_effect = [testcase_obj, None] + + result = report.generate_json(testcase_list, duration) + expected = { + 'version': '2018.09', + 'build_tag': 'build_tag', + 'vnf_type': 'tosca', + 'vnf_checksum': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', + 'test_date': '2018-01-13 13:13:13 UTC', + 'duration': duration, + 'validation': 'enabled', + 'testcases_list': [ + { + 'name': 'ta.tb.tc', + 'result': 'PASS', + 'objective': 'objective', + 'mandatory': True, + 'portal_key_file': 'a/b.log', + 'sub_testcase': [{ + 'name': 'subt_a', + 'result': 'PASS' + }] + }, + { + 'name': 'td.te.tf', + 'result': 'Undefined', + 'objective': '', + 'mandatory': False, + 'portal_key_file': '', + 'sub_testcase': [] + } + ] + } + + self.assertEqual(expected, result) + + @patch('dovetail.report.os.getenv') + @patch('dovetail.report.Testcase') + @patch('dovetail.report.datetime.datetime') + @patch('dovetail.report.dt_cfg') + def test_generate_json_noVNF(self, mock_config, mock_datetime, + mock_testcase, mock_env): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_list = ['ta.tb.tc', 'td.te.tf'] + duration = 42 + mock_config.dovetail_config = { + 'build_tag': 'build_tag', + 'version': '2018.09' + } + mock_env.return_value = 'disabled' + utc_obj = Mock() + utc_obj.strftime.return_value = '2018-01-13 13:13:13 UTC' + mock_datetime.utcnow.return_value = utc_obj + testcase_obj = Mock() + testcase_obj.passed.return_value = 'PASS' + testcase_obj.objective.return_value = 'objective' + testcase_obj.is_mandatory = True + testcase_obj.vnf_type.return_value = None + testcase_obj.portal_key_file.return_value = 'a/b.log' + testcase_obj.sub_testcase.return_value = ['subt_a'] + testcase_obj.sub_testcase_passed.return_value = 'PASS' + mock_testcase.get.side_effect = [testcase_obj, None] + + result = report.generate_json(testcase_list, duration) + expected = { + 'version': '2018.09', + 'build_tag': 'build_tag', + 'test_date': '2018-01-13 13:13:13 UTC', + 'duration': duration, + 'validation': 'disabled', + 'testcases_list': [ + { + 'name': 'ta.tb.tc', + 'result': 'PASS', + 'objective': 'objective', + 'mandatory': True, + 'portal_key_file': 'a/b.log', + 'sub_testcase': [{ + 'name': 'subt_a', + 'result': 'PASS' + }] + }, + { + 'name': 'td.te.tf', + 'result': 'Undefined', + 'objective': '', + 'mandatory': False, + 'portal_key_file': '', + 'sub_testcase': [] + } + ] + } + + self.assertEqual(expected, result) + + @patch('dovetail.report.os.getenv') + @patch('dovetail.report.Testcase') + @patch('dovetail.report.datetime.datetime') + @patch('dovetail.report.dt_cfg') + def test_generate_json_noVNF_inTestCase(self, mock_config, mock_datetime, + mock_testcase, mock_env): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_list = ['ta.tb.tc', 'td.te.tf'] + duration = 42 + mock_config.dovetail_config = { + 'build_tag': 'build_tag', + 'version': '2018.09' + } + mock_env.return_value = 'enabled' + utc_obj = Mock() + utc_obj.strftime.return_value = '2018-01-13 13:13:13 UTC' + mock_datetime.utcnow.return_value = utc_obj + testcase_obj = Mock() + testcase_obj.passed.return_value = 'PASS' + testcase_obj.objective.return_value = 'objective' + testcase_obj.is_mandatory = True + testcase_obj.portal_key_file.return_value = 'a/b.log' + testcase_obj.vnf_type.side_effect = Exception() + testcase_obj.sub_testcase.return_value = ['subt_a'] + testcase_obj.sub_testcase_passed.return_value = 'PASS' + mock_testcase.get.side_effect = [testcase_obj, None] + + result = report.generate_json(testcase_list, duration) + expected = { + 'version': '2018.09', + 'build_tag': 'build_tag', + 'test_date': '2018-01-13 13:13:13 UTC', + 'duration': duration, + 'validation': 'enabled', + 'testcases_list': [ + { + 'name': 'ta.tb.tc', + 'result': 'PASS', + 'objective': 'objective', + 'mandatory': True, + 'portal_key_file': 'a/b.log', + 'sub_testcase': [{ + 'name': 'subt_a', + 'result': 'PASS' + }] + }, + { + 'name': 'td.te.tf', + 'result': 'Undefined', + 'objective': '', + 'mandatory': False, + 'portal_key_file': '', + 'sub_testcase': [] + } + ] + } + + self.assertEqual(expected, result) + + @patch('dovetail.report.datetime.datetime') + @patch('dovetail.report.dt_cfg') + @patch.object(dt_report.Report, 'get_checksum') + def test_generate_json_no_list(self, mock_checksum, mock_config, + mock_datetime): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + duration = 42 + mock_config.dovetail_config = { + 'build_tag': 'build_tag', + 'version': '2018.09', + 'vnf_type': 'tosca' + } + utc_obj = Mock() + utc_obj.strftime.return_value = '2018-01-13 13:13:13 UTC' + mock_datetime.utcnow.return_value = utc_obj + mock_checksum.return_value = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' + + result = report.generate_json([], duration) + expected = { + 'version': '2018.09', + 'build_tag': 'build_tag', + 'vnf_type': 'tosca', + 'vnf_checksum': 'da39a3ee5e6b4b0d3255bfef95601890afd80709', + 'test_date': '2018-01-13 13:13:13 UTC', + 'duration': duration, + 'testcases_list': [] + } + + self.assertEqual(expected, result) + + @patch('dovetail.report.dt_cfg') + @patch.object(dt_report.Report, 'generate_json') + @patch.object(dt_report.Report, 'save_json_results') + def test_generate(self, mock_save, mock_generate, mock_config): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_list = ['ta.tb.tc', 'td.te.tf'] + duration = 42 + report_data = { + 'version': 'v2', + 'build_tag': '2.0.0', + 'test_date': '2018-01-13 13:13:13 UTC', + 'duration': 42.42, + 'testcases_list': [ + { + 'name': 'ta.tb.tc', + 'result': 'PASS', + 'sub_testcase': [{ + 'name': 'subt_a', + 'result': 'PASS' + }] + }, + { + 'name': 'td.te.tf', + 'result': 'SKIP' + } + ] + } + mock_generate.return_value = report_data + + result = report.generate(testcase_list, duration) + expected = self._produce_report_initial_text(report_data) + expected += 'Pass Rate: 100.00% (1/1)\n' + expected += '%-25s pass rate %.2f%%\n' % ('tb:', 100) + expected += '-%-25s %s\n' % ('ta.tb.tc', 'PASS') + expected += '\t%-110s %s\n' % ('subt_a', 'PASS') + expected += '%-25s all skipped\n' % 'te' + expected += '-%-25s %s\n' % ('td.te.tf', 'SKIP') + + mock_generate.assert_called_once_with(testcase_list, duration) + mock_save.assert_called_once_with(report_data) + report.logger.info.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('dovetail.report.dt_cfg') + @patch.object(dt_report.Report, 'generate_json') + @patch.object(dt_report.Report, 'save_json_results') + def test_generate_no_cases(self, mock_save, mock_generate, mock_config): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + duration = 42 + report_data = { + 'version': 'v2', + 'build_tag': '2.0.0', + 'test_date': '2018-01-13 13:13:13 UTC', + 'duration': 42.42, + 'testcases_list': [] + } + mock_generate.return_value = report_data + + result = report.generate([], duration) + expected = self._produce_report_initial_text(report_data) +\ + 'no testcase or all testcases are skipped in this testsuite\n' + + mock_generate.assert_called_once_with([], duration) + mock_save.assert_called_once_with(report_data) + report.logger.info.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json') + @patch('dovetail.report.os.path') + @patch('dovetail.report.dt_cfg') + def test_save_json_results(self, mock_config, mock_path, mock_json, + mock_open): + mock_config.dovetail_config = { + 'result_dir': 'a', + 'result_file': 'b' + } + mock_path.join.return_value = 'result_file' + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + mock_json.dumps.return_value = 'results text' + + report = dt_report.Report() + report.save_json_results('results') + + mock_path.join.assert_called_once_with('a', 'b') + mock_open.assert_called_once_with('result_file', 'w') + mock_json.dumps.assert_called_once_with('results') + file_obj.write.assert_called_once_with('results text\n') + + @patch('builtins.open') + @patch('dovetail.report.json') + @patch('dovetail.report.os.path') + @patch('dovetail.report.dt_cfg') + def test_save_json_results_exception(self, mock_config, mock_path, + mock_json, mock_open): + report = dt_report.Report() + logger_obj = Mock() + report.logger = logger_obj + mock_config.dovetail_config = { + 'result_dir': 'a', + 'result_file': 'b' + } + mock_path.join.return_value = 'result_file' + mock_open.return_value.__enter__.side_effect = Exception('error') + + report.save_json_results('results') + + mock_path.join.assert_called_once_with('a', 'b') + mock_open.assert_called_once_with('result_file', 'w') + report.logger.exception.assert_called_once_with( + 'Failed to add result to file result_file, exception: error') + + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.time') + @patch('dovetail.report.os') + @patch('dovetail.report.tarfile') + def test_save_logs(self, mock_tar, mock_os, mock_time, mock_config): + mock_config.dovetail_config = {'result_dir': 'result_dir'} + local_time_obj = Mock() + mock_time.localtime.return_value = local_time_obj + mock_time.strftime.return_value = '20180113_13:13' + mock_os.getcwd.return_value = 'cwd' + tar_obj = Mock() + tar_file_obj = Mock() + mock_tar.open.return_value.__enter__.return_value = tar_file_obj + mock_os.path.join.side_effect = ['one', tar_obj, 'three'] + mock_os.listdir.return_value = ['file'] + + dt_report.Report.save_logs() + + mock_time.localtime.assert_called_once_with() + mock_time.strftime.assert_called_once_with('%Y%m%d_%H%M', + local_time_obj) + mock_os.getcwd.assert_called_once_with() + mock_os.path.join.assert_has_calls([ + call('result_dir', '..'), + call('result_dir', '..', 'logs_20180113_13:13.tar.gz'), + call('results', 'file')]) + mock_tar.open.assert_called_once_with(tar_obj, 'w:gz') + mock_os.listdir.assert_called_once_with('result_dir') + tar_file_obj.add.assert_called_once_with('three') + mock_os.chdir.assert_has_calls([call('one'), call('cwd')]) + + @patch('dovetail.report.CrawlerFactory') + def test_get_result(self, mock_crawler): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_obj = Mock() + crawler_obj = Mock() + testcase_obj.validate_testcase.return_value = 'validate' + testcase_obj.validate_type.return_value = 'functest' + mock_crawler.create.return_value = crawler_obj + crawler_obj.crawl.return_value = 'result' + + result = report.get_result(testcase_obj, 'check_results_files') + + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.validate_type.assert_called_once_with() + mock_crawler.create.assert_called_once_with('functest') + crawler_obj.crawl.assert_called_once_with( + testcase_obj, 'check_results_files') + logger_obj.debug.assert_called_once_with( + 'Test case: validate -> result acquired') + self.assertEqual({'validate': 'result'}, + dt_report.Report.results['functest']) + self.assertEqual('result', result) + + @patch('dovetail.report.CrawlerFactory') + def test_get_result_no_result(self, mock_crawler): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_obj = Mock() + crawler_obj = Mock() + testcase_obj.validate_testcase.return_value = 'validate' + testcase_obj.validate_type.return_value = 'functest' + testcase_obj.increase_retry.return_value = 'retry' + mock_crawler.create.return_value = crawler_obj + crawler_obj.crawl.return_value = None + + result = report.get_result(testcase_obj, 'check_results_files') + + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.validate_type.assert_called_once_with() + mock_crawler.create.assert_called_once_with('functest') + crawler_obj.crawl.assert_called_once_with( + testcase_obj, 'check_results_files') + testcase_obj.increase_retry.assert_called_once_with() + logger_obj.debug.assert_called_once_with( + 'Test case: validate -> result acquired retry: retry') + self.assertEqual(None, result) + + @patch('dovetail.report.CrawlerFactory') + def test_get_result_no_crawler(self, mock_crawler): + logger_obj = Mock() + report = dt_report.Report() + report.logger = logger_obj + testcase_obj = Mock() + testcase_obj.name.return_value = 'name' + testcase_obj.validate_testcase.return_value = 'validate' + testcase_obj.validate_type.return_value = 'functest' + mock_crawler.create.return_value = None + + result = report.get_result(testcase_obj, 'check_results_files') + + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.validate_type.assert_called_once_with() + mock_crawler.create.assert_called_once_with('functest') + logger_obj.error.assert_called_once_with( + 'Crawler is None: name') + self.assertEqual(None, result) + + @patch('dovetail.report.dt_logger') + def test_functest_crawler_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.FunctestCrawler.create_log() + + self.assertEqual(getlogger_obj, dt_report.FunctestCrawler.logger) + + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.os.path') + def test_functest_crawler_crawl_not_exists(self, mock_path, mock_config): + logger_obj = Mock() + mock_config.dovetail_config = {'build_tag': 'tag'} + dt_report.FunctestCrawler.logger = logger_obj + mock_path.exists.return_value = False + file_path = 'file_path' + testcase_obj = Mock() + testcase_obj.validate_testcase.return_value = 'validate' + testcase_obj.name.return_value = 'name' + + crawler = dt_report.FunctestCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.name.assert_called_once_with() + logger_obj.error.assert_called_once_with( + 'Result file not found: {}'.format(file_path)) + self.assertEqual(None, result) + + def test_functest_crawler_get_details_exception(self): + logger_obj = Mock() + dt_report.FunctestCrawler.logger = logger_obj + data = None + crawler = dt_report.FunctestCrawler() + + excepted = None + result = crawler.get_details(data) + logger_obj.exception.assert_called_once() + self.assertEqual(excepted, result) + + def test_functest_crawler_get_rally_details_exception(self): + logger_obj = Mock() + dt_report.FunctestCrawler.logger = logger_obj + data = None + crawler = dt_report.FunctestCrawler() + + excepted = None + result = crawler.get_rally_details(data) + logger_obj.exception.assert_called_once() + self.assertEqual(excepted, result) + + @patch('builtins.open') + @patch('dovetail.report.json') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.dt_utils') + @patch('dovetail.report.os.path') + def test_functest_crawler_crawl(self, mock_path, mock_utils, mock_config, + mock_json, mock_open): + logger_obj = Mock() + mock_config.dovetail_config = {'build_tag': 'tag'} + dt_report.FunctestCrawler.logger = logger_obj + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + testcase_obj.validate_testcase.return_value = 'name' + testcase_obj.name.return_value = 'name' + testcase_obj.sub_testcase.return_value = ['subt_a'] + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'case_name': 'name', + 'build_tag': 'tag-name', + 'criteria': 'criteria', + 'start_date': 'start_date', + 'stop_date': 'stop_date', + 'details': { + 'tests_number': 'tests_number', + 'failures_number': 'failures_number', + 'success': 'success', + 'failures': 'failures', + 'skipped': 'skipped' + } + } + mock_json.loads.return_value = data_dict + mock_utils.get_duration.return_value = 'duration' + + crawler = dt_report.FunctestCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'criteria', 'timestart': 'start_date', + 'timestop': 'stop_date', 'duration': 'duration', + 'details': { + 'tests': 'tests_number', 'failures': 'failures_number', + 'success': 'success', 'errors': 'failures', + 'skipped': 'skipped'}} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_json.loads.assert_called_once_with(file_obj) + mock_utils.get_duration.assert_called_once_with( + 'start_date', 'stop_date', logger_obj) + testcase_obj.set_results.assert_called_once_with(expected) + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.sub_testcase.assert_called_once_with() + testcase_obj.name.assert_called_once_with() + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.dt_utils') + @patch('dovetail.report.os.path') + def test_functest_rally_crawler_crawl(self, mock_path, mock_utils, + mock_config, mock_json, mock_open): + logger_obj = Mock() + mock_config.dovetail_config = {'build_tag': 'tag'} + dt_report.FunctestCrawler.logger = logger_obj + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + testcase_obj.validate_testcase.return_value = 'rally_full' + testcase_obj.name.return_value = 'name' + testcase_obj.sub_testcase.return_value = ['subt_a', 'subt_b', 'subt_c'] + file_obj = Mock() + mock_open.return_value.__enter__.side_effect = [[file_obj], file_obj] + data_dict = { + 'case_name': 'rally_full', + 'build_tag': 'tag-name', + 'criteria': 'criteria', + 'start_date': 'start_date', + 'stop_date': 'stop_date', + 'details': { + 'modules': [ + { + 'details': { + 'success': ['subt_a'], + 'failures': ['subt_b', 'subt_c'] + }, + 'module': 'module' + } + ] + } + } + + mock_json.loads.return_value = data_dict + mock_utils.get_duration.return_value = 'duration' + + crawler = dt_report.FunctestCrawler() + result = crawler.crawl(testcase_obj, [file_path, file_path]) + expected = {'criteria': 'criteria', 'timestart': 'start_date', + 'timestop': 'stop_date', 'duration': 'duration', + 'details': { + 'tests': 3, 'failures': 2, + 'success': ['subt_a'], 'errors': ['subt_b', 'subt_c'], + 'skipped': []}} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_with(file_path, 'r') + mock_json.loads.assert_called_with(file_obj) + mock_utils.get_duration.assert_called_once_with( + 'start_date', 'stop_date', logger_obj) + testcase_obj.set_results.assert_called_with(expected) + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.sub_testcase.assert_called_once_with() + testcase_obj.name.assert_called_once_with() + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.dt_utils') + @patch('dovetail.report.os.path') + def test_functest_crawler_crawl_errors(self, mock_path, mock_utils, + mock_config, mock_load, mock_open): + logger_obj = Mock() + mock_config.dovetail_config = {'build_tag': 'tag'} + dt_report.FunctestCrawler.logger = logger_obj + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + testcase_obj.validate_testcase.return_value = 'name' + testcase_obj.name.return_value = 'name' + testcase_obj.sub_testcase.return_value = ['subt_a'] + file_a = Mock() + file_b = Mock() + mock_open.return_value.__enter__.return_value = [file_a, file_b] + mock_load.side_effect = [ValueError(), {}] + mock_utils.get_duration.return_value = 'duration' + + crawler = dt_report.FunctestCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_load.assert_has_calls([call(file_a), call(file_b)]) + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.sub_testcase.assert_called_once_with() + testcase_obj.name.assert_called_once_with() + logger_obj.exception.assert_called_once_with( + "Result data don't have key 'case_name'.") + self.assertEqual(None, result) + + @patch('dovetail.report.dt_logger') + def test_functestk8s_crawler_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.FunctestK8sCrawler.create_log() + + self.assertEqual(getlogger_obj, dt_report.FunctestK8sCrawler.logger) + + @patch('dovetail.report.FunctestK8sCrawler.crawl_from_file') + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.os.path') + def test_functestk8s_crawler_crawl_none(self, mock_path, mock_config, + mock_crawl): + logger_obj = Mock() + dt_report.FunctestK8sCrawler.logger = logger_obj + mock_crawl.return_value = None + testcase = 'testcase' + file_path = 'file_path' + + crawler = dt_report.FunctestK8sCrawler() + + result = crawler.crawl(testcase, [file_path]) + + dt_report.FunctestK8sCrawler.crawl_from_file.assert_called_once_with( + 'testcase', 'file_path') + self.assertEqual(None, result) + + @patch('dovetail.report.dt_logger') + def test_yardstick_crawler_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.YardstickCrawler.create_log() + + self.assertEqual(getlogger_obj, dt_report.YardstickCrawler.logger) + + @patch('dovetail.report.os.path') + def test_yardstick_crawler_crawl_not_exists(self, mock_path): + logger_obj = Mock() + dt_report.YardstickCrawler.logger = logger_obj + mock_path.exists.return_value = False + file_path = 'file_path' + + crawler = dt_report.YardstickCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + logger_obj.error.assert_called_once_with( + 'Result file not found: {}'.format(file_path)) + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.dt_utils') + @patch('dovetail.report.os.path') + def test_yardstick_crawler_crawl(self, mock_path, mock_utils, mock_loads, + mock_open): + dt_report.YardstickCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + testcase_obj.validate_testcase.return_value = 'name' + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'result': { + 'testcases': { + 'name': { + 'tc_data': [{ + 'data': { + 'sla_pass': 0 + } + }] + } + } + } + } + mock_loads.return_value = data_dict + mock_utils.get_value_from_dict.return_value = 'PASS' + + crawler = dt_report.YardstickCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + mock_utils.get_value_from_dict.assert_called_once_with( + 'result.criteria', data_dict) + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.dt_utils') + @patch('dovetail.report.os.path') + def test_yardstick_crawler_crawl_key_error(self, mock_path, mock_utils, + mock_loads, mock_open): + logger_obj = Mock() + dt_report.YardstickCrawler.logger = logger_obj + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + testcase_obj.validate_testcase.return_value = 'name' + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + + mock_loads.return_value = {} + mock_utils.get_value_from_dict.return_value = 'PASS' + + crawler = dt_report.YardstickCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'PASS'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + mock_utils.get_value_from_dict.assert_called_once_with( + 'result.criteria', {}) + testcase_obj.validate_testcase.assert_called_once_with() + testcase_obj.set_results.assert_called_once_with(expected) + logger_obj.exception.assert_called_once_with( + "Pass flag not found 'result'") + self.assertEqual(expected, result) + + @patch('dovetail.report.dt_logger') + def test_bottlenecks_crawler_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.BottlenecksCrawler.create_log() + + self.assertEqual(getlogger_obj, dt_report.BottlenecksCrawler.logger) + + @patch('dovetail.report.os.path') + def test_bottlenecks_crawler_crawl_not_exists(self, mock_path): + logger_obj = Mock() + dt_report.BottlenecksCrawler.logger = logger_obj + mock_path.exists.return_value = False + file_path = 'file_path' + + crawler = dt_report.BottlenecksCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + logger_obj.error.assert_called_once_with( + 'Result file not found: {}'.format(file_path)) + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_bottlenecks_crawler_crawl_pass(self, mock_path, mock_loads, + mock_open): + dt_report.BottlenecksCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'data_body': { + 'result': 'PASS' + } + } + mock_loads.return_value = data_dict + + crawler = dt_report.BottlenecksCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'PASS'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_bottlenecks_crawler_crawl_fail(self, mock_path, mock_loads, + mock_open): + dt_report.BottlenecksCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'data_body': { + 'result': 'FAIL' + } + } + mock_loads.return_value = data_dict + + crawler = dt_report.BottlenecksCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_bottlenecks_crawler_crawl_key_error(self, mock_path, mock_loads, + mock_open): + logger_obj = Mock() + dt_report.BottlenecksCrawler.logger = logger_obj + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + + mock_loads.return_value = {} + + crawler = dt_report.BottlenecksCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + testcase_obj.set_results.assert_called_once_with(expected) + logger_obj.exception.assert_called_once_with( + "Pass flag not found 'data_body'") + self.assertEqual(expected, result) + + @patch('dovetail.report.os.path') + def test_shell_crawler_crawl_not_exists(self, mock_path): + mock_path.exists.return_value = False + file_path = 'file_path' + + crawler = dt_report.ShellCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.report.os.path') + def test_shell_crawler_crawl_exception(self, mock_path, mock_open): + mock_path.exists.return_value = True + file_path = 'file_path' + mock_open.return_value.__enter__.return_value = Exception() + + crawler = dt_report.ShellCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.report.json.load') + @patch('dovetail.report.os.path') + def test_shell_crawler_crawl(self, mock_path, mock_load, + mock_open): + mock_path.exists.return_value = True + file_path = 'file_path' + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = 'result' + + crawler = dt_report.ShellCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_load.assert_called_once_with(file_obj) + self.assertEqual('result', result) + + @patch('dovetail.report.dt_logger') + def test_onapvtp_crawler_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.OnapVtpCrawler.create_log() + + self.assertEqual(getlogger_obj, dt_report.OnapVtpCrawler.logger) + + @patch('dovetail.report.dt_logger') + def test_onapvvp_crawler_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.OnapVvpCrawler.create_log() + + self.assertEqual(getlogger_obj, dt_report.OnapVvpCrawler.logger) + + @patch('dovetail.report.os.path') + def test_onapvtp_crawler_crawl_not_exists(self, mock_path): + logger_obj = Mock() + dt_report.OnapVtpCrawler.logger = logger_obj + mock_path.exists.return_value = False + file_path = 'file_path' + + crawler = dt_report.OnapVtpCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + logger_obj.error.assert_called_once_with( + 'Result file not found: {}'.format(file_path)) + self.assertEqual(None, result) + + @patch('dovetail.report.os.path') + def test_onapvvp_crawler_crawl_not_exists(self, mock_path): + logger_obj = Mock() + dt_report.OnapVvpCrawler.logger = logger_obj + mock_path.exists.return_value = False + file_path = 'file_path' + + crawler = dt_report.OnapVvpCrawler() + result = crawler.crawl(None, [file_path]) + + mock_path.exists.assert_called_once_with(file_path) + logger_obj.error.assert_called_once_with( + 'Result file not found: {}'.format(file_path)) + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.report.os.path') + def test_onapvvp_crawler_crawl_pass(self, mock_path, + mock_open): + dt_report.OnapVvpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + file_obj.read.return_value = json.dumps({'outcome': 'PASS'}) + mock_open.return_value.__enter__.return_value = file_obj + + crawler = dt_report.OnapVvpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'PASS'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + file_obj.read.assert_called_once_with() + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.os.path') + def test_onapvvp_crawler_crawl_fail(self, mock_path, + mock_open): + dt_report.OnapVvpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + file_obj.read.return_value = json.dumps({'outcome': 'FAIL'}) + mock_open.return_value.__enter__.return_value = file_obj + + crawler = dt_report.OnapVvpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + file_obj.read.assert_called_once_with() + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.os.path') + def test_onapvvp_crawler_crawl_value_exception(self, mock_path, + mock_open): + dt_report.OnapVvpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + file_obj.read.return_value = 'error' + mock_open.return_value.__enter__.return_value = file_obj + + crawler = dt_report.OnapVvpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + file_obj.read.assert_called_once_with() + dt_report.OnapVvpCrawler.logger.exception.assert_called_once_with( + 'Result file has invalid format') + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.os.path') + def test_onapvvp_crawler_crawl_key_exception(self, mock_path, + mock_open): + dt_report.OnapVvpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + file_obj.read.return_value = json.dumps({'key': 'value'}) + mock_open.return_value.__enter__.return_value = file_obj + + crawler = dt_report.OnapVvpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + file_obj.read.assert_called_once_with() + dt_report.OnapVvpCrawler.logger.exception.assert_called_once_with( + "Outcome field not found 'outcome'") + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_onapvtp_crawler_crawl_pass(self, mock_path, mock_loads, + mock_open): + dt_report.OnapVtpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'results': [ + {"property": "results", "value": "{value=SUCCESS}"}, + {"property": "build_tag", "value": "test-name"}, + {"property": "criteria", "value": "PASS"} + ] + } + mock_loads.return_value = data_dict + + crawler = dt_report.OnapVtpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'PASS'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_onapvtp_crawler_crawl_fail(self, mock_path, mock_loads, + mock_open): + dt_report.OnapVtpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'results': [ + {"property": "results", "value": "{value=file doesn't exist}"}, + {"property": "build_tag", "value": "test-name"}, + {"property": "criteria", "value": "FAILED"} + ] + } + mock_loads.return_value = data_dict + + crawler = dt_report.OnapVtpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_onapvtp_crawler_crawl_no_criteria(self, mock_path, mock_loads, + mock_open): + dt_report.OnapVtpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'results': [ + {"property": "results", "value": "{value=file doesn't exist}"}, + {"property": "build_tag", "value": "test-name"}, + {"property": "error_criteria", "value": "FAILED"} + ] + } + mock_loads.return_value = data_dict + + crawler = dt_report.OnapVtpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + dt_report.OnapVtpCrawler.logger.error.assert_called_once_with( + 'There is no property criteria.') + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_onapvtp_crawler_crawl_exception(self, mock_path, mock_loads, + mock_open): + dt_report.OnapVtpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + data_dict = { + 'error_results': [ + {"property": "results", "value": "{value=file doesn't exist}"}, + {"property": "build_tag", "value": "test-name"}, + {"property": "error_criteria", "value": "FAILED"} + ] + } + mock_loads.return_value = data_dict + + crawler = dt_report.OnapVtpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + dt_report.OnapVtpCrawler.logger.exception.assert_called_once_with( + "Pass flag not found 'results'") + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('dovetail.report.json.loads') + @patch('dovetail.report.os.path') + def test_onapvtp_crawler_crawl_value_error(self, mock_path, mock_loads, + mock_open): + dt_report.OnapVtpCrawler.logger = Mock() + mock_path.exists.return_value = True + file_path = 'file_path' + testcase_obj = Mock() + file_obj = Mock() + mock_open.return_value.__enter__.return_value = [file_obj] + mock_loads.side_effect = ValueError('No JSON object could be decoded') + + crawler = dt_report.OnapVtpCrawler() + result = crawler.crawl(testcase_obj, [file_path]) + expected = {'criteria': 'FAIL'} + + mock_path.exists.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_loads.assert_called_once_with(file_obj) + testcase_obj.set_results.assert_called_once_with(expected) + self.assertEqual(expected, result) + + def test_crawler_factory(self): + result = dt_report.CrawlerFactory.create('shell') + self.assertEqual(dt_report.ShellCrawler, result.__class__) + + def test_crawler_factory_none(self): + self.assertEqual(None, dt_report.CrawlerFactory.create('other')) + + def test_result_checker(self): + self.assertEqual('PASS', dt_report.ResultChecker.check()) + + @patch('dovetail.report.dt_logger') + def test_functest_checker_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.FunctestChecker.create_log() + + self.assertEqual(getlogger_obj, dt_report.FunctestChecker.logger) + + def test_functest_get_sub_testcase_no_result(self): + self.assertEqual( + False, dt_report.FunctestChecker.get_sub_testcase(None, None)) + + def test_functest_get_sub_testcase_simple_match(self): + self.assertEqual( + True, + dt_report.FunctestChecker.get_sub_testcase('subt_a', + ['subt_b', 'subt_a'])) + + def test_functest_get_sub_testcase_extended_match(self): + self.assertEqual( + True, + dt_report.FunctestChecker.get_sub_testcase('subt_a', + ['subt_b', 'subt_a+'])) + + def test_functest_get_sub_testcase_class_match(self): + self.assertEqual( + True, + dt_report.FunctestChecker.get_sub_testcase('subclass_a.subt_a', + ['subclass_a', + 'subclass_b.subt_b'])) + + def test_functest_get_sub_testcase_class_no_match(self): + self.assertEqual( + False, + dt_report.FunctestChecker.get_sub_testcase('subclass_a.subt_a', + ['subclass_a.subt_a_a', + 'subclass_b.subt_b'])) + + def test_functest_get_sub_no_match(self): + self.assertEqual( + False, + dt_report.FunctestChecker.get_sub_testcase('subt_a', + ['subt_b'])) + + def test_functest_check_no_db_results(self): + testcase_obj = Mock() + testcase_obj.sub_testcase.return_value = ['subt_a'] + + checker = dt_report.FunctestChecker() + checker.check(testcase_obj, None) + + testcase_obj.sub_testcase.assert_called_once_with() + testcase_obj.sub_testcase_passed.assert_called_once_with( + 'subt_a', 'FAIL') + + def test_functest_check_no_subtestcases(self): + testcase_obj = Mock() + testcase_obj.sub_testcase.return_value = None + + checker = dt_report.FunctestChecker() + checker.check(testcase_obj, {'criteria': 'PASS'}) + + testcase_obj.sub_testcase.assert_called_once_with() + testcase_obj.passed.assert_called_once_with('PASS') + + @patch.object(dt_report.FunctestChecker, 'get_sub_testcase') + def test_functest_check(self, mock_get): + testcase_obj = Mock() + testcase_obj.sub_testcase.return_value = [ + 'subt_a', 'subt_b', 'subt_c', 'subt_d'] + logger_obj = Mock() + dt_report.FunctestChecker.logger = logger_obj + db_result = { + 'criteria': 'PASS', + 'details': { + 'success': True, + 'skipped': False + } + } + mock_get.side_effect = [True, False, True, False, False, KeyError()] + + checker = dt_report.FunctestChecker() + checker.check(testcase_obj, db_result) + + testcase_obj.sub_testcase.assert_called_once_with() + testcase_obj.passed.assert_has_calls([call('PASS'), call('FAIL')]) + + @patch('dovetail.report.dt_logger') + def test_functestk8s_checker_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.FunctestK8sChecker.create_log() + + self.assertEqual(getlogger_obj, dt_report.FunctestK8sChecker.logger) + + @patch('dovetail.report.dt_logger') + def test_yardstick_checker_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.YardstickChecker.create_log() + + self.assertEqual(getlogger_obj, dt_report.YardstickChecker.logger) + + def test_yardstick_check_result(self): + testcase_obj = Mock() + result = {'criteria': 'PASS'} + + dt_report.YardstickChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('PASS') + + def test_yardstick_check_result_none(self): + testcase_obj = Mock() + result = {} + + dt_report.YardstickChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('FAIL') + + @patch('dovetail.report.dt_logger') + def test_bottlenecks_checker_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.BottlenecksChecker.create_log() + + self.assertEqual(getlogger_obj, dt_report.BottlenecksChecker.logger) + + def test_bottlenecks_check_result(self): + testcase_obj = Mock() + result = {'criteria': 'PASS'} + + dt_report.BottlenecksChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('PASS') + + def test_bottlenecks_check_result_none(self): + testcase_obj = Mock() + result = {} + + dt_report.BottlenecksChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('FAIL') + + def test_shell_check_result(self): + testcase_obj = Mock() + result = {'pass': True} + + dt_report.ShellChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with(True) + + def test_shell_check_result_exception(self): + testcase_obj = Mock() + result = {} + + dt_report.ShellChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with(False) + + def test_checker_factory(self): + result = dt_report.CheckerFactory.create('shell') + self.assertEqual(dt_report.ShellChecker, result.__class__) + + def test_checker_factory_none(self): + self.assertEqual(None, dt_report.CheckerFactory.create('other')) + + @patch('dovetail.report.dt_logger') + def test_onapvtp_checker_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.OnapVtpChecker.create_log() + + self.assertEqual(getlogger_obj, dt_report.OnapVtpChecker.logger) + + def test_onapvtp_check_result_none(self): + testcase_obj = Mock() + result = {} + + dt_report.OnapVtpChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('FAIL') + + def test_onapvtp_check_result(self): + testcase_obj = Mock() + result = {'criteria': 'PASS'} + + dt_report.OnapVtpChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('PASS') + + @patch('dovetail.report.dt_logger') + def test_onapvvp_checker_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + dt_report.OnapVvpChecker.create_log() + + self.assertEqual(getlogger_obj, dt_report.OnapVvpChecker.logger) + + def test_onapvvp_check_result_none(self): + testcase_obj = Mock() + result = {} + + dt_report.OnapVvpChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('FAIL') + + def test_onapvvp_check_result(self): + testcase_obj = Mock() + result = {'criteria': 'PASS'} + + dt_report.OnapVvpChecker.check(testcase_obj, result) + + testcase_obj.passed.assert_called_once_with('PASS') + + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.os.path') + @patch('builtins.open') + @patch('dovetail.report.os.getenv') + def test_get_checksum_tosca(self, mock_env, mock_open, mock_path, + mock_config): + mock_config.dovetail_config = { + 'config_dir': 'config_dir' + } + mock_env.return_value = 'csar_file' + file_obj = Mock() + file_obj.read.return_value = 'info' + file_obj.__exit__ = Mock() + file_obj.__enter__ = Mock() + mock_open.return_value = file_obj + mock_path.isdir.return_value = False + mock_path.isfile.return_value = True + + dt_report.Report.get_checksum('tosca') + + @patch('dovetail.report.dt_cfg') + @patch('dovetail.report.os.path') + @patch('dovetail.report.os.walk') + @patch('builtins.open') + @patch('dovetail.report.os.getenv') + def test_get_checksum_heat(self, mock_env, mock_open, mock_walk, mock_path, + mock_config): + mock_config.dovetail_config = { + 'config_dir': 'config_dir' + } + mock_env.return_value = 'heat_templates_archive' + file_obj = Mock() + file_obj.read.return_value = 'info' + file_obj.__exit__ = Mock() + file_obj.__enter__ = Mock() + mock_open.return_value = file_obj + mock_path.isdir.return_value = True + mock_walk.return_value = [('root', ['dir'], ['file'])] + + dt_report.Report.get_checksum('heat') diff --git a/dovetail/tests/unit/test_run.py b/dovetail/tests/unit/test_run.py new file mode 100644 index 00000000..c1e37116 --- /dev/null +++ b/dovetail/tests/unit/test_run.py @@ -0,0 +1,655 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import os +import unittest +import yaml +from mock import patch, call, Mock +from _pytest.monkeypatch import MonkeyPatch + +from dovetail.utils.dovetail_config import DovetailConfig + +monkeypatch = MonkeyPatch() +conf_path = os.path.abspath( + os.path.join(os.path.dirname(__file__))) +file_path = os.path.join(os.path.dirname(__file__), 'cmd_config.yml') +with open(file_path) as f: + extra_config = yaml.safe_load(f) +monkeypatch.setattr(DovetailConfig, 'load_config_files', Mock()) +monkeypatch.setattr(DovetailConfig, 'dovetail_config', extra_config) +from dovetail import run as dt_run # noqa: E402 +monkeypatch.undo() + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class RunTesting(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('dovetail.run.dt_testcase.Testsuite') + def test_load_testsuite(self, mock_testsuite): + mock_testsuite.get.return_value = 'suite_a' + + result = dt_run.load_testsuite('testsuite') + + mock_testsuite.load.assert_called_once_with() + mock_testsuite.get.assert_called_once_with('testsuite') + self.assertEqual('suite_a', result) + + @patch('dovetail.run.dt_report.Report') + def test_run_test_no_list(self, mock_report): + logger = Mock() + mock_report.return_value = Mock() + + dt_run.run_test([], False, logger) + logger.warning.assert_called_once_with( + "No test case will be executed.") + + @patch('dovetail.run.datetime') + @patch('dovetail.run.dt_utils') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_report.Report') + @patch('dovetail.run.dt_testcase.Testcase') + @patch('dovetail.run.time') + @patch('os.getenv') + def test_run_test(self, mock_getenv, mock_time, mock_testcase, mock_report, + mock_config, mock_utils, mock_datetime): + logger = Mock() + report_obj = Mock() + mock_report.return_value = report_obj + mock_time.time.side_effect = [42, 43, 83, 84] + datetime_obj = Mock() + mock_datetime.fromtimestamp.return_value = datetime_obj + datetime_obj.strftime.side_effect = ['1969-12-31 19:00:43', + '1969-12-31 19:01:23'] + testcase_name = 'testcase' + testcase_obj = Mock() + mock_testcase.get.return_value = testcase_obj + mock_config.dovetail_config = {'stop': True} + mock_getenv.return_value = 'true' + report_obj.check_tc_result.return_value = {'criteria': 'PASS'} + mock_utils.push_results_to_db.return_value = True + + dt_run.run_test([testcase_name], True, logger) + + mock_time.time.assert_has_calls([call(), call(), call(), call()]) + logger.info.assert_called_once_with( + '>>[testcase]: {}'.format(testcase_name)) + mock_testcase.get.assert_called_once_with(testcase_name) + testcase_obj.run.assert_called_once_with() + report_obj.check_tc_result.assert_called_once_with(testcase_obj) + mock_utils.push_results_to_db.assert_called_once_with( + case_name=testcase_name, + start_date='1969-12-31 19:00:43', + stop_date='1969-12-31 19:01:23', + details={'criteria': 'PASS'}, + logger=logger) + report_obj.generate.assert_called_once_with([testcase_name], 42) + report_obj.save_logs.assert_called_once_with() + + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_report.Report') + @patch('dovetail.run.dt_testcase.Testcase') + @patch('dovetail.run.time') + def test_run_test_fail(self, mock_time, mock_testcase, mock_report, + mock_config): + logger = Mock() + report_obj = Mock() + mock_report.return_value = report_obj + testcase_name = 'testcase' + testcase_obj = Mock() + mock_testcase.get.return_value = testcase_obj + mock_config.dovetail_config = {'stop': True} + report_obj.check_tc_result.return_value = {'criteria': 'FAIL'} + + dt_run.run_test([testcase_name], True, logger) + + mock_time.time.assert_has_calls([call(), call(), call().__float__(), + call(), call().__float__()]) + logger.info.assert_has_calls([ + call('>>[testcase]: {}'.format(testcase_name)), + call('Stop because {} failed'.format(testcase_name))]) + mock_testcase.get.assert_called_once_with(testcase_name) + testcase_obj.run.assert_called_once_with() + report_obj.check_tc_result.assert_called_once_with(testcase_obj) + + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_report.Report') + @patch('dovetail.run.dt_testcase.Testcase') + @patch('dovetail.run.time') + def test_run_test_fail_key_error(self, mock_time, mock_testcase, + mock_report, mock_config): + logger = Mock() + report_obj = Mock() + mock_report.return_value = report_obj + mock_time.time.return_value = 42 + testcase_name = 'testcase' + testcase_obj = Mock() + mock_testcase.get.return_value = testcase_obj + mock_config.dovetail_config = {'stop': True} + report_obj.check_tc_result.return_value = {'key': 'value'} + + dt_run.run_test([testcase_name], True, logger) + + mock_time.time.assert_has_calls([call(), call(), call()]) + logger.info.assert_has_calls([ + call('>>[testcase]: {}'.format(testcase_name)), + call('Stop because {} failed'.format(testcase_name))]) + logger.error.assert_called_once_with("There is no key 'criteria'.") + mock_testcase.get.assert_called_once_with(testcase_name) + testcase_obj.run.assert_called_once_with() + report_obj.check_tc_result.assert_called_once_with(testcase_obj) + + @patch('dovetail.run.dt_cfg') + def test_filter_config(self, mock_config): + mock_config.dovetail_config = { + 'cli': { + 'key_a': { + 'config': { + 'config_key': {'path': 'a'}, + 'KEY_UPPER': {'path': 'b'} + } + }, + 'key_b': {}, + 'key_c': { + 'config': None + }, + 'key_d': { + 'invalid': {} + } + } + } + input_dict = { + 'config_key': 'c', + 'key_upper': 'd' + } + expected_dict = { + 'config_key': {'path': 'a', 'value': 'c'}, + 'KEY_UPPER': {'path': 'b', 'value': 'd'} + } + + result = dt_run.filter_config(input_dict, Mock()) + + self.assertEqual(expected_dict, result) + + @patch('dovetail.run.dt_cfg') + def test_filter_config_none(self, mock_config): + mock_config.dovetail_config = {'cli': {}} + result = dt_run.filter_config({}, Mock()) + + self.assertEqual(None, result) + + @patch('dovetail.run.dt_cfg') + def test_filter_config_keyerror(self, mock_config): + mock_config.dovetail_config = { + 'cli': { + 'key_a': { + 'config': { + 'config_key': {'invalid': 'a'} + } + } + } + } + input_dict = {'config_key': 'c'} + logger = Mock() + + with self.assertRaises(SystemExit) as cm: + dt_run.filter_config(input_dict, logger) + + logger.exception.assert_called_once_with("KeyError 'path'.") + expected = cm.exception + self.assertEqual(expected.code, 2) + + @patch('dovetail.run.Container') + @patch('dovetail.run.Parser') + @patch('dovetail.run.dt_report') + @patch('dovetail.run.dt_test_runner') + @patch('dovetail.run.dt_testcase') + def test_create_logs(self, mock_testcase, mock_test_runner, mock_report, + mock_parser, mock_container): + + dt_run.create_logs() + + mock_container.create_log.assert_called_once_with() + mock_parser.create_log.assert_called_once_with() + mock_report.Report.create_log.assert_called_once_with() + mock_report.FunctestCrawler.create_log.assert_called_once_with() + mock_report.YardstickCrawler.create_log.assert_called_once_with() + mock_report.BottlenecksCrawler.create_log.assert_called_once_with() + mock_report.FunctestChecker.create_log.assert_called_once_with() + mock_report.YardstickChecker.create_log.assert_called_once_with() + mock_report.BottlenecksChecker.create_log.assert_called_once_with() + mock_testcase.Testcase.create_log.assert_called_once_with() + mock_testcase.Testsuite.create_log.assert_called_once_with() + mock_test_runner.DockerRunner.create_log.assert_called_once_with() + mock_test_runner.ShellRunner.create_log.assert_called_once_with() + + @patch('dovetail.run.dt_utils') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.os') + def test_clean_results_dir(self, mock_os, mock_config, mock_utils): + mock_config.dovetail_config = {'result_dir': 'value'} + mock_os.path.exists.return_value = True + mock_os.path.isdir.return_value = True + + dt_run.clean_results_dir() + + mock_os.path.exists.assert_called_once_with('value') + mock_os.path.isdir.assert_called_once_with('value') + mock_utils.exec_cmd.assert_called_once_with( + 'rm -rf value/*', exit_on_error=False, exec_msg_on=False) + + @patch('dovetail.run.dt_utils') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.os') + def test_clean_results_dir_error(self, mock_os, mock_config, mock_utils): + mock_config.dovetail_config = {'result_dir': 'value'} + mock_os.path.exists.return_value = True + mock_os.path.isdir.return_value = False + + with self.assertRaises(SystemExit) as cm: + dt_run.clean_results_dir() + + mock_os.path.exists.assert_called_once_with('value') + mock_os.path.isdir.assert_called_once_with('value') + expected = cm.exception + self.assertEqual(expected.code, 2) + + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.os') + def test_get_result_path(self, mock_os, mock_config): + dovetail_home = 'dovetail_home' + mock_os.environ = {'DOVETAIL_HOME': dovetail_home} + mock_os.path.join.side_effect = [ + 'result_path', 'images_dir', 'pre_config_path', 'patch_set_path', + 'userconfig_dir'] + mock_config.dovetail_config = {} + + result = dt_run.get_result_path() + + mock_os.path.join.assert_has_calls([ + call(dovetail_home, 'results'), + call(dovetail_home, 'images'), + call(dovetail_home, 'pre_config'), + call(dovetail_home, 'patches'), + call(dovetail_home, 'userconfig')]) + expected_dict = { + 'result_dir': 'result_path', + 'images_dir': 'images_dir', + 'config_dir': 'pre_config_path', + 'patch_dir': 'patch_set_path', + 'userconfig_dir': 'userconfig_dir'} + self.assertEqual(expected_dict, mock_config.dovetail_config) + self.assertEqual(dovetail_home, result) + + @patch('dovetail.run.os') + def test_get_result_path_exception(self, mock_os): + mock_os.environ = {} + + result = dt_run.get_result_path() + + self.assertEqual(None, result) + + @patch('dovetail.run.constants') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_utils') + @patch('dovetail.run.os') + def test_copy_userconfig_files(self, mock_os, mock_utils, mock_config, + mock_constants): + mock_config.dovetail_config = {'userconfig_dir': 'value'} + mock_os.path.isdir.return_value = False + mock_constants.USERCONF_PATH = 'value' + logger = Mock() + + dt_run.copy_userconfig_files(logger) + + mock_os.path.isdir.assert_called_once_with('value') + mock_os.makedirs.assert_called_once_with('value') + mock_utils.exec_cmd.assert_called_once_with( + 'cp -r value/* value', logger, exit_on_error=False) + + @patch('dovetail.run.constants') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_utils') + @patch('dovetail.run.os') + def test_copy_patch_files(self, mock_os, mock_utils, mock_config, + mock_constants): + mock_config.dovetail_config = {'patch_dir': 'value'} + mock_os.path.isdir.return_value = False + mock_constants.PATCH_PATH = 'value' + logger = Mock() + + dt_run.copy_patch_files(logger) + + mock_os.path.isdir.assert_called_once_with('value') + mock_os.makedirs.assert_called_once_with('value') + mock_utils.exec_cmd.assert_called_once_with( + 'cp -a -r value/* value', logger, exit_on_error=False) + + @patch('dovetail.run.os') + def test_update_deploy_scenario(self, mock_os): + logger = Mock() + mock_os.environ = {} + + dt_run.update_deploy_scenario(logger, deploy_scenario='a') + + logger.info.assert_called_once_with('DEPLOY_SCENARIO : %s', 'a') + self.assertEqual({'DEPLOY_SCENARIO': 'a'}, mock_os.environ) + + @patch('dovetail.run.dt_cfg') + @patch.object(dt_run, 'filter_config') + def test_cli_no_validation(self, mock_filter, mock_config): + mock_config.dovetail_config = {} + logger = Mock() + + dt_run.parse_cli(logger=logger, + offline='a', + no_clean='b', + stop='c', + mandatory='d', + optional='e', + no_api_validation=True) + expected_dict = { + 'offline': 'a', + 'noclean': 'b', + 'stop': 'c', + 'mandatory': 'd', + 'optional': 'e', + 'no_api_validation': True + } + + logger.warning.assert_called_once_with( + 'Strict API response validation DISABLED.') + self.assertEqual(expected_dict, mock_config.dovetail_config) + + @patch('dovetail.run.dt_cfg') + @patch.object(dt_run, 'filter_config') + def test_cli_with_validation(self, mock_filter, mock_config): + mock_config.dovetail_config = {} + + dt_run.parse_cli(offline='a', + no_clean='b', + stop='c', + mandatory='d', + optional='e', + no_api_validation=False) + expected_dict = { + 'offline': 'a', + 'noclean': 'b', + 'stop': 'c', + 'mandatory': 'd', + 'optional': 'e', + 'no_api_validation': False + } + + self.assertEqual(expected_dict, mock_config.dovetail_config) + + def test_check_testcase_list_not_in_list(self): + logger = Mock() + + result = dt_run.check_testcase_list(['testcase'], logger) + + logger.error.assert_called_once_with( + 'Test case testcase is not defined.') + self.assertEqual(None, result) + + def test_check_testcase_list_none(self): + logger = Mock() + result = dt_run.check_testcase_list(None, logger) + + logger.error.assert_called_once_with( + 'There is no test case to be executed.') + self.assertEqual(None, result) + + @patch('dovetail.run.dt_testcase.Testcase') + def test_check_testcase_list(self, mock_testcase): + testcase_list = ['testcase'] + mock_testcase.testcase_list = testcase_list + + result = dt_run.check_testcase_list(testcase_list) + + self.assertEqual(testcase_list, result) + + @patch('dovetail.run.dt_testcase.Testcase') + @patch.object(dt_run, 'check_testcase_list') + def test_get_testcase_list_check(self, mock_check, mock_testcase): + testcase_list = ['testcase'] + mock_check.return_value = testcase_list + + result = dt_run.get_testcase_list(testcase=testcase_list) + + mock_check.assert_called_once_with(testcase_list, None) + mock_testcase.load.assert_called_once_with() + self.assertEqual(testcase_list, result) + + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_testcase.Testcase') + @patch.object(dt_run, 'check_testcase_list') + @patch.object(dt_run, 'load_testsuite') + def test_get_testcase_list(self, mock_load, mock_check, mock_testcase, + mock_config): + mock_config.dovetail_config = {'testsuite_supported': ['suite']} + testcase_list = ['testcase'] + mock_testcase.check_testarea.return_value = (True, 'area') + mock_load.return_value = 'testsuite_yaml' + mock_testcase.get_testcases_for_testsuite.return_value = testcase_list + mock_check.return_value = testcase_list + + result = dt_run.get_testcase_list( + testcase=None, testsuite='suite', testarea='area') + + mock_testcase.load.assert_called_once_with() + mock_testcase.check_testarea.assert_called_once_with('area') + mock_load.assert_called_once_with('suite') + mock_testcase.get_testcases_for_testsuite.assert_called_once_with( + 'testsuite_yaml', 'area') + mock_check.assert_called_once_with(testcase_list, None) + self.assertEqual(testcase_list, result) + + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_testcase.Testcase') + def test_get_testcase_list_no_testsuite(self, mock_testcase, mock_config): + logger = Mock() + mock_config.dovetail_config = {'testsuite_supported': []} + mock_testcase.check_testarea.return_value = (True, 'area') + + result = dt_run.get_testcase_list( + logger, testcase=None, testsuite='suite', testarea='area') + + mock_testcase.load.assert_called_once_with() + mock_testcase.check_testarea.assert_called_once_with('area') + logger.error.assert_called_once_with( + 'Test suite suite is not defined.') + self.assertEqual(None, result) + + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_testcase.Testcase') + def test_get_testcase_list_no_testarea(self, mock_testcase, mock_config): + logger = Mock() + mock_config.dovetail_config = {'testsuite_supported': ['suite']} + mock_testcase.check_testarea.return_value = (False, 'area') + + result = dt_run.get_testcase_list( + logger, testcase=None, testsuite='suite', testarea='area') + + mock_testcase.load.assert_called_once_with() + mock_testcase.check_testarea.assert_called_once_with('area') + logger.error.assert_called_once_with( + 'Test area area is not defined.') + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.run.os') + @patch('dovetail.run.json') + @patch('dovetail.run.uuid') + @patch('dovetail.run.dt_logger') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_utils') + @patch.object(dt_run, 'get_result_path') + @patch.object(dt_run, 'clean_results_dir') + @patch.object(dt_run, 'parse_cli') + @patch.object(dt_run, 'update_deploy_scenario') + @patch.object(dt_run, 'copy_userconfig_files') + @patch.object(dt_run, 'copy_patch_files') + @patch.object(dt_run, 'get_testcase_list') + @patch.object(dt_run, 'run_test') + @patch.object(dt_run, 'create_logs') + def test_main(self, mock_create_logs, mock_run, mock_get_list, + mock_copy_patch, mock_copy_userconf, mock_update, mock_parse, + mock_clean, mock_get_result, mock_utils, mock_config, + mock_logger, mock_uuid, mock_json, mock_os, mock_open): + mock_config.dovetail_config = {} + mock_os.environ = {'DOVETAIL_HOME': 'dovetail_home'} + logger_obj = Mock() + logger_temp_obj = Mock() + file_obj = Mock() + logger_temp_obj.getLogger.return_value = logger_obj + mock_logger.Logger.return_value = logger_temp_obj + mock_open.return_value.__enter__.return_value = file_obj + mock_json.dumps.return_value = 'results text' + mock_uuid.uuid1.return_value = 42 + mock_get_result.return_value = True + testcase_list = ['testcase'] + mock_get_list.return_value = testcase_list + kwargs_dict = { + 'debug': True, + 'opnfv_ci': True, + 'report': True, + 'testsuite': 'testsuite', + 'docker_tag': '2.0.0', + 'no_api_validation': False + } + + with self.assertRaises(SystemExit) as cm: + dt_run.main(['--testsuite=testsuite', '--debug', '--report', + '2.0.0', '--opnfv-ci']) + expected = cm.exception + + logger_temp_obj.getLogger.assert_called_once_with() + mock_logger.Logger.assert_called_once_with('run') + mock_uuid.uuid1.assert_called_once_with() + self.assertEqual({'build_tag': 'daily-master-42'}, + mock_config.dovetail_config) + mock_get_result.assert_called_once_with() + mock_clean.assert_called_once_with() + self.assertEqual({'DOVETAIL_HOME': 'dovetail_home', 'DEBUG': 'true', + 'OPNFV_CI': 'true', 'validation': 'enabled'}, + mock_os.environ) + mock_create_logs.assert_called_once_with() + logger_obj.info.assert_has_calls([ + call('================================================'), + call('Dovetail compliance: testsuite!'), + call('================================================'), + call('Build tag: daily-master-42')]) + mock_parse.assert_called_once_with(logger_obj, **kwargs_dict) + mock_update.assert_called_once_with(logger_obj, **kwargs_dict) + mock_copy_userconf.assert_called_once_with(logger_obj) + mock_copy_patch.assert_called_once_with(logger_obj) + mock_utils.check_docker_version.assert_called_once_with(logger_obj) + mock_get_list.assert_called_once_with(logger_obj, **kwargs_dict) + mock_run.assert_called_once_with( + testcase_list, kwargs_dict['report'], logger_obj) + self.assertEqual(expected.code, 0) + + @patch('dovetail.run.uuid') + @patch('dovetail.run.dt_cfg') + @patch.object(dt_run, 'get_result_path') + def test_main_no_results_path(self, mock_get_result, mock_config, + mock_uuid): + mock_config.dovetail_config = {} + mock_uuid.uuid1.return_value = 42 + mock_get_result.return_value = False + + with self.assertRaises(SystemExit) as cm: + dt_run.main(['2.0.0']) + expected = cm.exception + + mock_uuid.uuid1.assert_called_once_with() + self.assertEqual({'build_tag': 'daily-master-42'}, + mock_config.dovetail_config) + mock_get_result.assert_called_once_with() + self.assertEqual(expected.code, 0) + + @patch('builtins.open') + @patch('dovetail.run.json') + @patch('dovetail.run.os') + @patch('dovetail.run.uuid') + @patch('dovetail.run.dt_logger') + @patch('dovetail.run.dt_cfg') + @patch('dovetail.run.dt_utils') + @patch.object(dt_run, 'get_result_path') + @patch.object(dt_run, 'clean_results_dir') + @patch.object(dt_run, 'update_deploy_scenario') + @patch.object(dt_run, 'copy_userconfig_files') + @patch.object(dt_run, 'copy_patch_files') + @patch.object(dt_run, 'get_testcase_list') + @patch.object(dt_run, 'parse_cli') + @patch.object(dt_run, 'run_test') + @patch.object(dt_run, 'create_logs') + def test_main_no_testcaselist(self, mock_create_logs, mock_run, mock_parse, + mock_get_list, mock_copy_patch, + mock_copy_userconf, mock_update, mock_clean, + mock_get_result, mock_utils, mock_config, + mock_logger, mock_uuid, mock_os, mock_json, + mock_open): + mock_config.dovetail_config = {} + mock_os.environ = {'DOVETAIL_HOME': 'dovetail_home'} + logger_obj = Mock() + logger_temp_obj = Mock() + file_obj = Mock() + logger_temp_obj.getLogger.return_value = logger_obj + mock_logger.Logger.return_value = logger_temp_obj + mock_open.return_value.__enter__.return_value = file_obj + mock_json.dumps.return_value = 'results text' + mock_uuid.uuid1.return_value = 42 + mock_get_result.return_value = True + mock_get_list.return_value = None + kwargs_dict = { + 'debug': True, + 'opnfv_ci': False, + 'report': True, + 'testsuite': 'testsuite', + 'docker_tag': '2.0.0', + 'no_api_validation': False + } + + with self.assertRaises(SystemExit) as cm: + dt_run.main([ + '--testsuite=testsuite', '--debug', '--report', '2.0.0']) + expected = cm.exception + self.assertEqual(expected.code, 2) + + logger_temp_obj.getLogger.assert_called_once_with() + mock_logger.Logger.assert_called_once_with('run') + mock_uuid.uuid1.assert_called_once_with() + self.assertEqual({'build_tag': 'daily-master-42'}, + mock_config.dovetail_config) + mock_get_result.assert_called_once_with() + mock_clean.assert_called_once_with() + self.assertEqual({'DOVETAIL_HOME': 'dovetail_home', 'DEBUG': 'true', + 'OPNFV_CI': 'false', 'validation': 'enabled'}, + mock_os.environ) + mock_create_logs.assert_called_once_with() + logger_obj.info.assert_has_calls([ + call('================================================'), + call('Dovetail compliance: testsuite!'), + call('================================================'), + call('Build tag: daily-master-42')]) + mock_parse.assert_called_once_with(logger_obj, **kwargs_dict) + mock_update.assert_called_once_with(logger_obj, **kwargs_dict) + mock_copy_userconf.assert_called_once_with(logger_obj) + mock_copy_patch.assert_called_once_with(logger_obj) + mock_utils.check_docker_version.assert_called_once_with(logger_obj) + mock_get_list.assert_called_once_with(logger_obj, **kwargs_dict) diff --git a/dovetail/tests/unit/test_test_runner.py b/dovetail/tests/unit/test_test_runner.py new file mode 100644 index 00000000..232de7b1 --- /dev/null +++ b/dovetail/tests/unit/test_test_runner.py @@ -0,0 +1,712 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import unittest +from mock import patch, call, Mock + +import dovetail.test_runner as t_runner + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class TestRunnerTesting(unittest.TestCase): + + def setUp(self): + self.patcher1 = patch.object(t_runner, 'dt_logger') + self.patcher2 = patch.object(t_runner.DockerRunner, + '_update_config') + + self.logger = self.patcher1.start().return_value + self._update_config = self.patcher2.start().return_value + + self.testcase = Mock() + self.testcase_name = 'testcase_name' + self.testcase_type = 'functest' + self.testcase_dict = {} + self.testcase_valid = 'validate_testcase' + + self.testcase.testcase = self.testcase_dict + self.testcase.name.return_value = self.testcase_name + self.testcase.validate_testcase.return_value = self.testcase_valid + self.testcase.validate_type.return_value = self.testcase_type + + def tearDown(self): + self.patcher1.stop() + self.patcher2.stop() + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.Container') + def test_run_offline_not_exist(self, mock_container, mock_config, + mock_utils): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'offline': True, 'result_dir': 'result_dir' + } + docker_runner = t_runner.TestRunnerFactory.create(self.testcase) + + container_obj = Mock() + docker_img_obj = Mock() + container_obj.get_docker_image.return_value = docker_img_obj + container_obj.get_image_id.return_value = False + mock_container.return_value = container_obj + + docker_runner.run() + + mock_container.assert_called_once_with(self.testcase) + container_obj.get_docker_image.assert_called_once_with() + container_obj.get_image_id.assert_called_once_with(docker_img_obj) + docker_runner.logger.error.assert_called_once_with( + "{} image doesn't exist, can't run offline.".format( + self.testcase_type)) + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.Container') + def test_run__not_offline_no_pull(self, mock_container, mock_config, + mock_utils): + t_runner.YardstickRunner.create_log() + mock_config.dovetail_config = { + 'offline': False, 'result_dir': 'result_dir' + } + docker_runner = t_runner.YardstickRunner(self.testcase) + + container_obj = Mock() + docker_img_obj = Mock() + container_obj.get_docker_image.return_value = docker_img_obj + container_obj.pull_image.return_value = False + mock_container.return_value = container_obj + + docker_runner.run() + + mock_container.assert_called_once_with(self.testcase) + container_obj.get_docker_image.assert_called_once_with() + container_obj.pull_image.assert_called_once_with(docker_img_obj) + docker_runner.logger.error.assert_called_once_with( + 'Failed to pull the image.') + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.Container') + def test_run__not_offline_no_create(self, mock_container, mock_config, + mock_utils): + t_runner.BottlenecksRunner.create_log() + mock_config.dovetail_config = { + 'offline': False, 'result_dir': 'result_dir' + } + docker_runner = t_runner.BottlenecksRunner(self.testcase) + + container_obj = Mock() + docker_img_obj = Mock() + container_obj.get_docker_image.return_value = docker_img_obj + container_obj.pull_image.return_value = True + container_obj.create.return_value = [None, 'error'] + mock_container.return_value = container_obj + + docker_runner.run() + + mock_container.assert_called_once_with(self.testcase) + container_obj.get_docker_image.assert_called_once_with() + container_obj.pull_image.assert_called_once_with(docker_img_obj) + container_obj.create.assert_called_once_with(docker_img_obj) + docker_runner.logger.error.assert_has_calls([ + call('Failed to create container.'), call('error')]) + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.Container') + def test_run__not_offline_no_prepare(self, mock_container, + mock_config, mock_utils): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'offline': False, + 'noclean': False, + 'result_dir': 'result_dir' + } + docker_runner = t_runner.FunctestRunner(self.testcase) + + container_obj = Mock() + docker_img_obj = Mock() + container_obj.get_docker_image.return_value = docker_img_obj + container_obj.pull_image.return_value = True + container_id = '12345' + container_msg = 'Successfully to create container.' + container_obj.create.return_value = [container_id, container_msg] + mock_container.return_value = container_obj + self.testcase.pre_condition.return_value = ['cmd'] + self.testcase.prepare_cmd.return_value = False + self.testcase.post_condition.return_value = ['cmd'] + container_obj.exec_cmd.return_value = (1, 'error') + + docker_runner.run() + + mock_container.assert_called_once_with(self.testcase) + container_obj.get_docker_image.assert_called_once_with() + container_obj.pull_image.assert_called_once_with(docker_img_obj) + container_obj.create.assert_called_once_with(docker_img_obj) + docker_runner.logger.debug.assert_called_with( + 'container id: {}'.format(container_id)) + self.testcase.pre_condition.assert_called_once_with() + container_obj.exec_cmd.assert_has_calls([ + call('cmd'), call('cmd')]) + self.testcase.prepare_cmd.assert_called_once_with(self.testcase_type) + self.testcase.post_condition.assert_called_once_with() + docker_runner.logger.error.assert_has_calls([ + call('Failed to exec all pre_condition cmds.'), + call('Failed to prepare test case: {}' + .format(self.testcase_name))]) + container_obj.clean.assert_called_once_with() + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.Container') + def test_run__not_offline_prepare(self, mock_container, + mock_config, mock_utils): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'offline': False, + 'noclean': False, + 'result_dir': 'result_dir' + } + docker_runner = t_runner.FunctestRunner(self.testcase) + container_obj = Mock() + docker_img_obj = Mock() + container_obj.get_docker_image.return_value = docker_img_obj + container_obj.pull_image.return_value = True + container_id = '12345' + container_msg = 'Successfully to create container.' + container_obj.create.return_value = [container_id, container_msg] + mock_container.return_value = container_obj + self.testcase.pre_condition.return_value = ['cmd'] + self.testcase.prepare_cmd.return_value = True + self.testcase.post_condition.return_value = ['cmd'] + self.testcase.cmds = ['cmd'] + container_obj.exec_cmd.return_value = (1, 'error') + + docker_runner.run() + + mock_container.assert_called_once_with(self.testcase) + container_obj.get_docker_image.assert_called_once_with() + container_obj.pull_image.assert_called_once_with(docker_img_obj) + container_obj.create.assert_called_once_with(docker_img_obj) + docker_runner.logger.debug.assert_called_with( + 'container id: {}'.format(container_id)) + self.testcase.pre_condition.assert_called_once_with() + container_obj.exec_cmd.assert_has_calls([ + call('cmd'), call('cmd'), call('cmd')]) + self.testcase.prepare_cmd.assert_called_once_with(self.testcase_type) + self.testcase.post_condition.assert_called_once_with() + docker_runner.logger.error.assert_has_calls([ + call('Failed to exec all pre_condition cmds.'), + call('Failed to exec {}, ret: {}, msg: {}' + .format('cmd', 1, 'error'))]) + container_obj.clean.assert_called_once_with() + + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os') + def test_archive_logs_no_files(self, mock_os, mock_utils, mock_config): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = {'result_dir': 'result_dir'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_os.environ = {'DOVETAIL_HOME': 'dovetail_home'} + mock_utils.get_value_from_dict.return_value = [] + + result = docker_runner.archive_logs() + + mock_os.path.join.assert_has_calls([call('dovetail_home', 'results')]) + mock_utils.get_value_from_dict.assert_has_calls([ + call('report.source_archive_files', self.testcase_dict), + call('report.dest_archive_files', self.testcase_dict)]) + self.assertEqual(True, result) + + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os') + def test_archive_logs_difference_in_files(self, mock_os, mock_utils, + mock_config): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = {'result_dir': 'result_dir'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_os.environ = {'DOVETAIL_HOME': 'dovetail_home'} + mock_utils.get_value_from_dict.side_effect = [[], ['file']] + + result = docker_runner.archive_logs() + + mock_os.path.join.assert_has_calls([call('dovetail_home', 'results')]) + mock_utils.get_value_from_dict.assert_has_calls([ + call('report.source_archive_files', self.testcase_dict), + call('report.dest_archive_files', self.testcase_dict)]) + docker_runner.logger.error.assert_called_once_with( + "Can't find corresponding 'result_dest_files' " + "for 'result_source_files' with testcase {}" + .format(self.testcase_name)) + self.assertEqual(False, result) + + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os') + def test_archive_logs_src_file_error(self, mock_os, mock_utils, + mock_config): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = {'result_dir': 'result_dir'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_os.environ = {'DOVETAIL_HOME': 'dovetail_home'} + mock_utils.get_value_from_dict.side_effect = [['src_file'], + ['dst_file']] + mock_os.path.join.side_effect = ['result_path', 'src_file_path', + 'dest_file_path'] + mock_os.path.isfile.return_value = False + + result = docker_runner.archive_logs() + + mock_os.path.join.assert_has_calls([ + call('dovetail_home', 'results'), + call('result_path', 'src_file'), + call('result_path', 'dst_file')]) + mock_utils.get_value_from_dict.assert_has_calls([ + call('report.source_archive_files', self.testcase_dict), + call('report.dest_archive_files', self.testcase_dict)]) + mock_os.path.isfile.assert_has_calls([call('src_file_path')]) + docker_runner.logger.error.assert_called_once_with( + "Can't find file {}.".format('src_file_path')) + self.assertEqual(False, result) + + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os') + def test_archive_logs_src_file_exists(self, mock_os, mock_utils, + mock_config): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = {'result_dir': 'result_dir'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_os.environ = {'DOVETAIL_HOME': 'dovetail_home'} + mock_utils.get_value_from_dict.side_effect = [['src_file'], + ['dst_file']] + mock_os.path.join.side_effect = ['result_path', 'src_file_path', + 'dest_file_path'] + mock_os.path.isfile.return_value = True + + result = docker_runner.archive_logs() + + mock_os.path.join.assert_has_calls([ + call('dovetail_home', 'results'), + call('result_path', 'src_file'), + call('result_path', 'dst_file')]) + mock_utils.get_value_from_dict.assert_has_calls([ + call('report.source_archive_files', self.testcase_dict), + call('report.dest_archive_files', self.testcase_dict)]) + mock_os.path.isfile.assert_has_calls([call('src_file_path')]) + mock_os.renames.assert_called_once_with( + 'src_file_path', 'dest_file_path') + self.assertEqual(True, result) + + @patch('dovetail.test_runner.jinja2') + def test_render(self, mock_jinja): + render_obj = Mock() + template_obj = Mock() + mock_jinja.Template.return_value = template_obj + template_obj.render.return_value = render_obj + + result = t_runner.FunctestRunner._render('task_template') + + mock_jinja.Template.assert_called_once_with('task_template') + template_obj.render.assert_called_with() + self.assertEqual(render_obj, result) + + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.os') + def test_add_testcase_info(self, mock_os, mock_config): + mock_os.getenv.side_effect = ['os_insecure', 'dovetail_home', 'debug', + 'os_cacert', 'host_url', 'csar_file', + 'heat_templates_archive'] + mock_os.environ = {'DEPLOY_SCENARIO': 'deploy_scenario'} + mock_config.dovetail_config = {'build_tag': 'build_tag'} + + expected = { + 'validate_testcase': 'validate_testcase', + 'testcase': 'testcase_name', 'os_insecure': 'os_insecure', + 'deploy_scenario': 'deploy_scenario', + 'dovetail_home': 'dovetail_home', 'debug': 'debug', + 'build_tag': 'build_tag', 'cacert': 'os_cacert', + 'host_url': 'host_url', 'csar_file': 'csar_file', + 'heat_templates_archive': 'heat_templates_archive' + } + result = t_runner.FunctestRunner._add_testcase_info(self.testcase) + + self.testcase.validate_testcase.assert_called_once_with() + self.testcase.name.assert_called_once_with() + mock_os.getenv.assert_has_calls([ + call('OS_INSECURE'), call('DOVETAIL_HOME'), call('DEBUG'), + call('OS_CACERT'), call('HOST_URL'), call('CSAR_FILE'), + call('VNF_ARCHIVE_NAME')]) + self.assertEqual(expected, result) + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.constants') + def test_update_config_no_task_template(self, mock_const, mock_path, + mock_config, mock_utils): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'config_dir': 'one', 'pod_file': 'two', 'result_dir': 'three'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_path.join.side_effect = ['config_file', 'pod_file'] + mock_utils.read_yaml_file.return_value = 'pod_info' + mock_utils.read_plain_file.return_value = None + mock_const.CONF_PATH = 'conf_path' + + self.patcher2.stop() + result = docker_runner._update_config(self.testcase) + self.patcher2.start() + + mock_path.join.assert_has_calls([ + call('three', 'endpoint_info.json'), + call('conf_path', docker_runner.config_file_name)]) + mock_utils.read_plain_file.assert_called_once_with( + 'config_file', docker_runner.logger) + self.assertEqual(None, result) + + @patch('dovetail.test_runner.yaml.safe_load') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.constants') + @patch.object(t_runner.DockerRunner, '_add_testcase_info') + @patch.object(t_runner.DockerRunner, '_render') + def test_update_config_pod_info_key_err(self, mock_render, mock_add_info, + mock_const, mock_path, mock_config, + mock_utils, mock_load): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'config_dir': 'one', 'pod_file': 'two', 'result_dir': 'three'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_path.join.side_effect = ['config_file', 'pod_file'] + mock_utils.read_yaml_file.return_value = {'key': 'value'} + mock_utils.read_plain_file.return_value = True + mock_const.CONF_PATH = 'conf_path' + mock_add_info.return_value = {'config_item': 'item'} + mock_render.return_value = 'full_task' + mock_load.return_value = {'full_task_yaml': 'full_value'} + + self.patcher2.stop() + result = docker_runner._update_config(self.testcase) + self.patcher2.start() + + mock_path.join.assert_has_calls([ + call('three', 'endpoint_info.json'), + call('conf_path', docker_runner.config_file_name), + call('one', 'two')]) + mock_add_info.assert_called_once_with(self.testcase) + mock_render.assert_called_once_with(True, config_item='item') + mock_load.assert_called_once_with('full_task') + self.assertEqual( + {'config_dir': 'one', + 'pod_file': 'two', + 'full_task_yaml': 'full_value', + 'result_dir': 'three'}, + result) + + @patch('dovetail.test_runner.yaml.safe_load') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.constants') + @patch.object(t_runner.DockerRunner, '_add_testcase_info') + @patch.object(t_runner.DockerRunner, '_render') + def test_update_config_pod_info_no_info(self, mock_render, mock_add_info, + mock_const, mock_path, mock_config, + mock_utils, mock_load): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'config_dir': 'one', 'pod_file': 'two', 'result_dir': 'three'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_path.join.side_effect = ['config_file', 'pod_file'] + mock_utils.read_yaml_file.return_value = False + mock_utils.read_plain_file.return_value = True + mock_const.CONF_PATH = 'conf_path' + mock_add_info.return_value = {'config_item': 'item'} + mock_render.return_value = 'full_task' + mock_load.return_value = {'full_task_yaml': 'full_value'} + + self.patcher2.stop() + result = docker_runner._update_config(self.testcase) + self.patcher2.start() + + mock_path.join.assert_has_calls([ + call('three', 'endpoint_info.json'), + call('conf_path', docker_runner.config_file_name), + call('one', 'two')]) + mock_add_info.assert_called_once_with(self.testcase) + mock_render.assert_called_once_with(True, config_item='item') + mock_load.assert_called_once_with('full_task') + self.assertEqual( + {'config_dir': 'one', + 'pod_file': 'two', + 'full_task_yaml': 'full_value', + 'result_dir': 'three'}, + result) + + @patch('dovetail.test_runner.yaml.safe_load') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.constants') + @patch.object(t_runner.DockerRunner, '_add_testcase_info') + @patch.object(t_runner.DockerRunner, '_render') + def test_update_config_pod_info(self, mock_render, mock_add_info, + mock_const, mock_path, mock_config, + mock_utils, mock_load): + t_runner.FunctestRunner.create_log() + mock_config.dovetail_config = { + 'config_dir': 'one', 'pod_file': 'two', 'result_dir': 'three'} + docker_runner = t_runner.FunctestRunner(self.testcase) + mock_path.join.side_effect = ['config_file', 'pod_file'] + mock_utils.read_yaml_file.return_value = { + 'process_info': [ + {'key': 'value'}, {'testcase_name': self.testcase_name} + ]} + mock_utils.read_plain_file.return_value = True + mock_const.CONF_PATH = 'conf_path' + mock_add_info.return_value = {'config_item': 'item'} + mock_render.return_value = 'full_task' + mock_load.return_value = {'full_task_yaml': 'full_value'} + + self.patcher2.stop() + result = docker_runner._update_config(self.testcase) + self.patcher2.start() + + mock_path.join.assert_has_calls([ + call('three', 'endpoint_info.json'), + call('conf_path', docker_runner.config_file_name), + call('one', 'two')]) + mock_add_info.assert_called_once_with( + self.testcase, {'testcase_name': self.testcase_name}) + docker_runner.logger.error.assert_called_once_with( + "Need key '{}' in {}".format('testcase_name', {'key': 'value'})) + mock_render.assert_called_once_with(True, config_item='item') + mock_load.assert_called_once_with('full_task') + self.assertEqual( + {'config_dir': 'one', + 'pod_file': 'two', + 'full_task_yaml': 'full_value', + 'result_dir': 'three'}, + result) + + @patch('builtins.open') + @patch('dovetail.test_runner.json') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + def test_shell_run_prepare_cmd(self, mock_path, mock_utils, mock_config, + mock_json, mock_open): + t_runner.ShellRunner.create_log() + docker_runner = t_runner.ShellRunner(self.testcase) + self.testcase.cmds = ['cmd'] + self.testcase.pre_condition.return_value = ['cmd'] + self.testcase.post_condition.return_value = ['cmd'] + self.testcase.prepare_cmd.return_value = True + mock_utils.exec_cmd.return_value = (1, 'error') + mock_path.join.return_value = 'join_path' + mock_config.dovetail_config = {'result_dir': 'result'} + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + dump_obj = Mock() + mock_json.dumps.return_value = dump_obj + + docker_runner.run() + + self.testcase.pre_condition.assert_called_once_with() + self.testcase.prepare_cmd.assert_called_once_with(docker_runner.type) + docker_runner.logger.error.assert_called_once_with( + 'Failed to execute all pre_condition cmds.') + mock_utils.exec_cmd.assert_has_calls([ + call('cmd', docker_runner.logger), + call('cmd', docker_runner.logger), + call('cmd', docker_runner.logger)]) + self.testcase.post_condition.assert_called_once_with() + mock_path.join.assert_called_once_with( + 'result', self.testcase_name) + docker_runner.logger.debug.assert_called_with( + 'Save result: {}'.format('join_path.out')) + mock_open.assert_called_once_with('join_path.out', 'w') + mock_json.dumps.assert_called_once_with( + {'results': [ + ('cmd', 1, 'error'), + ('cmd', 1, 'error'), + ('cmd', 1, 'error')], + 'pass': 'FAIL'}) + file_obj.write.assert_called_once_with(dump_obj) + + @patch('builtins.open') + @patch('dovetail.test_runner.dt_cfg') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + def test_shell_run_no_prepare_cmd_and_exception(self, mock_path, + mock_utils, mock_config, + mock_open): + t_runner.ShellRunner.create_log() + docker_runner = t_runner.ShellRunner(self.testcase) + self.testcase.cmds = ['cmd'] + self.testcase.pre_condition.return_value = ['cmd'] + self.testcase.post_condition.return_value = ['cmd'] + self.testcase.prepare_cmd.return_value = False + mock_utils.exec_cmd.return_value = (1, 'error') + mock_path.join.return_value = 'join_path' + mock_config.dovetail_config = {'result_dir': 'result'} + mock_open.return_value.__enter__.side_effect = Exception('error') + + docker_runner.run() + + self.testcase.pre_condition.assert_called_once_with() + self.testcase.prepare_cmd.assert_called_once_with(docker_runner.type) + docker_runner.logger.error.assert_has_calls([ + call('Failed to execute all pre_condition cmds.'), + call('Failed to prepare cmd: {}'.format(self.testcase_name))]) + mock_utils.exec_cmd.assert_has_calls([ + call('cmd', docker_runner.logger), + call('cmd', docker_runner.logger)]) + self.testcase.post_condition.assert_called_once_with() + mock_path.join.assert_called_once_with( + 'result', self.testcase_name) + docker_runner.logger.debug.assert_called_with( + 'Save result: {}'.format('join_path.out')) + mock_open.assert_called_once_with('join_path.out', 'w') + + def test_factory_error(self): + self.testcase.validate_type.return_value = 'unknown' + docker_runner = t_runner.TestRunnerFactory() + + result = docker_runner.create(self.testcase) + + self.assertEqual(None, result) + + @patch('dovetail.test_runner.constants') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + def test_k8s_update_config_no_task_template(self, mock_path, mock_utils, + mock_const): + t_runner.FunctestK8sRunner.create_log() + mock_utils.read_plain_file.return_value = None + mock_path.join.side_effect = ['config_file'] + mock_const.CONF_PATH = 'conf_path' + docker_runner = t_runner.FunctestK8sRunner(self.testcase) + + self.patcher2.stop() + result = docker_runner._update_config(self.testcase, update_pod=False) + self.patcher2.start() + + mock_path.join.assert_has_calls([ + call('conf_path', docker_runner.config_file_name)]) + mock_utils.read_plain_file.assert_has_calls([ + call('config_file', docker_runner.logger)]) + self.assertEqual(None, result) + + @patch('dovetail.test_runner.yaml.safe_load') + @patch('dovetail.test_runner.constants') + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.dt_cfg') + @patch.object(t_runner.DockerRunner, '_add_testcase_info') + @patch.object(t_runner.DockerRunner, '_render') + def test_k8s_update_config(self, mock_render, mock_add_info, mock_config, + mock_path, mock_utils, mock_const, mock_load): + t_runner.FunctestK8sRunner.create_log() + mock_utils.read_plain_file.return_value = True + mock_path.join.side_effect = ['config_file', 'config_file'] + mock_const.CONF_PATH = 'conf_path' + mock_add_info.return_value = {'config_item': 'item'} + mock_render.return_value = 'full_task' + mock_load.return_value = {'full_task_yaml': 'full_value'} + mock_config.dovetail_config = { + 'config_dir': 'one', 'pod_file': 'two'} + + docker_runner = t_runner.FunctestK8sRunner(self.testcase) + self.patcher2.stop() + result = docker_runner._update_config(self.testcase, update_pod=False) + self.patcher2.start() + + mock_path.join.assert_has_calls([ + call('conf_path', docker_runner.config_file_name)]) + mock_utils.read_plain_file.assert_has_calls([ + call('config_file', docker_runner.logger)]) + mock_add_info.assert_has_calls([call(self.testcase)]) + mock_render.assert_has_calls([call(True, config_item='item')]) + mock_load.assert_has_calls([call('full_task')]) + self.assertEqual( + {'config_dir': 'one', + 'pod_file': 'two', + 'full_task_yaml': 'full_value'}, + result) + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.dt_cfg') + def test_init_onapvtprunner_no_env_file(self, mock_config, mock_path, + mock_utils): + t_runner.OnapVtpRunner.create_log() + mock_path.join.side_effect = ['env_file'] + mock_config.dovetail_config = {'config_dir': 'one', 'env_file': 'two'} + mock_path.isfile.return_value = False + + docker_runner = t_runner.OnapVtpRunner(self.testcase) + + mock_path.join.assert_has_calls([call('one', 'two')]) + mock_path.isfile.assert_called_once() + docker_runner.logger.error.assert_called_once_with( + 'File env_file does not exist.') + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.dt_cfg') + def test_init_onapvtprunner(self, mock_config, mock_path, mock_utils): + t_runner.OnapVtpRunner.create_log() + mock_path.join.side_effect = ['env_file'] + mock_config.dovetail_config = {'config_dir': 'one', 'env_file': 'two'} + mock_path.isfile.return_value = True + + t_runner.OnapVtpRunner(self.testcase) + + mock_path.join.assert_has_calls([call('one', 'two')]) + mock_path.isfile.assert_called_once() + mock_utils.source_env.assert_called_once_with('env_file') + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.dt_cfg') + def test_init_onapvvprunner_no_env_file(self, mock_config, mock_path, + mock_utils): + t_runner.OnapVvpRunner.create_log() + mock_path.join.side_effect = ['env_file'] + mock_config.dovetail_config = {'config_dir': 'one', 'env_file': 'two'} + mock_path.isfile.return_value = False + + docker_runner = t_runner.OnapVvpRunner(self.testcase) + + mock_path.join.assert_has_calls([call('one', 'two')]) + mock_path.isfile.assert_called_once() + docker_runner.logger.error.assert_called_once_with( + 'File env_file does not exist.') + + @patch('dovetail.test_runner.dt_utils') + @patch('dovetail.test_runner.os.path') + @patch('dovetail.test_runner.dt_cfg') + def test_init_onapvvprunner(self, mock_config, mock_path, mock_utils): + t_runner.OnapVvpRunner.create_log() + mock_path.join.side_effect = ['env_file'] + mock_config.dovetail_config = {'config_dir': 'one', 'env_file': 'two'} + mock_path.isfile.return_value = True + + t_runner.OnapVvpRunner(self.testcase) + + mock_path.join.assert_has_calls([call('one', 'two')]) + mock_path.isfile.assert_called_once() + mock_utils.source_env.assert_called_once_with('env_file') diff --git a/dovetail/tests/unit/test_testcase.py b/dovetail/tests/unit/test_testcase.py new file mode 100644 index 00000000..81a8de39 --- /dev/null +++ b/dovetail/tests/unit/test_testcase.py @@ -0,0 +1,658 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import os +import unittest +import yaml +from mock import patch, call, Mock + +import dovetail.testcase as tcase + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class TestcaseTesting(unittest.TestCase): + + def setUp(self): + test_path = os.path.dirname(os.path.realpath(__file__)) + with open(os.path.join(test_path, 'test_testcase.yaml')) as f: + self.testcase_yaml = yaml.safe_load(f) + + def tearDown(self): + pass + + def teardown_method(self, method): + tcase.Testcase.logger = None + tcase.Testcase.validate_testcase_list = {} + tcase.Testcase.testcase_list = {} + tcase.Testsuite.testsuite_list = {} + + @patch('dovetail.testcase.dt_logger') + def test_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + tcase.Testcase.create_log() + + self.assertEqual(getlogger_obj, tcase.Testcase.logger) + + @patch('dovetail.testcase.Parser') + def test_parse_cmd_no_lines(self, mock_parser): + testcase = tcase.YardstickTestcase(self.testcase_yaml) + cmds_list = ['cmd'] + mock_parser.parse_cmd.return_value = None + + result = testcase.parse_cmd(cmds_list) + + mock_parser.parse_cmd.assert_called_once_with( + 'cmd', testcase) + self.assertEqual(False, result) + + @patch('dovetail.testcase.Parser') + def test_parse_cmd(self, mock_parser): + testcase = tcase.BottlenecksTestcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + cmds_list = ['cmd'] + mock_parser.parse_cmd.return_value = 'cmd_lines' + + result = testcase.parse_cmd(cmds_list) + + mock_parser.parse_cmd.assert_called_once_with( + 'cmd', testcase) + logger_obj.debug.assert_called_once_with("cmds: ['cmd_lines']") + self.assertEqual(['cmd_lines'], testcase.cmds) + self.assertEqual(True, result) + + @patch('dovetail.testcase.dt_cfg') + def test_prepare_cmd_no_cmds(self, mock_config): + testcase = tcase.ShellTestcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + mock_config.dovetail_config = {} + + result = testcase.prepare_cmd('type') + + logger_obj.error.assert_called_once_with( + 'Test case {} has no cmds.'.format(testcase.name())) + self.assertEqual(False, result) + + @patch('dovetail.testcase.dt_cfg') + @patch.object(tcase.Testcase, 'parse_cmd') + def test_prepare_cmd_testcase_cmd(self, mock_parse, mock_config): + testcase = tcase.ShellTestcase(self.testcase_yaml) + testcase.testcase['validate']['cmds'] = ['cmd'] + mock_config.dovetail_config = {} + mock_parse.return_value = True + + result = testcase.prepare_cmd('type') + + mock_parse.assert_called_once_with(['cmd']) + self.assertEqual(True, result) + + @patch('dovetail.testcase.dt_cfg') + @patch.object(tcase.Testcase, 'parse_cmd') + def test_prepare_cmd_config_cmd(self, mock_parse, mock_config): + testcase = tcase.TestcaseFactory.create('yardstick', + self.testcase_yaml) + mock_config.dovetail_config = {'type': {'cmds': ['cmd']}} + mock_parse.return_value = True + + result = testcase.prepare_cmd('type') + + mock_parse.assert_called_once_with(['cmd']) + self.assertEqual(True, result) + + def test_str(self): + testcase = tcase.OnapVtpTestcase(self.testcase_yaml) + + result = testcase.__str__() + + self.assertEqual(testcase.testcase, result) + + def test_objective(self): + testcase = tcase.OnapVvpTestcase(self.testcase_yaml) + testcase.testcase['objective'] = 'objective' + + result = testcase.objective() + + self.assertEqual('objective', result) + + @patch('dovetail.testcase.dt_utils') + def test_sub_testcase(self, mock_utils): + testcase = tcase.Testcase(self.testcase_yaml) + mock_utils.get_value_from_dict.return_value = 'value' + + result = testcase.sub_testcase() + + mock_utils.get_value_from_dict.assert_called_once_with( + 'report.sub_testcase_list', testcase.testcase) + self.assertEqual('value', result) + + def test_sub_testcase_passed(self): + testcase = tcase.Testcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + + result = testcase.sub_testcase_passed('name', 'passed') + + self.assertEqual('passed', result) + + def test_validate_type(self): + testcase = tcase.Testcase(self.testcase_yaml) + + result = testcase.validate_type() + + self.assertEqual('functest', result) + + def test_validate_testcase(self): + testcase = tcase.Testcase(self.testcase_yaml) + + result = testcase.validate_testcase() + + self.assertEqual('tempest_smoke_serial', result) + + def test_portal_key_file(self): + testcase = tcase.Testcase(self.testcase_yaml) + + result = testcase.portal_key_file() + + self.assertEqual('tempest_logs/tempest_smoke_serial.html', result) + + def test_vnf_type(self): + testcase = tcase.OnapVtpTestcase(self.testcase_yaml) + + result = testcase.vnf_type() + + self.assertEqual('tosca', result) + + def test_passed(self): + testcase = tcase.Testcase(self.testcase_yaml) + + result = testcase.passed('passed') + + self.assertEqual('passed', result) + + def test_set_get_results(self): + testcase = tcase.Testcase(self.testcase_yaml) + + testcase.set_results('results') + + self.assertEqual('results', testcase.get_results()) + + def test_pre_condition_exists(self): + testcase = tcase.Testcase(self.testcase_yaml) + testcase.testcase['validate']['pre_condition'] = 'pre_condition' + + result = testcase.pre_condition() + + self.assertEqual('pre_condition', result) + + @patch.object(tcase.Testcase, 'pre_condition_cls') + def test_pre_condition_not_exists(self, mock_pre_condition): + testcase = tcase.Testcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + mock_pre_condition.return_value = False + + result = testcase.pre_condition() + + mock_pre_condition.assert_called_once_with('functest') + logger_obj.debug.assert_called_once_with( + 'Test case: {} pre_condition is empty.'.format(testcase.name())) + self.assertEqual(False, result) + + def test_pre_copy_path(self): + testcase = tcase.Testcase(self.testcase_yaml) + testcase.testcase['validate']['pre_copy'] = {'key': 'value'} + + result = testcase.pre_copy_path('key') + + self.assertEqual('value', result) + + def test_pre_copy_path_error(self): + testcase = tcase.Testcase(self.testcase_yaml) + + result = testcase.pre_copy_path('key') + + self.assertEqual(None, result) + + def test_post_condition_exists(self): + testcase = tcase.Testcase(self.testcase_yaml) + testcase.testcase['validate']['post_condition'] = 'post_condition' + + result = testcase.post_condition() + + self.assertEqual('post_condition', result) + + @patch.object(tcase.Testcase, 'post_condition_cls') + def test_post_condition_not_exists(self, mock_post_condition): + testcase = tcase.Testcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + mock_post_condition.return_value = False + + result = testcase.post_condition() + + mock_post_condition.assert_called_once_with('functest') + logger_obj.debug.assert_called_once_with( + 'Test case: {} post_condition is empty.'.format(testcase.name())) + self.assertEqual(False, result) + + @patch('builtins.open') + @patch('dovetail.testcase.os.path') + @patch('dovetail.testcase.dt_cfg') + @patch.object(tcase.Testcase, 'sub_testcase') + def test_mk_src_file(self, mock_sub_testcase, mock_config, + mock_path, mock_open): + testcase = tcase.Testcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + mock_config.dovetail_config = {'result_dir': 'value'} + sub_test = 'sub_test' + file_path = 'file_path' + mock_path.join.return_value = file_path + mock_sub_testcase.return_value = [sub_test] + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + + result = testcase.mk_src_file() + + mock_path.join.assert_called_once_with('value', 'tempest_custom.txt') + mock_open.assert_called_once_with(file_path, 'w+') + file_obj.write.assert_called_once_with(sub_test + '\n') + logger_obj.debug.assert_called_once_with( + 'Save test cases to {}'.format(file_path)) + self.assertEqual(file_path, result) + + @patch('builtins.open') + @patch('dovetail.testcase.os.path') + @patch('dovetail.testcase.dt_cfg') + @patch.object(tcase.Testcase, 'sub_testcase') + def test_mk_src_file_exception(self, mock_sub_testcase, + mock_config, mock_path, mock_open): + testcase = tcase.Testcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + mock_config.dovetail_config = {'result_dir': 'value'} + sub_test = 'sub_test' + file_path = 'file_path' + mock_path.join.return_value = file_path + mock_sub_testcase.return_value = [sub_test] + mock_open.return_value.__enter__.side_effect = Exception() + + result = testcase.mk_src_file() + + mock_path.join.assert_called_once_with('value', 'tempest_custom.txt') + mock_open.assert_called_once_with(file_path, 'w+') + logger_obj.exception('Failed to save: {}'.format(file_path)) + self.assertEqual(None, result) + + @patch('dovetail.testcase.TestRunnerFactory') + def test_run(self, mock_factory): + testcase = tcase.Testcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + runner_obj = Mock() + mock_factory.create.return_value = runner_obj + error_msg = 'An error happened!' + runner_obj.archive_logs.side_effect = AttributeError(error_msg) + + testcase.run() + + runner_obj.run.assert_called_once_with() + runner_obj.archive_logs.assert_called_once_with() + logger_obj.exception.assert_called_once_with( + 'Test case: {} Exception: {}'.format(testcase.name, error_msg)) + + @patch('dovetail.testcase.dt_cfg') + def test_pre_condition_cls(self, mock_config): + mock_config.dovetail_config = {'type': {'pre_condition': 'value'}} + + result = tcase.Testcase.pre_condition_cls('type') + self.assertEqual('value', result) + + @patch('dovetail.testcase.dt_cfg') + def test_pre_condition_cls_key_error(self, mock_config): + mock_config.dovetail_config = {} + + result = tcase.Testcase.pre_condition_cls('type') + self.assertEqual(None, result) + + @patch('dovetail.testcase.dt_cfg') + def test_post_condition_cls(self, mock_config): + mock_config.dovetail_config = {'type': {'post_condition': 'value'}} + + result = tcase.Testcase.post_condition_cls('type') + self.assertEqual('value', result) + + @patch('dovetail.testcase.dt_cfg') + def test_post_condition_cls_key_error(self, mock_config): + mock_config.dovetail_config = {} + + result = tcase.Testcase.post_condition_cls('type') + self.assertEqual(None, result) + + def test_increase_retry(self): + testcase = tcase.Testcase(self.testcase_yaml) + tcase.Testcase.validate_testcase_list[ + 'tempest_smoke_serial'] = {'retry': 0} + + for _ in range(0, 42): + result = testcase.increase_retry() + self.assertEqual(42, result) + + @patch('builtins.open') + @patch('dovetail.testcase.yaml') + @patch('dovetail.testcase.os') + @patch('dovetail.testcase.TestcaseFactory') + @patch('dovetail.testcase.constants') + def test_load(self, mock_constants, mock_factory, mock_os, mock_yaml, + mock_open): + testcase = tcase.Testcase(self.testcase_yaml) + mock_constants.TESTCASE_PATH = 'abs_path' + mock_os.walk.return_value = [('root', ['dir'], ['file'])] + mock_os.path.join.return_value = 'testcase_path' + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + yaml_dict = {'key': {'validate': {'type': 'value'}}} + mock_yaml.safe_load.return_value = yaml_dict + runner_obj = Mock() + mock_factory.create.return_value = runner_obj + + testcase.load() + + mock_os.walk.assert_called_once_with('abs_path') + mock_os.path.join.assert_called_with('root', 'file') + mock_open.assert_called_once_with('testcase_path') + mock_yaml.safe_load.assert_called_once_with(file_obj) + mock_factory.create.assert_called_once_with('value', yaml_dict) + self.assertEqual(runner_obj, tcase.Testcase.get('key')) + + @patch('builtins.open') + @patch('dovetail.testcase.yaml') + @patch('dovetail.testcase.os') + @patch('dovetail.testcase.TestcaseFactory') + @patch('dovetail.testcase.constants') + def test_load_no_testcase(self, mock_constants, mock_factory, mock_os, + mock_yaml, mock_open): + logger_obj = Mock() + tcase.Testcase.logger = logger_obj + mock_constants.TESTCASE_PATH = 'abs_path' + mock_os.walk.return_value = [('root', ['dir'], ['file'])] + mock_os.path.join.return_value = 'testcase_path' + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + yaml_dict = {'key': {'validate': {'type': 'value'}}} + mock_yaml.safe_load.return_value = yaml_dict + mock_factory.create.return_value = None + + tcase.Testcase.load() + + mock_os.walk.assert_called_once_with('abs_path') + mock_os.path.join.assert_called_with('root', 'file') + mock_open.assert_called_once_with('testcase_path') + mock_yaml.safe_load.assert_called_once_with(file_obj) + mock_factory.create.assert_called_once_with('value', yaml_dict) + logger_obj.error.assert_called_once_with( + 'Failed to create test case: file') + + def test_get_none(self): + self.assertEqual(None, tcase.Testcase.get('unknown')) + + def test_check_testarea_none(self): + self.assertEqual((True, ['full']), + tcase.Testcase.check_testarea(None)) + + @patch('dovetail.testcase.dt_cfg') + def test_check_testarea_full(self, mock_config): + self.assertEqual((True, ['full']), + tcase.Testcase.check_testarea(['full'])) + + @patch('dovetail.testcase.dt_cfg') + def test_check_testarea(self, mock_config): + self.assertEqual((True, ['area']), + tcase.Testcase.check_testarea(['area'])) + + def test_check_testcase_area(self): + self.assertEqual(False, + tcase.Testcase.check_testcase_area(None, None)) + + def test_check_testcase_area_full_or_in_testcase(self): + self.assertEqual(True, + tcase.Testcase.check_testcase_area(['full'], 'full')) + + def test_check_testcase_area_not_in_testcase_or_full(self): + self.assertEqual(False, + tcase.Testcase.check_testcase_area(['full'], 'half')) + + @patch('dovetail.testcase.dt_utils') + def test_get_testcases_for_testsuite_no_testcases(self, mock_utils): + mock_utils.get_value_from_dict.return_value = None + + result = tcase.Testcase.get_testcases_for_testsuite('suite', 'area') + + mock_utils.get_value_from_dict.assert_has_calls([ + call('testcases_list', 'suite'), + call('mandatory', None), + call('optional', None)]) + self.assertEqual([], result) + + @patch('dovetail.testcase.dt_cfg') + @patch('dovetail.testcase.dt_utils') + def test_get_testcases_for_testsuite_no_selected_testcases(self, + mock_utils, + mock_config): + logger_obj = Mock() + tcase.Testcase.logger = logger_obj + testcases_obj = Mock() + mock_utils.get_value_from_dict.side_effect = [ + testcases_obj, None, None] + mock_config.dovetail_config = { + 'mandatory': True, + 'optional': True + } + testsuite = {'name': 'test_name'} + + result = tcase.Testcase.get_testcases_for_testsuite(testsuite, 'area') + + mock_utils.get_value_from_dict.assert_has_calls([ + call('testcases_list', testsuite), + call('mandatory', testcases_obj), + call('optional', testcases_obj)]) + logger_obj.error.assert_has_calls([ + call('There is no mandatory test case in test suite {}' + .format(testsuite['name'])), + call('There is no optional test case in test suite {}' + .format(testsuite['name']))]) + self.assertEqual(None, result) + + @patch('dovetail.testcase.dt_cfg') + @patch('dovetail.testcase.dt_utils') + @patch.object(tcase.Testcase, 'check_testcase_area') + def test_get_testcases_for_testsuite(self, mock_check, mock_utils, + mock_config): + logger_obj = Mock() + tcase.Testcase.logger = logger_obj + testcases_obj = Mock() + mock_utils.get_value_from_dict.side_effect = [ + testcases_obj, ['mandatory'], ['optional']] + mock_config.dovetail_config = { + 'mandatory': True, + 'optional': True + } + mock_check.return_value = True + testsuite = {'name': 'test_name'} + testarea = ['area'] + + mandatory_obj = Mock() + tcase.Testcase.testcase_list['mandatory'] = mandatory_obj + optional_obj = Mock() + tcase.Testcase.testcase_list['optional'] = optional_obj + result = tcase.Testcase.get_testcases_for_testsuite( + testsuite, testarea) + + mock_utils.get_value_from_dict.assert_has_calls([ + call('testcases_list', testsuite), + call('mandatory', testcases_obj), + call('optional', testcases_obj)]) + mock_check.assert_has_calls([ + call('mandatory', 'area'), + call('optional', 'area')]) + self.assertEqual(['mandatory', 'optional'], result) + self.assertEqual( + True, tcase.Testcase.testcase_list['mandatory'].is_mandatory) + self.assertEqual( + False, tcase.Testcase.testcase_list['optional'].is_mandatory) + + @patch('dovetail.testcase.dt_cfg') + @patch('dovetail.testcase.dt_utils') + @patch.object(tcase.Testcase, 'check_testcase_area') + def test_get_testcases_for_testsuite_no_conf(self, mock_check, mock_utils, + mock_config): + logger_obj = Mock() + tcase.Testcase.logger = logger_obj + testcases_obj = Mock() + mock_utils.get_value_from_dict.side_effect = [ + testcases_obj, ['mandatory'], ['optional']] + mock_config.dovetail_config = { + 'mandatory': False, + 'optional': False + } + mock_check.return_value = True + testsuite = {'name': 'test_name'} + testarea = ['area'] + + mandatory_obj = Mock() + tcase.Testcase.testcase_list['mandatory'] = mandatory_obj + optional_obj = Mock() + tcase.Testcase.testcase_list['optional'] = optional_obj + result = tcase.Testcase.get_testcases_for_testsuite(testsuite, + testarea) + + mock_utils.get_value_from_dict.assert_has_calls([ + call('testcases_list', testsuite), + call('mandatory', testcases_obj), + call('optional', testcases_obj)]) + mock_check.assert_has_calls([ + call('mandatory', 'area'), + call('optional', 'area')]) + self.assertEqual(['mandatory', 'optional'], result) + self.assertEqual(True, + tcase.Testcase.testcase_list['mandatory'] + .is_mandatory) + self.assertEqual(False, + tcase.Testcase.testcase_list['optional'].is_mandatory) + + @patch.object(tcase.Testcase, 'prepare_cmd') + def test_functest_case_prepare_cmd_false(self, mock_prepare): + testcase = tcase.FunctestTestcase(self.testcase_yaml) + mock_prepare.return_value = False + + result = testcase.prepare_cmd('type') + + mock_prepare.assert_called_once_with('type') + self.assertEqual(False, result) + + @patch('dovetail.testcase.os.path') + @patch('dovetail.testcase.dt_cfg') + @patch.object(tcase.Testcase, 'prepare_cmd') + def test_functest_case_prepare_cmd(self, mock_prepare, mock_config, + mock_path): + testcase = tcase.FunctestTestcase(self.testcase_yaml) + logger_obj = Mock() + testcase.logger = logger_obj + mock_prepare.return_value = True + mock_config.dovetail_config = { + 'no_api_validation': True, + 'functest': {'patches_dir': 'value'}} + mock_path.join.return_value = 'patch_cmd' + + result = testcase.prepare_cmd('type') + + mock_path.join.assert_called_once_with( + 'value', 'functest', 'disable-api-validation', 'apply.sh') + logger_obj.debug.assert_called_once_with( + 'Updated list of commands for test run with ' + 'disabled API response validation: {}' + .format(testcase.cmds)) + self.assertEqual(['patch_cmd'], testcase.cmds) + self.assertEqual(True, result) + + def test_testfactory_error(self): + self.assertEqual(None, + tcase.TestcaseFactory.create('unknown', + self.testcase_yaml)) + + def test_testfactory_k8s(self): + k8s_testcase = tcase.TestcaseFactory.create('functest-k8s', + self.testcase_yaml) + self.assertEqual('functest-k8s', k8s_testcase.type) + + @patch('dovetail.testcase.dt_logger') + def test_testsuite_create_log(self, mock_logger): + getlogger_obj = Mock() + logger_obj = Mock() + logger_obj.getLogger.return_value = getlogger_obj + mock_logger.Logger.return_value = logger_obj + + tcase.Testsuite.create_log() + + self.assertEqual(getlogger_obj, tcase.Testsuite.logger) + + def test_testsuite_get_test(self): + suite = tcase.Testsuite('suite') + suite.testcase_list['testcase'] = 'value' + + result = suite.get_test('testcase') + + self.assertEqual('value', result) + + def test_testsuite_get_test_not_exists(self): + suite = tcase.Testsuite('suite') + + result = suite.get_test('testcase') + + self.assertEqual(None, result) + + @patch('builtins.open') + @patch('dovetail.testcase.yaml') + @patch('dovetail.testcase.os') + @patch('dovetail.testcase.constants') + def test_testsuite_load(self, mock_constants, mock_os, mock_yaml, + mock_open): + mock_constants.COMPLIANCE_PATH = 'abs_path' + mock_os.walk.return_value = [('root', ['dir'], ['file'])] + mock_os.path.join.return_value = 'file_path' + mock_yaml.safe_load.return_value = {'testsuite': 'value'} + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + + tcase.Testsuite.load() + + mock_os.walk.assert_called_once_with('abs_path') + mock_os.path.join.assert_called_with('root', 'file') + mock_open.assert_called_once_with('file_path') + mock_yaml.safe_load.assert_called_once_with(file_obj) + self.assertEqual({'testsuite': 'value'}, + tcase.Testsuite.testsuite_list) + + def test_testsuite_get_none(self): + self.assertEqual(None, tcase.Testsuite.get('unknown')) + + def test_testsuite_get(self): + tcase.Testsuite.testsuite_list.update({'key': 'value'}) + self.assertEqual('value', tcase.Testsuite.get('key')) + + def test_testsuite_get_all(self): + tcase.Testsuite.testsuite_list.update({'key': 'value'}) + self.assertEqual({'key': 'value'}, tcase.Testsuite.get_all()) diff --git a/dovetail/tests/unit/test_testcase.yaml b/dovetail/tests/unit/test_testcase.yaml index cb947cd9..b4cd3b1d 100644 --- a/dovetail/tests/unit/test_testcase.yaml +++ b/dovetail/tests/unit/test_testcase.yaml @@ -1,11 +1,22 @@ +############################################################################## +# Copyright (c) 2019 opnfv. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + --- dovetail.ipv6.tc001: name: dovetail.ipv6.tc001 objective: VIM ipv6 operations, to create/delete network, port and subnet in bulk operation + vnf_type: tosca validate: type: functest testcase: tempest_smoke_serial report: + portal_key_file: tempest_logs/tempest_smoke_serial.html sub_testcase_list: - tempest.api.network.test_networks.BulkNetworkOpsIpV6Test.test_bulk_create_delete_network - tempest.api.network.test_networks.BulkNetworkOpsIpV7Test.test_bulk_create_delete_port diff --git a/dovetail/tests/unit/utils/__init__.py b/dovetail/tests/unit/utils/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/dovetail/tests/unit/utils/__init__.py diff --git a/dovetail/tests/unit/utils/test_dovetail_config.py b/dovetail/tests/unit/utils/test_dovetail_config.py new file mode 100644 index 00000000..8e835f49 --- /dev/null +++ b/dovetail/tests/unit/utils/test_dovetail_config.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import unittest +from mock import patch + +from dovetail.utils.dovetail_config import DovetailConfig + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class DovetailConfigTesting(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch.object(DovetailConfig, 'update_non_envs') + def test_update_config(self, mock_non_envs): + config_dict = {'key': {'path': ['aa / bb/ cc'], 'value': 'val'}} + dovetail_cfg = DovetailConfig() + + dovetail_cfg.update_config(config_dict) + + mock_non_envs.assert_called_once_with(['aa', 'bb', 'cc'], 'val') + + def test_set_leaf_dict(self): + dict_to_test = {} + dovetail_cfg = DovetailConfig() + + dovetail_cfg.set_leaf_dict(dict_to_test, ['aa', 'bb', 'cc'], 'val') + + self.assertEqual({'aa': {'bb': {'cc': 'val'}}}, dict_to_test) + + @patch.object(DovetailConfig, 'set_leaf_dict') + @patch.object(DovetailConfig, 'dovetail_config') + def test_update_non_envs(self, mock_cfg, mock_set_leaf): + path = ['aa', 'bb', 'cc'] + value = 'val' + dovetail_cfg = DovetailConfig() + + dovetail_cfg.update_non_envs(path, value) + + mock_set_leaf.assert_called_once_with(mock_cfg, path, value) diff --git a/dovetail/tests/unit/utils/test_dovetail_logger.py b/dovetail/tests/unit/utils/test_dovetail_logger.py new file mode 100644 index 00000000..a70c0503 --- /dev/null +++ b/dovetail/tests/unit/utils/test_dovetail_logger.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import unittest +from mock import patch, call, Mock + +from dovetail.utils import dovetail_utils +from dovetail.utils.dovetail_logger import Logger + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class DovetailLoggerTesting(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('sys.stdout') + @patch('dovetail.utils.dovetail_logger.os') + @patch('dovetail.utils.dovetail_logger.logging') + def test_logger_info(self, mock_logging, mock_os, mock_stdout): + file_path = 'file_path' + level_const_info = 'INFO' + level_const_debug = 'DEBUG' + logger = Mock() + mock_os.getenv.return_value = 'False' + mock_logging.INFO = level_const_info + mock_logging.DEBUG = level_const_debug + mock_logging.getLogger.return_value = logger + dovetail_utils.dt_cfg.dovetail_config = {'result_dir': file_path} + mock_os.path.exists.return_value = False + stream_handler_obj = Mock() + formatter_obj = Mock() + file_handler_obj = Mock() + mock_logging.StreamHandler.return_value = stream_handler_obj + mock_logging.Formatter.return_value = formatter_obj + mock_logging.FileHandler.return_value = file_handler_obj + + logger_name = 'name' + dovetail_logger = Logger(logger_name) + mock_logging.getLogger.assert_called_once_with(logger_name) + self.assertEqual(dovetail_logger.logger.propagate, 0) + logger.setLevel.assert_called_once_with(level_const_debug) + mock_os.path.exists.assert_called_once_with(file_path) + # mock_os.makedirs.assert_called_once_with(file_path) + mock_logging.Formatter.assert_called_once_with( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') + stream_handler_obj.setFormatter.assert_called_once_with(formatter_obj) + stream_handler_obj.setLevel.assert_called_once_with(level_const_info) + file_handler_obj.setLevel.assert_called_once_with(level_const_info) + logger.addHandler.assert_has_calls([ + call(stream_handler_obj), call(file_handler_obj)]) + self.assertEqual(dovetail_logger.getLogger(), logger) + + @patch('sys.stdout') + @patch('dovetail.utils.dovetail_logger.os') + @patch('dovetail.utils.dovetail_logger.logging') + def test_logger_debug(self, mock_logging, mock_os, mock_stdout): + file_path = 'file_path' + level_const_debug = 'DEBUG' + logger = Mock() + mock_os.getenv.return_value = 'True' + mock_logging.DEBUG = level_const_debug + mock_logging.getLogger.return_value = logger + dovetail_utils.dt_cfg.dovetail_config = {'result_dir': file_path} + mock_os.path.exists.return_value = False + stream_handler_obj = Mock() + formatter_obj = Mock() + file_handler_obj = Mock() + mock_logging.StreamHandler.return_value = stream_handler_obj + mock_logging.Formatter.return_value = formatter_obj + mock_logging.FileHandler.return_value = file_handler_obj + + logger_name = 'name' + dovetail_logger = Logger(logger_name) + mock_logging.getLogger.assert_called_once_with(logger_name) + self.assertEqual(dovetail_logger.logger.propagate, 0) + logger.setLevel.assert_called_once_with(level_const_debug) + mock_os.path.exists.assert_called_once_with(file_path) + # mock_os.makedirs.assert_called_once_with(file_path) + mock_logging.Formatter.assert_called_once_with( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') + stream_handler_obj.setFormatter.assert_called_once_with(formatter_obj) + stream_handler_obj.setLevel.assert_called_once_with(level_const_debug) + file_handler_obj.setLevel.assert_called_once_with(level_const_debug) + logger.addHandler.assert_has_calls([ + call(stream_handler_obj), call(file_handler_obj)]) + self.assertEqual(dovetail_logger.getLogger(), logger) diff --git a/dovetail/tests/unit/utils/test_dovetail_utils.py b/dovetail/tests/unit/utils/test_dovetail_utils.py new file mode 100644 index 00000000..7d1fddc1 --- /dev/null +++ b/dovetail/tests/unit/utils/test_dovetail_utils.py @@ -0,0 +1,1402 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import io +import unittest +from mock import patch, call, Mock + +from dovetail import constants +from dovetail.utils import dovetail_utils + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class DovetailUtilsTesting(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + @patch('sys.stdout') + @patch('builtins.print') + def test_exec_log_no_verbose(self, mock_print, mock_stdout): + dovetail_utils.exec_log(verbose=False, logger=None, msg='', + level='info', flush=True) + + mock_print.assert_not_called() + mock_stdout.flush.assert_not_called() + + @patch('sys.stdout') + @patch('builtins.print') + def test_exec_log_no_logger_flush(self, mock_print, mock_stdout): + message = 'message' + + dovetail_utils.exec_log(verbose=True, logger=False, msg=message, + level='info', flush=True) + + mock_print.assert_has_calls([call(message)]) + mock_stdout.flush.assert_called_once() + + @patch('sys.stdout') + @patch('builtins.print') + def test_exec_log_no_logger_no_flush(self, mock_print, mock_stdout): + message = 'message' + + dovetail_utils.exec_log(verbose=True, logger=False, msg=message, + level='info', flush=False) + + mock_print.assert_has_calls([call(message)]) + mock_stdout.flush.assert_not_called() + + def test_exec_log_logger_info(self): + message = 'message' + logger = Mock() + + dovetail_utils.exec_log(verbose=True, logger=logger, msg=message, + level='info', flush=True) + + logger.info.assert_called_once_with(message) + + def test_exec_log_logger_error(self): + message = 'message' + logger = Mock() + + dovetail_utils.exec_log(verbose=True, logger=logger, msg=message, + level='error', flush=True) + + logger.error.assert_called_once_with(message) + + def test_exec_log_logger_debug(self): + message = 'message' + logger = Mock() + + dovetail_utils.exec_log(verbose=True, logger=logger, msg=message, + level='debug', flush=True) + + logger.debug.assert_called_once_with(message) + + def test_get_value_from_dict(self): + key_path = 'a.b' + input_dict = {'a': {'b': 'c'}} + + expected = 'c' + result = dovetail_utils.get_value_from_dict(key_path, input_dict) + + self.assertEqual(expected, result) + + def test_get_value_from_dict_key_path_not_str(self): + key_path = 1 + input_dict = {'a': {'b': 'c'}} + + expected = None + result = dovetail_utils.get_value_from_dict(key_path, input_dict) + + self.assertEqual(expected, result) + + def test_get_value_from_dict_input_dict_not_dict(self): + key_path = 'a.b' + input_dict = 'dictionary' + + expected = None + result = dovetail_utils.get_value_from_dict(key_path, input_dict) + + self.assertEqual(expected, result) + + def test_get_value_from_dict_no_value_for_key_in_key_path(self): + key_path = 'a.b' + input_dict = {'a': {'c': 'b'}} + + expected = None + result = dovetail_utils.get_value_from_dict(key_path, input_dict) + + self.assertEqual(expected, result) + + @patch('os.path', autospec=True) + def test_read_plain_file_not_exist(self, mock_path): + file_path = 'unknown_file' + logger = Mock() + mock_path.isfile.return_value = False + + expected = None + result = dovetail_utils.read_plain_file(file_path, logger) + + mock_path.isfile.assert_called_once_with(file_path) + logger.error.assert_called_once_with("File {} doesn't exist." + .format(file_path)) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_read_plain_file(self, mock_path, mock_open): + file_path = 'known_file' + file_data = u'file data' + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.return_value = io.StringIO(file_data) + + expected = file_data + result = dovetail_utils.read_plain_file(file_path) + + mock_path.isfile.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_read_plain_file_raised_exception(self, mock_path, mock_open): + logger = Mock() + file_path = 'known_file' + errorMSG = 'Exception was raised' + exception = Exception(errorMSG) + mock_open.side_effect = exception + + expected = None + result = dovetail_utils.read_plain_file(file_path, logger) + + mock_open.assert_called_once_with(file_path, 'r') + logger.exception.assert_called_once_with( + 'Failed to read file {}, exception: {}' + .format(file_path, exception)) + self.assertEqual(expected, result) + + @patch('os.path', autospec=True) + def test_read_yaml_file_not_exist(self, mock_path): + file_path = 'unknown_file' + logger = Mock() + mock_path.isfile.return_value = False + + expected = None + result = dovetail_utils.read_yaml_file(file_path, logger) + + mock_path.isfile.assert_called_once_with(file_path) + logger.error.assert_called_once_with("File {} doesn't exist." + .format(file_path)) + self.assertEqual(expected, result) + + @patch('yaml.safe_load') + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_read_yaml_file(self, mock_path, mock_open, mock_load): + file_obj = Mock() + file_path = 'known_file' + file_data = 'file data' + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = file_data + + expected = file_data + result = dovetail_utils.read_yaml_file(file_path) + + mock_path.isfile.assert_called_once_with(file_path) + mock_open.assert_called_once_with(file_path, 'r') + mock_load.assert_called_once_with(file_obj) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_read_yaml_file_raised_exception(self, mock_path, mock_open): + logger = Mock() + file_path = 'known_file' + errorMSG = 'Exception was raised' + exception = Exception(errorMSG) + mock_open.side_effect = exception + + expected = None + result = dovetail_utils.read_yaml_file(file_path, logger) + + mock_open.assert_called_once_with(file_path, 'r') + logger.exception.assert_called_once_with( + 'Failed to read file {}, exception: {}' + .format(file_path, exception)) + self.assertEqual(expected, result) + + @patch('os.path', autospec=True) + def test_get_hosts_info_not_exist(self, mock_path): + file_path = 'file_path' + file_complete_name = '/'.join((file_path, 'hosts.yaml')) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_path.isfile.return_value = False + logger = Mock() + + expected = {} + result = dovetail_utils.get_hosts_info(logger) + + mock_path.join.assert_called_once_with(file_path, 'hosts.yaml') + mock_path.isfile.assert_called_once_with(file_complete_name) + self.assertEqual(expected, result) + + @patch('yaml.safe_load') + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_get_hosts_info_not_yaml(self, mock_path, mock_open, mock_load): + file_path = 'file_path' + file_complete_name = '/'.join((file_path, 'hosts.yaml')) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_path.isfile.return_value = True + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = None + logger = Mock() + + expected = {} + result = dovetail_utils.get_hosts_info(logger) + + mock_path.join.assert_called_once_with(file_path, 'hosts.yaml') + mock_path.isfile.assert_called_once_with(file_complete_name) + mock_open.assert_called_once_with(file_complete_name) + mock_load.assert_called_once_with(file_obj) + logger.debug.assert_called_once_with( + 'File {} is empty.'.format(file_complete_name)) + self.assertEqual(expected, result) + + @patch('yaml.safe_load') + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_get_hosts_info_no_hosts_info(self, mock_path, mock_open, + mock_load): + file_path = 'file_path' + file_complete_name = '/'.join((file_path, 'hosts.yaml')) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_path.isfile.return_value = True + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = {'a': 'b'} + logger = Mock() + + expected = {} + result = dovetail_utils.get_hosts_info(logger) + + mock_path.join.assert_called_once_with(file_path, 'hosts.yaml') + mock_path.isfile.assert_called_once_with(file_complete_name) + mock_open.assert_called_once_with(file_complete_name) + mock_load.assert_called_once_with(file_obj) + logger.error.assert_called_once_with( + 'There is no key hosts_info in file {}' + .format(file_complete_name)) + self.assertEqual(expected, result) + + @patch('yaml.safe_load') + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_get_hosts_info_no_hostname(self, mock_path, mock_open, mock_load): + file_path = 'file_path' + file_complete_name = '/'.join((file_path, 'hosts.yaml')) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_path.isfile.return_value = True + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = {'hosts_info': {'127.0.0.1': []}} + + expected = {} + result = dovetail_utils.get_hosts_info() + + mock_path.join.assert_called_once_with(file_path, 'hosts.yaml') + mock_path.isfile.assert_called_once_with(file_complete_name) + mock_open.assert_called_once_with(file_complete_name) + mock_load.assert_called_once_with(file_obj) + self.assertEqual(expected, result) + + @patch('dovetail.utils.dovetail_utils.add_hosts_info') + @patch('yaml.safe_load') + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_get_hosts_info_no_valid_hostname(self, mock_path, mock_open, + mock_load, mock_fn): + file_path = 'file_path' + file_complete_name = '/'.join((file_path, 'hosts.yaml')) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_path.isfile.return_value = True + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + hosts_info = {'127.0.0.1': [None]} + mock_load.return_value = {'hosts_info': hosts_info} + + expected = {} + result = dovetail_utils.get_hosts_info() + + mock_path.join.assert_called_once_with(file_path, 'hosts.yaml') + mock_path.isfile.assert_called_once_with(file_complete_name) + mock_open.assert_called_once_with(file_complete_name) + mock_load.assert_called_once_with(file_obj) + mock_fn.assert_called_once_with(list(hosts_info.keys())[0], + list(hosts_info.values())[0]) + self.assertEqual(expected, result) + + @patch('dovetail.utils.dovetail_utils.add_hosts_info') + @patch('yaml.safe_load') + @patch('builtins.open') + @patch('os.path', autospec=True) + def test_get_hosts_info(self, mock_path, mock_open, mock_load, mock_fn): + file_path = 'file_path' + file_complete_name = '/'.join((file_path, 'hosts.yaml')) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_path.isfile.return_value = True + file_obj = Mock() + mock_open.return_value.__enter__.return_value = file_obj + hosts_ip = '127.0.0.1' + hostnames = ['host_one', 'host_two'] + mock_load.return_value = {'hosts_info': {hosts_ip: hostnames}} + logger = Mock() + + names_str = ' '.join(hostnames) + expected = {names_str: hosts_ip} + result = dovetail_utils.get_hosts_info(logger) + + mock_path.join.assert_called_once_with(file_path, 'hosts.yaml') + mock_path.isfile.assert_called_once_with(file_complete_name) + mock_open.assert_called_once_with(file_complete_name) + mock_load.assert_called_once_with(file_obj) + mock_fn.assert_called_once_with(hosts_ip, hostnames) + logger.debug.assert_called_once_with('Get hosts info {}:{}.' + .format(hosts_ip, names_str)) + self.assertEqual(expected, result) + + @patch('os.path', autospec=True) + def test_check_cacert_false(self, mock_path): + file_one_path = 'path_one' + file_two_path = 'path_two' + logger = Mock() + mock_path.isfile.return_value = True + mock_path.dirname.return_value = file_one_path + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_two_path} + + expected = False + result = dovetail_utils.check_cacert_file(file_one_path, logger) + + mock_path.isfile.assert_called_once_with(file_one_path) + mock_path.dirname.assert_called_once_with(file_one_path) + logger.error.assert_called_once_with( + 'Credential file must be put under {}, ' + 'which can be mounted into other container.' + .format(file_two_path)) + self.assertEqual(expected, result) + + @patch('os.path', autospec=True) + def test_check_cacert_true(self, mock_path): + file_path = 'path_one' + mock_path.isfile.return_value = True + mock_path.dirname.return_value = file_path + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': file_path} + + expected = True + result = dovetail_utils.check_cacert_file(file_path) + + mock_path.isfile.assert_called_once_with(file_path) + mock_path.dirname.assert_called_once_with(file_path) + self.assertEqual(expected, result) + + @patch('os.path', autospec=True) + def test_check_cacert_not_exist(self, mock_path): + file_path = 'path_one' + mock_path.isfile.return_value = False + logger = Mock() + + expected = False + result = dovetail_utils.check_cacert_file(file_path, logger) + + mock_path.isfile.assert_called_once_with(file_path) + logger.error.assert_called_once_with( + 'OS_CACERT is {}, but the file does not exist.' + .format(file_path)) + self.assertEqual(expected, result) + + @patch('sys.stdout') + def test_show_progress_bar(self, mock_stdout): + length = 99 + max_length = 50 + expect_length = length % max_length + calls = [call('Running ' + ' ' * max_length + '\r'), + call('Running ' + '.' * expect_length + '\r')] + + dovetail_utils.show_progress_bar(length) + mock_stdout.write.assert_has_calls(calls) + mock_stdout.flush.assert_has_calls([call(), call()]) + + def test_get_duration(self): + date = '2018-08-10 05:12:27' + logger = Mock() + + expected = '0.0m0s' + result = dovetail_utils.get_duration(date, date, logger) + + self.assertEqual(expected, result) + + def test_get_duration_invalid_time(self): + date = 'invalid' + logger = Mock() + + expected = None + result = dovetail_utils.get_duration(date, date, logger) + + logger.exception.assert_called_once() + self.assertEqual(expected, result) + + @patch('os.getenv') + def test_check_https_enabled(self, mock_getenv): + auth_url = 'https://valid-url.com' + mock_getenv.return_value = auth_url + logger = Mock() + + expected = True + result = dovetail_utils.check_https_enabled(logger) + + logger.debug.assert_has_calls( + [call('Checking if https enabled or not...'), + call('https is enabled')]) + self.assertEqual(expected, result) + + @patch('os.getenv') + def test_check_https_disabled(self, mock_getenv): + auth_url = 'invalid' + mock_getenv.return_value = auth_url + logger = Mock() + + expected = False + result = dovetail_utils.check_https_enabled(logger) + + logger.debug.assert_has_calls( + [call('Checking if https enabled or not...'), + call('https is not enabled')]) + self.assertEqual(expected, result) + + @patch('python_hosts.Hosts', autospec=True) + @patch('python_hosts.HostsEntry', autospec=True) + def test_add_hosts_info_no_ip(self, mock_python_h_entry, + mock_python_hosts): + dovetail_utils.add_hosts_info(None, ['host_one']) + + mock_python_hosts.assert_called_once_with(path='/etc/hosts') + mock_python_h_entry.assert_not_called() + + @patch('python_hosts.Hosts', autospec=True) + @patch('python_hosts.HostsEntry', autospec=True) + def test_add_hosts_info_no_hosts(self, mock_python_h_entry, + mock_python_hosts): + dovetail_utils.add_hosts_info('127.0.0.1', []) + + mock_python_hosts.assert_called_once_with(path='/etc/hosts') + mock_python_h_entry.assert_not_called() + + @patch('python_hosts.Hosts', autospec=True) + @patch('python_hosts.HostsEntry', autospec=True) + def test_add_hosts_info(self, mock_python_h_entry, mock_python_hosts): + ip = '127.0.0.1' + hostnames = ['host_one'] + hosts_obj = Mock() + entry_obj = Mock() + mock_python_hosts.return_value = hosts_obj + mock_python_h_entry.return_value = entry_obj + + dovetail_utils.add_hosts_info(ip, hostnames) + + mock_python_hosts.assert_called_once_with(path='/etc/hosts') + mock_python_h_entry.assert_called_once_with(entry_type='ipv4', + address=ip, + names=hostnames) + hosts_obj.add.assert_called_once_with([entry_obj]) + hosts_obj.write.assert_called_once() + + def test_get_obj_by_path(self): + obj = {'list': ['a', 'b'], 'name': 'name'} + dst_path = ('name',) + + expected = 'name' + result = dovetail_utils.get_obj_by_path(obj, dst_path) + self.assertEqual(expected, result) + + @patch('dovetail.utils.dovetail_utils.objwalk') + def test_get_obj_by_path_none(self, mock_walk): + path = 'path' + dist_path = 'dst_path' + obj = 'obj' + mock_walk.return_value = [(path, obj)] + + expected = None + result = dovetail_utils.get_obj_by_path(obj, dist_path) + + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.environ') + def test_source_env(self, mock_env, mock_open): + file_path = 'file_path' + env_name = 'name' + env_value = 'value' + file_data = u'export %s=%s' % (env_name, env_value) + mock_open.return_value.__enter__.return_value = io.StringIO(file_data) + + dovetail_utils.source_env(file_path) + + mock_open.assert_called_once_with(file_path, 'r') + mock_env.update.assert_called_once_with({env_name: env_value}) + + @patch('dovetail.utils.dovetail_utils.docker') + def test_check_docker_version(self, mock_docker): + server_version = '1.12.3' + client_obj = Mock() + mock_docker.from_env.return_value = client_obj + client_obj.version.return_value = {'Version': server_version} + logger = Mock() + + dovetail_utils.check_docker_version(logger) + + logger.debug.assert_has_calls( + [call('Docker server version: {}'.format(server_version))]) + + @patch('dovetail.utils.dovetail_utils.docker') + def test_check_docker_version_error(self, mock_docker): + client_obj = Mock() + mock_docker.from_env.return_value = client_obj + client_obj.version.return_value = {} + logger = Mock() + + dovetail_utils.check_docker_version(logger) + + logger.error.assert_has_calls( + [call("Don't support this Docker server version. " + "Docker server should be updated to at least 1.12.3.")]) + + @patch('dovetail.utils.dovetail_utils.docker') + def test_check_docker_version_less_than(self, mock_docker): + server_version = '1.12.1' + client_obj = Mock() + mock_docker.from_env.return_value = client_obj + client_obj.version.return_value = {'Version': server_version} + logger = Mock() + + dovetail_utils.check_docker_version(logger) + + logger.error.assert_has_calls( + [call("Don't support this Docker server version. " + "Docker server should be updated to at least 1.12.3.")]) + + @patch('builtins.open') + @patch('os.path') + @patch('os.listdir') + @patch('json.load') + @patch('json.dumps') + def test_combine_files(self, mock_dumps, mock_load, mock_listdir, + mock_path, mock_open): + file_path = 'file_path' + file_name = 'file_name' + file_complete_name = '/'.join([file_path, file_name]) + file_content_dict = {'key': 'value'} + file_content_str = '{"key": "value"}' + file_obj = Mock() + mock_listdir.return_value = [file_name] + mock_path.join.return_value = file_complete_name + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = file_content_dict + mock_dumps.return_value = file_content_str + logger = Mock() + + expected = 'result_file' + result = dovetail_utils.combine_files(file_path, expected, logger) + + mock_listdir.assert_called_once_with(file_path) + mock_path.join.assert_called_once_with(file_path, file_name) + mock_open.assert_any_call(file_complete_name, 'r') + mock_load.assert_called_once_with(file_obj) + mock_open.assert_any_call(expected, 'w') + mock_dumps.assert_called_once_with({file_name: file_content_dict}) + file_obj.write.assert_called_once_with(file_content_str) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.path') + @patch('os.listdir') + def test_combine_files_read_exception(self, mock_listdir, mock_path, + mock_open): + file_path = 'file_path' + file_name = 'file_name' + file_complete_name = '/'.join([file_path, file_name]) + mock_listdir.return_value = [file_name] + mock_path.join.return_value = file_complete_name + mock_open.side_effect = Exception() + logger = Mock() + + expected = None + result = dovetail_utils.combine_files(file_path, expected, logger) + + mock_listdir.assert_called_once_with(file_path) + mock_path.join.assert_called_once_with(file_path, file_name) + mock_open.assert_any_call(file_complete_name, 'r') + logger.error.assert_called_once_with( + 'Failed to read file {}.'.format(file_complete_name)) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.path') + @patch('os.listdir') + @patch('json.load') + @patch('json.dumps') + def test_combine_files_write_exception(self, mock_dumps, mock_load, + mock_listdir, mock_path, mock_open): + file_path = 'file_path' + file_name = 'file_name' + file_complete_name = '/'.join([file_path, file_name]) + file_content_dict = {'key': 'value'} + file_content_str = '{"key": "value"}' + file_obj = Mock() + file_obj.write.side_effect = Exception() + mock_listdir.return_value = [file_name] + mock_path.join.return_value = file_complete_name + mock_open.return_value.__enter__.return_value = file_obj + mock_load.return_value = file_content_dict + mock_dumps.return_value = file_content_str + logger = Mock() + + expected = None + result = dovetail_utils.combine_files(file_path, expected, logger) + + mock_listdir.assert_called_once_with(file_path) + mock_path.join.assert_called_once_with(file_path, file_name) + mock_open.assert_any_call(file_complete_name, 'r') + mock_load.assert_called_once_with(file_obj) + mock_open.assert_any_call(expected, 'w') + mock_dumps.assert_called_once_with({file_name: file_content_dict}) + file_obj.write.assert_called_once_with(file_content_str) + logger.exception.assert_called_once_with( + 'Failed to write file {}.'.format(expected)) + self.assertEqual(expected, result) + + @patch('json.dump') + @patch('builtins.open') + @patch('os.path') + @patch('dovetail.utils.dovetail_utils.check_https_enabled') + @patch('os.getenv') + @patch('dovetail.utils.dovetail_utils.OS_Utils', autospec=True) + def test_get_openstack_endpoint(self, mock_utils, mock_getenv, + mock_https_check, mock_path, mock_open, + mock_dump): + mock_https_check.return_value = True + mock_getenv.return_value = 'True' + endpoints_ret = True + endpoint_url = 'http://www.abc.com' + endpoint_enabled = True + service_id = '123456789' + service_type = 'type' + service_name = 'name' + endpoints = [{'url': endpoint_url, + 'enabled': endpoint_enabled, + 'service_id': service_id}] + services_ret = True + services = [{'service_type': service_type, + 'name': service_name}] + file_path = 'file_path' + file_name = 'endpoint_info.json' + file_complete_name = '/'.join([file_path, file_name]) + utils_obj = Mock() + file_obj = Mock() + logger = Mock() + mock_utils.return_value = utils_obj + utils_obj.search_endpoints.return_value = (endpoints_ret, endpoints) + utils_obj.search_services.return_value = (services_ret, services) + dovetail_utils.dt_cfg.dovetail_config = {'result_dir': file_path} + mock_path.join.return_value = file_complete_name + mock_open.return_value.__enter__.return_value = file_obj + + expected = [{'Service Type': service_type, + 'URL': endpoint_url, + 'Enabled': endpoint_enabled, + 'Service Name': service_name}] + result = dovetail_utils.get_openstack_endpoint(logger=logger) + + mock_https_check.assert_called_once_with(logger) + mock_getenv.assert_called_once_with('OS_INSECURE') + mock_utils.assert_called_once_with(verify=False) + utils_obj.search_endpoints.assert_called_once() + utils_obj.search_services.assert_called_once_with( + service_id=service_id) + mock_path.join.assert_called_once_with(file_path, file_name) + mock_open.assert_any_call(file_complete_name, 'w') + mock_dump.assert_called_once_with(expected, file_obj) + logger.debug.assert_called_once_with( + 'Record all endpoint info into file {}.' + .format(file_complete_name)) + self.assertEqual(expected, result) + + @patch('dovetail.utils.dovetail_utils.check_https_enabled') + @patch('os.getenv') + @patch('dovetail.utils.dovetail_utils.OS_Utils', autospec=True) + def test_get_openstack_endpoint_no_endpoints(self, mock_utils, mock_getenv, + mock_https_check): + mock_https_check.return_value = True + mock_getenv.return_value = 'True' + endpoints_ret = False + endpoints_exception_msg = 'An exception occured' + utils_obj = Mock() + logger = Mock() + mock_utils.return_value = utils_obj + utils_obj.search_endpoints.return_value = (endpoints_ret, + endpoints_exception_msg) + + expected = None + result = dovetail_utils.get_openstack_endpoint(logger=logger) + + mock_https_check.assert_called_once_with(logger) + mock_getenv.assert_called_once_with('OS_INSECURE') + mock_utils.assert_called_once_with(verify=False) + utils_obj.search_endpoints.assert_called_once() + logger.error.assert_called_once_with( + 'Failed to list endpoints. Exception message, {}' + .format(endpoints_exception_msg)) + self.assertEqual(expected, result) + + @patch('dovetail.utils.dovetail_utils.check_https_enabled') + @patch('os.getenv') + @patch('dovetail.utils.dovetail_utils.OS_Utils', autospec=True) + def test_get_openstack_endpoint_no_services(self, mock_utils, mock_getenv, + mock_https_check): + mock_https_check.return_value = True + mock_getenv.return_value = 'True' + endpoints_ret = True + endpoint_url = 'http://www.abc.com' + endpoint_enabled = True + service_id = '123456789' + endpoints = [{'url': endpoint_url, + 'enabled': endpoint_enabled, + 'service_id': service_id}] + services_ret = False + services_exception_msg = 'An exception occured' + utils_obj = Mock() + logger = Mock() + mock_utils.return_value = utils_obj + utils_obj.search_endpoints.return_value = (endpoints_ret, endpoints) + utils_obj.search_services.return_value = (services_ret, + services_exception_msg) + + expected = None + result = dovetail_utils.get_openstack_endpoint(logger=logger) + + mock_https_check.assert_called_once_with(logger) + mock_getenv.assert_called_once_with('OS_INSECURE') + mock_utils.assert_called_once_with(verify=False) + utils_obj.search_endpoints.assert_called_once() + utils_obj.search_services.assert_called_once_with( + service_id=service_id) + logger.error.assert_called_once_with( + 'Failed to list services. Exception message, {}' + .format(services_exception_msg)) + self.assertEqual(expected, result) + + @patch('builtins.open') + @patch('os.path') + @patch('dovetail.utils.dovetail_utils.check_https_enabled') + @patch('os.getenv') + @patch('dovetail.utils.dovetail_utils.OS_Utils', autospec=True) + def test_get_openstack_endpoint_exception(self, mock_utils, mock_getenv, + mock_https_check, mock_path, + mock_open): + mock_https_check.return_value = False + mock_getenv.return_value = 'True' + endpoints_ret = True + endpoint_url = 'http://www.abc.com' + endpoint_enabled = True + service_id = '123456789' + service_type = 'type' + service_name = 'name' + endpoints = [{'url': endpoint_url, + 'enabled': endpoint_enabled, + 'service_id': service_id}] + services_ret = True + services = [{'service_type': service_type, + 'name': service_name}] + file_path = 'file_path' + file_name = 'endpoint_info.json' + file_complete_name = '/'.join([file_path, file_name]) + utils_obj = Mock() + logger = Mock() + mock_utils.return_value = utils_obj + utils_obj.search_endpoints.return_value = (endpoints_ret, endpoints) + utils_obj.search_services.return_value = (services_ret, services) + dovetail_utils.dt_cfg.dovetail_config = {'result_dir': file_path} + mock_path.join.return_value = file_complete_name + errorMSG = 'Exception was raised' + exception = Exception(errorMSG) + mock_open.side_effect = exception + + expected = None + result = dovetail_utils.get_openstack_endpoint(logger=logger) + + mock_https_check.assert_called_once_with(logger) + mock_getenv.assert_called_once_with('OS_INSECURE') + mock_utils.assert_called_once_with() + utils_obj.search_endpoints.assert_called_once() + utils_obj.search_services.assert_called_once_with( + service_id=service_id) + mock_path.join.assert_called_once_with(file_path, file_name) + mock_open.assert_any_call(file_complete_name, 'w') + logger.exception.assert_called_once_with( + 'Failed to write endpoint info into file.') + self.assertEqual(expected, result) + + @patch('os.path') + @patch('dovetail.utils.dovetail_utils.get_inventory_file') + @patch('dovetail.utils.dovetail_utils.exec_cmd') + @patch('dovetail.utils.dovetail_utils.combine_files') + def test_get_hardware_info(self, mock_combine, mock_cmd, mock_inventory, + mock_path): + logger = Mock() + config_dir = 'config_dir' + result_dir = 'result_dir' + pod_file = 'pod_file' + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': config_dir, + 'result_dir': result_dir, + 'pod_file': pod_file} + mock_inventory.return_value = Mock() + ret = 0 + msg = '' + mock_cmd.return_value = (ret, msg) + inventory_file = '/'.join([result_dir, 'inventory.ini']) + info_file_path = '/'.join([result_dir, 'sut_hardware_info']) + all_info_file = '/'.join([result_dir, 'all_hosts_info.json']) + mock_path.join.side_effect = [ + '/'.join([config_dir, pod_file]), + info_file_path, + all_info_file, + inventory_file] + mock_path.exists.return_value = True + mock_combine.return_value = True + + expected = all_info_file + result = dovetail_utils.get_hardware_info(logger=logger) + + join_calls = [call(config_dir, pod_file), + call(result_dir, 'sut_hardware_info'), + call(result_dir, 'all_hosts_info.json'), + call(result_dir, 'inventory.ini')] + mock_path.join.assert_has_calls(join_calls) + log_calls = [ + call('Get hardware info of all nodes list in file {} ...' + .format('/'.join([config_dir, pod_file]))), + call('Hardware info of all nodes are stored in file {}.' + .format(expected))] + logger.info.assert_has_calls(log_calls) + mock_cmd.assert_called_once_with( + 'cd {} && ansible all -m setup -i {} --tree {}' + .format(constants.USERCONF_PATH, inventory_file, info_file_path), + verbose=False) + mock_path.exists.assert_called_once_with(info_file_path) + mock_combine.assert_called_once_with(info_file_path, all_info_file, + logger) + self.assertEqual(expected, result) + + @patch('os.path') + @patch('dovetail.utils.dovetail_utils.get_inventory_file') + def test_get_hardware_info_no_inventory(self, mock_inventory, + mock_path): + logger = Mock() + config_dir = 'config_dir' + result_dir = 'result_dir' + pod_file = 'pod_file' + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': config_dir, + 'result_dir': result_dir, + 'pod_file': pod_file} + mock_inventory.return_value = None + mock_path.join.side_effect = [ + '/'.join([config_dir, pod_file]), + '/'.join([result_dir, 'sut_hardware_info']), + '/'.join([result_dir, 'all_hosts_info.json']), + '/'.join([result_dir, 'inventory.ini'])] + + expected = None + result = dovetail_utils.get_hardware_info(logger=logger) + + join_calls = [call(config_dir, pod_file), + call(result_dir, 'sut_hardware_info'), + call(result_dir, 'all_hosts_info.json'), + call(result_dir, 'inventory.ini')] + mock_path.join.assert_has_calls(join_calls) + logger.info.assert_called_once_with( + 'Get hardware info of all nodes list in file {} ...' + .format('/'.join([config_dir, pod_file]))) + logger.error.assert_called_once_with( + 'Failed to get SUT hardware info.') + self.assertEqual(expected, result) + + @patch('os.path') + @patch('dovetail.utils.dovetail_utils.get_inventory_file') + @patch('dovetail.utils.dovetail_utils.exec_cmd') + def test_get_hardware_info_no_info(self, mock_cmd, mock_inventory, + mock_path): + logger = Mock() + config_dir = 'config_dir' + result_dir = 'result_dir' + pod_file = 'pod_file' + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': config_dir, + 'result_dir': result_dir, + 'pod_file': pod_file} + mock_inventory.return_value = Mock() + ret = 0 + msg = '' + mock_cmd.return_value = (ret, msg) + inventory_file = '/'.join([result_dir, 'inventory.ini']) + info_file_path = '/'.join([result_dir, 'sut_hardware_info']) + all_info_file = '/'.join([result_dir, 'all_hosts_info.json']) + mock_path.join.side_effect = [ + '/'.join([config_dir, pod_file]), + info_file_path, + all_info_file, + inventory_file] + mock_path.exists.return_value = False + + expected = None + result = dovetail_utils.get_hardware_info(logger=logger) + + join_calls = [call(config_dir, pod_file), + call(result_dir, 'sut_hardware_info'), + call(result_dir, 'all_hosts_info.json'), + call(result_dir, 'inventory.ini')] + mock_path.join.assert_has_calls(join_calls) + logger.info.assert_called_once_with( + 'Get hardware info of all nodes list in file {} ...' + .format('/'.join([config_dir, pod_file]))) + logger.error.assert_called_once_with( + 'Failed to get SUT hardware info.') + mock_cmd.assert_called_once_with( + 'cd {} && ansible all -m setup -i {} --tree {}' + .format(constants.USERCONF_PATH, inventory_file, info_file_path), + verbose=False) + mock_path.exists.assert_called_once_with(info_file_path) + self.assertEqual(expected, result) + + @patch('os.path') + @patch('dovetail.utils.dovetail_utils.get_inventory_file') + @patch('dovetail.utils.dovetail_utils.exec_cmd') + @patch('dovetail.utils.dovetail_utils.combine_files') + def test_get_hardware_info_no_combine(self, mock_combine, mock_cmd, + mock_inventory, mock_path): + logger = Mock() + config_dir = 'config_dir' + result_dir = 'result_dir' + pod_file = 'pod_file' + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': config_dir, + 'result_dir': result_dir, + 'pod_file': pod_file} + mock_inventory.return_value = Mock() + ret = 0 + msg = '' + mock_cmd.return_value = (ret, msg) + inventory_file = '/'.join([result_dir, 'inventory.ini']) + info_file_path = '/'.join([result_dir, 'sut_hardware_info']) + all_info_file = '/'.join([result_dir, 'all_hosts_info.json']) + mock_path.join.side_effect = [ + '/'.join([config_dir, pod_file]), + info_file_path, + all_info_file, + inventory_file] + mock_path.exists.return_value = True + mock_combine.return_value = False + + expected = None + result = dovetail_utils.get_hardware_info(logger=logger) + + join_calls = [call(config_dir, pod_file), + call(result_dir, 'sut_hardware_info'), + call(result_dir, 'all_hosts_info.json'), + call(result_dir, 'inventory.ini')] + mock_path.join.assert_has_calls(join_calls) + logger.info.assert_called_once_with( + 'Get hardware info of all nodes list in file {} ...' + .format('/'.join([config_dir, pod_file]))) + logger.error.assert_called_once_with( + 'Failed to get all hardware info.') + mock_cmd.assert_called_once_with( + 'cd {} && ansible all -m setup -i {} --tree {}' + .format(constants.USERCONF_PATH, inventory_file, info_file_path), + verbose=False) + mock_path.exists.assert_called_once_with(info_file_path) + mock_combine.assert_called_once_with(info_file_path, all_info_file, + logger) + self.assertEqual(expected, result) + + @patch('os.path') + @patch('builtins.open') + @patch('yaml.safe_load') + def test_get_inventory_password(self, mock_load, mock_open, mock_path): + name = 'name' + ip = 'ip' + user = 'user' + password = 'password' + pod_file_data = {'nodes': [{'name': name, + 'ip': ip, + 'user': user, + 'password': password}]} + inventory_file_name = 'inventory' + pod_file_name = 'pod' + logger = Mock() + pod_file_obj = Mock() + inventory_file_obj = Mock() + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.side_effect = [pod_file_obj, + inventory_file_obj] + mock_load.return_value = pod_file_data + + expected = True + result = dovetail_utils.get_inventory_file(pod_file_name, + inventory_file_name, + logger=logger) + + mock_path.isfile.assert_called_once_with(pod_file_name) + mock_open.assert_any_call(pod_file_name, 'r') + mock_open.assert_any_call(inventory_file_name, 'w') + mock_load.assert_called_once_with(pod_file_obj) + inventory_file_obj.write.assert_called_once_with( + '{name} ansible_host={ip} ansible_user={user} ' + 'ansible_ssh_pass={password}\n' + .format(name=name, ip=ip, user=user, password=password)) + logger.debug.assert_called_once_with( + 'Ansible inventory file is {}.'.format(inventory_file_name)) + self.assertEqual(expected, result) + + @patch('os.path') + @patch('builtins.open') + @patch('yaml.safe_load') + def test_get_inventory_key_filename(self, mock_load, mock_open, mock_path): + name = 'name' + ip = 'ip' + user = 'user' + password = 'password' + pod_file_data = {'nodes': [{'name': name, + 'ip': ip, + 'user': user, + 'key_filename': password}]} + inventory_file_name = 'inventory' + pod_file_name = 'pod' + logger = Mock() + pod_file_obj = Mock() + inventory_file_obj = Mock() + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.side_effect = [pod_file_obj, + inventory_file_obj] + mock_load.return_value = pod_file_data + config_dir = 'config_dir' + key_file = '/'.join([config_dir, 'id_rsa']) + dovetail_utils.dt_cfg.dovetail_config = {'config_dir': config_dir} + mock_path.join.return_value = key_file + + expected = True + result = dovetail_utils.get_inventory_file(pod_file_name, + inventory_file_name, + logger=logger) + + mock_path.isfile.assert_called_once_with(pod_file_name) + mock_open.assert_any_call(pod_file_name, 'r') + mock_open.assert_any_call(inventory_file_name, 'w') + mock_load.assert_called_once_with(pod_file_obj) + mock_path.join.assert_called_once_with(config_dir, 'id_rsa') + inventory_file_obj.write.assert_called_once_with( + '{name} ansible_host={ip} ansible_user={user} ' + 'ansible_ssh_private_key_file={key_file}\n' + .format(name=name, ip=ip, user=user, key_file=key_file)) + logger.debug.assert_called_once_with( + 'Ansible inventory file is {}.'.format(inventory_file_name)) + self.assertEqual(expected, result) + + @patch('os.path') + @patch('builtins.open') + @patch('yaml.safe_load') + def test_get_inventory_other(self, mock_load, mock_open, mock_path): + name = 'name' + ip = 'ip' + user = 'user' + pod_file_data = {'nodes': [{'name': name, + 'ip': ip, + 'user': user}]} + inventory_file_name = 'inventory' + pod_file_name = 'pod' + logger = Mock() + pod_file_obj = Mock() + inventory_file_obj = Mock() + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.side_effect = [pod_file_obj, + inventory_file_obj] + mock_load.return_value = pod_file_data + + expected = False + result = dovetail_utils.get_inventory_file(pod_file_name, + inventory_file_name, + logger=logger) + + mock_path.isfile.assert_called_once_with(pod_file_name) + mock_open.assert_any_call(pod_file_name, 'r') + mock_open.assert_any_call(inventory_file_name, 'w') + mock_load.assert_called_once_with(pod_file_obj) + logger.error.assert_called_once_with( + 'No password or key_filename in file {}.'.format(pod_file_name)) + self.assertEqual(expected, result) + + @patch('os.path') + @patch('builtins.open') + @patch('yaml.safe_load') + def test_get_inventory_keyerror(self, mock_load, mock_open, mock_path): + name = 'name' + ip = 'ip' + pod_file_data = {'nodes': [{'name': name, + 'ip': ip}]} + inventory_file_name = 'inventory' + pod_file_name = 'pod' + logger = Mock() + pod_file_obj = Mock() + inventory_file_obj = Mock() + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.side_effect = [pod_file_obj, + inventory_file_obj] + mock_load.return_value = pod_file_data + + expected = False + result = dovetail_utils.get_inventory_file(pod_file_name, + inventory_file_name, + logger=logger) + + mock_path.isfile.assert_called_once_with(pod_file_name) + mock_open.assert_any_call(pod_file_name, 'r') + mock_open.assert_any_call(inventory_file_name, 'w') + mock_load.assert_called_once_with(pod_file_obj) + logger.exception.assert_called_once_with( + "KeyError 'user'.") + self.assertEqual(expected, result) + + @patch('os.path') + @patch('builtins.open') + def test_get_inventory_exception(self, mock_open, mock_path): + inventory_file_name = 'inventory' + pod_file_name = 'pod' + logger = Mock() + mock_path.isfile.return_value = True + mock_open.return_value.__enter__.side_effect = Exception() + + expected = False + result = dovetail_utils.get_inventory_file(pod_file_name, + inventory_file_name, + logger=logger) + + mock_path.isfile.assert_called_once_with(pod_file_name) + mock_open.assert_called_once_with(pod_file_name, 'r') + logger.exception.assert_called_once_with( + 'Failed to read file {}.'.format(pod_file_name)) + self.assertEqual(expected, result) + + @patch('os.path') + def test_get_inventory_invalid_pod_file(self, mock_path): + inventory_file_name = 'inventory' + pod_file_name = 'pod' + logger = Mock() + mock_path.isfile.return_value = False + + expected = False + result = dovetail_utils.get_inventory_file(pod_file_name, + inventory_file_name, + logger=logger) + + mock_path.isfile.assert_called_once_with(pod_file_name) + logger.error.assert_called_once_with( + "File {} doesn't exist.".format(pod_file_name)) + self.assertEqual(expected, result) + + @patch('subprocess.Popen') + @patch('subprocess.PIPE') + @patch('subprocess.STDOUT') + @patch('os.getenv') + @patch('dovetail.utils.dovetail_utils.exec_log') + @patch('dovetail.utils.dovetail_utils.show_progress_bar') + def test_exec_cmd(self, mock_bar, mock_log, mock_getenv, mock_stdout, + mock_pipe, mock_open): + logger = Mock() + cmd = 'cmd' + verbose = True + subprocess_obj = Mock() + cmd_output = 'line' + mock_open.return_value = subprocess_obj + pip_obj = Mock() + stdout_obj = Mock() + mock_pipe.return_value = pip_obj + mock_stdout.return_value = stdout_obj + subp_stdout = Mock() + subprocess_obj.stdout = subp_stdout + subprocess_obj.wait.return_value = 0 + subp_stdout.readline.side_effect = [cmd_output.encode()] + + expected = (0, "b'line'") + result = dovetail_utils.exec_cmd( + cmd, logger=logger, exit_on_error=True, info=False, + exec_msg_on=True, err_msg='', verbose=verbose, + progress_bar=True) + + log_calls = [ + call(verbose, logger, "Executing command: '%s'" % cmd, 'debug'), + call(verbose, logger, cmd_output, 'debug', True)] + mock_log.assert_has_calls(log_calls) + mock_open.assert_called_once_with(cmd, shell=True, stdout=mock_pipe, + stderr=mock_stdout) + subp_stdout.readline.assert_has_calls([call(), call()]) + subp_stdout.close.assert_called_once_with() + subprocess_obj.wait.assert_called_once_with() + mock_getenv.assert_called_once_with('DEBUG') + # mock_bar.assert_called_once_with(1) + self.assertEqual(expected, result) + + @patch('sys.exit') + @patch('subprocess.Popen') + @patch('subprocess.PIPE') + @patch('subprocess.STDOUT') + @patch('os.getenv') + @patch('dovetail.utils.dovetail_utils.exec_log') + @patch('dovetail.utils.dovetail_utils.show_progress_bar') + def test_exec_cmd_error(self, mock_bar, mock_log, mock_getenv, mock_stdout, + mock_pipe, mock_open, mock_exit): + logger = Mock() + cmd = 'cmd' + verbose = True + subprocess_obj = Mock() + cmd_output = 'line' + mock_open.return_value = subprocess_obj + pip_obj = Mock() + stdout_obj = Mock() + mock_pipe.return_value = pip_obj + mock_stdout.return_value = stdout_obj + subp_stdout = Mock() + subprocess_obj.stdout = subp_stdout + subprocess_obj.wait.return_value = 1 + subp_stdout.readline.side_effect = [cmd_output.encode()] + + dovetail_utils.exec_cmd( + cmd, logger=logger, exit_on_error=True, info=False, + exec_msg_on=True, err_msg='', verbose=verbose, + progress_bar=True) + + log_calls = [ + call(verbose, logger, "Executing command: '%s'" % cmd, 'debug'), + call(verbose, logger, cmd_output, 'debug', True), + call(verbose, logger, "The command '%s' failed." % cmd, 'error')] + mock_log.assert_has_calls(log_calls) + mock_open.assert_called_once_with(cmd, shell=True, stdout=mock_pipe, + stderr=mock_stdout) + subp_stdout.readline.assert_has_calls([call(), call()]) + subp_stdout.close.assert_called_once_with() + subprocess_obj.wait.assert_called_once_with() + mock_getenv.assert_called_once_with('DEBUG') + # mock_bar.assert_called_once_with(1) + mock_exit.assert_called_once_with(1) + + @patch('os.path', autospec=True) + def test_get_openstack_info_no_openrc(self, mock_path): + logger = Mock() + config_dir = 'config_dir' + env_file = 'env_file' + dovetail_utils.dt_cfg.dovetail_config = { + 'config_dir': config_dir, 'env_file': env_file} + mock_path.join.side_effect = ['openrc'] + mock_path.isfile.return_value = False + dovetail_utils.get_openstack_info(logger) + + mock_path.join.assert_called_once_with(config_dir, env_file) + mock_path.isfile.assert_called_once_with('openrc') + logger.error.assert_called_once_with('File openrc does not exist.') + + @patch('dovetail.utils.dovetail_utils.source_env') + @patch('dovetail.utils.dovetail_utils.get_hosts_info') + @patch('dovetail.utils.dovetail_utils.get_openstack_endpoint') + @patch('dovetail.utils.dovetail_utils.get_hardware_info') + @patch('os.path', autospec=True) + def test_get_openstack_info(self, mock_path, mock_hardware, mock_endpoint, + mock_host, mock_env): + logger = Mock() + config_dir = 'config_dir' + env_file = 'env_file' + dovetail_utils.dt_cfg.dovetail_config = { + 'config_dir': config_dir, 'env_file': env_file} + mock_path.join.side_effect = ['openrc'] + mock_path.isfile.return_value = True + dovetail_utils.get_openstack_info(logger) + + mock_path.join.assert_called_once_with(config_dir, env_file) + mock_path.isfile.assert_called_once_with('openrc') + mock_env.assert_called_once() + mock_host.assert_called_once() + mock_endpoint.assert_called_once() + mock_hardware.assert_called_once() + + @patch('json.dumps') + @patch('dovetail.utils.dovetail_utils.requests') + @patch('os.getenv') + def test_push_results_to_db(self, mock_getenv, mock_requests, mock_dumps): + logger = Mock() + case_name = 'case_name' + details = {'criteria': 'PASS'} + start_date = 'start_date' + stop_date = 'stop_date' + mock_getenv.side_effect = [ + 'url', 'installer', 'scenario', 'pod_name', 'build_tag', 'version'] + post_req = Mock() + post_req.raise_for_status.return_value = None + mock_requests.post.return_value = post_req + mock_dumps.return_value = {"project_name": "dovetail"} + + dovetail_utils.push_results_to_db( + case_name, details, start_date, stop_date, logger) + + mock_requests.post.assert_called_once_with( + 'url', + data={"project_name": "dovetail"}, + headers={"Content-Type": "application/json"}) + logger.debug.assert_called_once_with( + "The results were successfully pushed to DB.") + + @patch('json.dumps') + @patch('dovetail.utils.dovetail_utils.requests') + @patch('os.getenv') + def test_push_results_to_db_exception(self, mock_getenv, mock_requests, + mock_dumps): + logger = Mock() + case_name = 'case_name' + details = {'criteria': 'PASS'} + start_date = 'start_date' + stop_date = 'stop_date' + mock_getenv.side_effect = [ + 'url', 'installer', 'scenario', 'pod_name', 'build_tag', 'version'] + post_req = Mock() + post_req.raise_for_status.side_effect = Exception() + mock_requests.post.return_value = post_req + mock_dumps.return_value = {"project_name": "dovetail"} + dovetail_utils.push_results_to_db( + case_name, details, start_date, stop_date, logger) + + logger.debug.assert_not_called() + logger.exception.assert_called_once_with( + "The results cannot be pushed to DB.") + + def test_get_mount_list_error_mount(self): + project_cfg = {'mounts': ['aaa']} + res, msg = dovetail_utils.get_mount_list(project_cfg) + self.assertEqual(None, res) + self.assertEqual('Error mount aaa.', msg) + + def test_get_mount_list_keyerror_exception(self): + project_cfg = {'mounts': ['aaa=a,bbb=b', '']} + res, msg = dovetail_utils.get_mount_list(project_cfg) + self.assertEqual(None, res) + self.assertEqual("'target'", str(msg)) + + def test_get_mount_list(self): + project_cfg = {'mounts': ['target=a,source=b', '']} + res, msg = dovetail_utils.get_mount_list(project_cfg) + expected = [{'Source': 'b', 'Type': 'bind', 'ReadOnly': False, + 'Target': 'a'}] + self.assertEqual(expected, res) + self.assertEqual('Successfully to get mount list.', msg) diff --git a/dovetail/tests/unit/utils/test_openstack_utils.py b/dovetail/tests/unit/utils/test_openstack_utils.py new file mode 100644 index 00000000..73583838 --- /dev/null +++ b/dovetail/tests/unit/utils/test_openstack_utils.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Copyright (c) 2018 mokats@intracom-telecom.com and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +## + +import unittest + +from mock import patch +import munch +import os_client_config +import shade + +import dovetail.utils.openstack_utils as os_dovetail_utils + +__author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>' + + +class OpenStackUtilsTesting(unittest.TestCase): + + def setUp(self): + self.patcher1 = patch.object(shade, + 'OperatorCloud', autospec=True) + self.patcher2 = patch.object(os_client_config, + 'get_config', autospec=True) + self.cloud = self.patcher1.start().return_value + self.os_client_config = self.patcher2.start().return_value + self.os_dovetail = os_dovetail_utils.OS_Utils() + + def tearDown(self): + self.patcher1.stop() + self.patcher2.stop() + + def test_search_endpoints(self): + endpoint = munch.Munch({u'region_id': u'RegionOne', + u'url': u'http://127.0.0.1:8977/', + u'region': u'RegionOne', + u'enabled': True, + u'interface': u'public', + u'service_id': u'123456', + u'id': u'123456'}) + endpoints = [endpoint] + self.cloud.search_endpoints.return_value = endpoints + + expected = (True, endpoints) + result = self.os_dovetail.search_endpoints() + + self.assertEqual(expected, result) + + def test_search_endpoints_raised_exception(self): + errorMSG = 'Exception was raised' + exception = shade.exc.OpenStackCloudException(errorMSG) + self.cloud.search_endpoints.side_effect = exception + + expected = (False, errorMSG) + result = self.os_dovetail.search_endpoints() + + self.assertEqual(expected, result) + + def test_search_services(self): + service = munch.Munch({'description': u'OpenStack Identity Service', + 'service_type': u'identity', + 'type': u'identity', + 'enabled': True, + 'id': u'1bd26028c8714f3bb726126dc1ea62fc', + 'name': u'keystone'}) + services = [service] + self.cloud.search_services.return_value = services + + expected = (True, services) + result = self.os_dovetail.search_services() + + self.assertEqual(expected, result) + + def test_search_services_raised_exception(self): + errorMSG = 'Exception was raised' + exception = shade.exc.OpenStackCloudException(errorMSG) + self.cloud.search_services.side_effect = exception + + expected = (False, errorMSG) + result = self.os_dovetail.search_services() + + self.assertEqual(expected, result) |