def test_save_db_removes_file_in_case_of_error(self, remove_mock, _, __): self.upgrader.exec_cmd_in_container = mock.MagicMock( side_effect=errors.ExecutedErrorNonZeroExitCode()) self.assertRaises(errors.ExecutedErrorNonZeroExitCode, self.upgrader.save_db) self.called_once(remove_mock)
def _wait_and_check_exit_code(cmd, child): """Wait for child and check it's exit code :param cmd: command :param child: object which returned by subprocess.Popen :raises: ExecutedErrorNonZeroExitCode """ child.wait() exit_code = child.returncode if exit_code != 0: raise errors.ExecutedErrorNonZeroExitCode( 'Shell command executed with "{0}" ' 'exit code: {1} '.format(exit_code, cmd)) logger.debug('Command "%s" successfully executed', cmd)
class TestDockerUpgrader(BaseTestCase): def setUp(self): # NOTE (eli): mocking doesn't work correctly # when we try to patch docker client with # class decorator, it's the reason why # we have to do it explicitly self.docker_patcher = mock.patch( 'fuel_upgrade.engines.docker_engine.docker.Client') self.docker_mock_class = self.docker_patcher.start() self.docker_mock = mock.MagicMock() self.docker_mock_class.return_value = self.docker_mock self.supervisor_patcher = mock.patch( 'fuel_upgrade.engines.docker_engine.SupervisorClient') self.supervisor_class = self.supervisor_patcher.start() self.supervisor_mock = mock.MagicMock() self.supervisor_class.return_value = self.supervisor_mock self.version_mock = mock.MagicMock() with mock.patch('fuel_upgrade.engines.docker_engine.utils'): with mock.patch('fuel_upgrade.engines.docker_engine.VersionFile', return_value=self.version_mock): self.upgrader = DockerUpgrader(self.fake_config) self.upgrader.upgrade_verifier = mock.MagicMock() self.pg_dump_path = '/var/lib/fuel_upgrade/9999/pg_dump_all.sql' def tearDown(self): self.docker_patcher.stop() self.supervisor_patcher.stop() def mock_methods(self, obj, methods): for method in methods: setattr(obj, method, mock.MagicMock()) def test_upgrade(self): mocked_methods = [ 'stop_fuel_containers', 'save_db', 'save_cobbler_configs', 'save_astute_keys', 'upload_images', 'create_and_start_new_containers', 'generate_configs', 'switch_to_new_configs'] self.mock_methods(self.upgrader, mocked_methods) self.upgrader.upgrade() self.assertEqual( self.upgrader.generate_configs.call_args_list, [mock.call(autostart=False), mock.call(autostart=True)]) self.called_once(self.upgrader.stop_fuel_containers) self.called_once(self.supervisor_mock.stop_all_services) self.called_once(self.supervisor_mock.restart_and_wait) self.called_once(self.upgrader.upgrade_verifier.verify) self.called_once(self.version_mock.save_current) self.called_once(self.version_mock.switch_to_new) def test_rollback(self): self.upgrader.stop_fuel_containers = mock.MagicMock() self.upgrader.switch_version_file_to_previous_version = \ mock.MagicMock() self.upgrader.rollback() self.called_times(self.upgrader.stop_fuel_containers, 1) self.called_once(self.supervisor_mock.switch_to_previous_configs) self.called_once(self.supervisor_mock.stop_all_services) self.called_once(self.supervisor_mock.restart_and_wait) self.called_once(self.version_mock.save_current) self.called_once(self.version_mock.switch_to_previous) @mock.patch('fuel_upgrade.engines.docker_engine.utils') @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=['file1', 'file2']) def test_on_success(self, glob_mock, utils_mock): self.upgrader.on_success() glob_mock.assert_called_once_with(self.fake_config.version_files_mask) self.assertEqual( utils_mock.remove.call_args_list, [mock.call('file1'), mock.call('file2')]) def test_stop_fuel_containers(self): non_fuel_images = [ 'first_image_1.0', 'second_image_2.0', 'third_image_2.0'] fuel_images = [ 'fuel/image_1.0', 'fuel/image_2.0'] all_images = [{'Image': v, 'Id': i} for i, v in enumerate(non_fuel_images + fuel_images)] ports = [1, 2, 3] self.upgrader._get_docker_container_public_ports = mock.MagicMock( return_value=ports) self.docker_mock.containers.return_value = all_images self.upgrader.stop_fuel_containers() self.assertEqual( self.docker_mock.stop.call_args_list, [mock.call(3, 20), mock.call(4, 20)]) @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd') @mock.patch('fuel_upgrade.engines.docker_engine.os.path.exists', return_value=True) def test_upload_images(self, _, exec_mock): self.upgrader.new_release_images = [ {'docker_image': 'image1'}, {'docker_image': 'image2'}] self.upgrader.upload_images() self.assertEqual( exec_mock.call_args_list, [mock.call('docker load < "image1"'), mock.call('docker load < "image2"')]) def test_create_containers(self): fake_containers = [ {'id': 'id1', 'container_name': 'name1', 'image_name': 'i_name1', 'volumes_from': ['id2']}, {'id': 'id2', 'image_name': 'i_name2', 'container_name': 'name2', 'after_container_creation_command': 'cmd', 'supervisor_config': True}] self.upgrader.new_release_containers = fake_containers def mocked_create_container(*args, **kwargs): """Return name of the container """ return kwargs['name'] self.upgrader.create_container = mock.MagicMock( side_effect=mocked_create_container) self.upgrader.start_container = mock.MagicMock() self.upgrader.run_after_container_creation_command = mock.MagicMock() self.upgrader.clean_iptables_rules = mock.MagicMock() self.upgrader.start_service_under_supervisor = mock.MagicMock() self.upgrader.create_and_start_new_containers() create_container_calls = [ mock.call('i_name2', detach=False, ports=None, volumes=None, name='name2'), mock.call('i_name1', detach=False, ports=None, volumes=None, name='name1')] start_container_calls = [ mock.call('name2', volumes_from=[], binds=None, port_bindings=None, privileged=False, links=[]), mock.call('name1', volumes_from=['name2'], binds=None, port_bindings=None, privileged=False, links=[])] self.upgrader.clean_iptables_rules.assert_called_once_with( fake_containers[-1]) self.upgrader.start_service_under_supervisor.assert_called_once_with( 'docker-id2') self.assertEqual( self.upgrader.create_container.call_args_list, create_container_calls) self.assertEqual( self.upgrader.start_container.call_args_list, start_container_calls) self.called_once(self.upgrader.run_after_container_creation_command) def test_run_after_container_creation_command(self): self.upgrader.exec_with_retries = mock.MagicMock() self.upgrader.run_after_container_creation_command({ 'after_container_creation_command': 'cmd', 'container_name': 'name'}) args, kwargs = self.upgrader.exec_with_retries.call_args self.assertEqual(args[1], errors.ExecutedErrorNonZeroExitCode) self.assertEqual(kwargs, {'retries': 30, 'interval': 4}) def test_create_container(self): self.upgrader.create_container( 'image_name', param1=1, param2=2, ports=[1234]) self.docker_mock.create_container.assert_called_once_with( 'image_name', param2=2, param1=1, ports=[1234]) def test_start_container(self): self.upgrader.start_container( {'Id': 'container_id'}, param1=1, param2=2) self.docker_mock.start.assert_called_once_with( 'container_id', param2=2, param1=1) def test_build_dependencies_graph(self): containers = [ {'id': '1', 'volumes_from': ['2'], 'links': [{'id': '3'}]}, {'id': '2', 'volumes_from': [], 'links': []}, {'id': '3', 'volumes_from': [], 'links': [{'id': '2'}]}] actual_graph = self.upgrader.build_dependencies_graph(containers) expected_graph = { '1': ['2', '3'], '2': [], '3': ['2']} self.assertEqual(actual_graph, expected_graph) def test_get_container_links(self): fake_containers = [ {'id': 'id1', 'container_name': 'container_name1', 'links': [{'id': 'id2', 'alias': 'alias2'}]}, {'id': 'id2', 'container_name': 'container_name2'}] self.upgrader.new_release_containers = fake_containers links = self.upgrader.get_container_links(fake_containers[0]) self.assertEqual(links, [('container_name2', 'alias2')]) def test_get_ports(self): ports = self.upgrader.get_ports({'ports': [[53, 'udp'], 100]}) self.assertEqual([(53, 'udp'), 100], ports) def test_generate_configs(self): fake_containers = [ {'id': 'id1', 'container_name': 'container_name1', 'supervisor_config': False}, {'id': 'id2', 'container_name': 'container_name2', 'supervisor_config': True}, {'id': 'cobbler', 'container_name': 'cobbler_container', 'supervisor_config': False}] self.upgrader.new_release_containers = fake_containers self.upgrader.generate_configs() self.supervisor_mock.generate_configs.assert_called_once_with( [{'config_name': 'id2', 'service_name': 'docker-id2', 'command': 'docker start -a container_name2', 'autostart': True}]) self.supervisor_mock.generate_cobbler_config.assert_called_once_with( 'cobbler', 'docker-cobbler', 'cobbler_container', autostart=True) def test_switch_to_new_configs(self): self.upgrader.switch_to_new_configs() self.supervisor_mock.switch_to_new_configs.assert_called_once_with() @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd') def test_exec_cmd_in_container(self, exec_cmd_mock): name = 'container_name' cmd = 'some command' self.upgrader.container_docker_id = mock.MagicMock(return_value=name) self.upgrader.exec_cmd_in_container(name, cmd) self.called_once(self.upgrader.container_docker_id) exec_cmd_mock.assert_called_once_with( "lxc-attach --name {0} -- {1}".format(name, cmd)) @mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.exec_cmd') @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.verify_cobbler_configs') def test_save_cobbler_configs(self, verify_mock, exec_cmd_mock): self.upgrader.save_cobbler_configs() exec_cmd_mock.assert_called_once_with( 'docker cp fuel-core-0-cobbler:/var/lib/cobbler/config ' '/var/lib/fuel_upgrade/9999/cobbler_configs') self.called_once(verify_mock) @mock.patch('fuel_upgrade.engines.docker_engine.utils.rmtree') @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd', side_effect=errors.ExecutedErrorNonZeroExitCode()) def test_save_cobbler_configs_removes_dir_in_case_of_error( self, exec_cmd_mock, rm_mock): with self.assertRaises(errors.ExecutedErrorNonZeroExitCode): self.upgrader.save_cobbler_configs() cobbler_config_path = '/var/lib/fuel_upgrade/9999/cobbler_configs' exec_cmd_mock.assert_called_once_with( 'docker cp fuel-core-0-cobbler:/var/lib/cobbler/config ' '{0}'.format(cobbler_config_path)) rm_mock.assert_called_once_with(cobbler_config_path) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_save_astute_keys(self, utils_mock): self.upgrader.save_astute_keys() utils_mock.exec_cmd.assert_called_once_with( 'docker cp fuel-core-0-astute:/var/lib/astute ' '/var/lib/fuel_upgrade/9999') utils_mock.remove.assert_called_once_with( '/var/lib/fuel_upgrade/9999/astute') @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd', side_effect=errors.ExecutedErrorNonZeroExitCode()) @mock.patch('fuel_upgrade.engines.docker_engine.os') @mock.patch('fuel_upgrade.engines.docker_engine.utils.remove') def test_save_astute_keys_creates_dir_if_error( self, remove_mock, os_mock, exec_cmd_mock): self.upgrader.save_astute_keys() exec_cmd_mock.assert_called_once_with( 'docker cp fuel-core-0-astute:/var/lib/astute ' '/var/lib/fuel_upgrade/9999') remove_mock.assert_called_once_with( '/var/lib/fuel_upgrade/9999/astute') os_mock.mkdir.assert_called_once_with( '/var/lib/fuel_upgrade/9999/astute') @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=['1.json']) @mock.patch('fuel_upgrade.engines.docker_engine.utils.' 'check_file_is_valid_json') def test_verify_cobbler_configs(self, json_checker_mock, glob_mock): self.upgrader.verify_cobbler_configs() glob_mock.assert_called_once_with( '/var/lib/fuel_upgrade/9999/' 'cobbler_configs/config/systems.d/*.json') json_checker_mock.assert_called_once_with('1.json') @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=[]) def test_verify_cobbler_configs_raises_error_if_not_enough_systems( self, glob_mock): with self.assertRaises(errors.WrongCobblerConfigsError): self.upgrader.verify_cobbler_configs() self.called_once(glob_mock) @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=['1.json']) @mock.patch('fuel_upgrade.engines.docker_engine.utils.' 'check_file_is_valid_json', return_value=False) def test_verify_cobbler_configs_raises_error_if_invalid_file( self, json_checker_mock, glob_mock): with self.assertRaises(errors.WrongCobblerConfigsError): self.upgrader.verify_cobbler_configs() self.called_once(glob_mock) self.called_once(json_checker_mock) def test_get_docker_container_public_ports(self): docker_ports_mapping = [ {'Ports': [ {'PublicPort': 514}, {'PublicPort': 515}]}, {'Ports': [ {'PublicPort': 516}, {'PublicPort': 517}]}] self.assertEquals( [514, 515, 516, 517], self.upgrader._get_docker_container_public_ports( docker_ports_mapping)) @mock.patch('fuel_upgrade.engines.docker_engine.utils.safe_exec_cmd') def test_clean_iptables_rules(self, exec_cmd_mock): containers = [ {'id': 'astute', 'port_bindings': ['some_ports']}, {'id': 'some_volume_container'}, {'id': 'ostf', 'port_bindings': ['some_ports']}] for container in containers: with mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader._log_iptables') as log_mock: self.upgrader.clean_iptables_rules(container) self.called_times(log_mock, 2) self.assertEqual( exec_cmd_mock.call_args_list, [mock.call('dockerctl post_start_hooks astute'), mock.call('service iptables save'), mock.call('dockerctl post_start_hooks ostf'), mock.call('service iptables save')]) @mock.patch('fuel_upgrade.engines.docker_engine.utils.files_size', return_value=5) def test_required_free_space(self, _): self.assertEqual( self.upgrader.required_free_space, {'/var/lib/fuel_upgrade/9999': 150, '/var/lib/docker': 5, '/etc/fuel/': 10, '/etc/supervisord.d/': 10}) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_save_db_succeed(self, mock_utils): with mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.VersionedFile') as version_mock: version_mock.return_value.next_file_name.return_value = 'file3' version_mock.return_value.sorted_files.return_value = [ 'file3', 'file2', 'file1'] self.upgrader.save_db() self.called_once(mock_utils.wait_for_true) mock_utils.hardlink.assert_called_once_with( 'file3', '/var/lib/fuel_upgrade/9999/pg_dump_all.sql', overwrite=True) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_save_db_error_first_dump_is_invalid(self, mock_utils): with mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.VersionedFile') as version_mock: version_mock.return_value.filter_files.return_value = [] self.assertRaises(errors.DatabaseDumpError, self.upgrader.save_db) self.method_was_not_called(mock_utils.hardlink) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_save_db_removes_old_dump_files(self, mock_utils): mock_utils.file_exists.return_value = True with mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.VersionedFile') as version_mock: version_mock.return_value.sorted_files.return_value = [ 'file1', 'file2', 'file3', 'file4', 'file5'] self.upgrader.save_db() self.assertEqual( mock_utils.remove_if_exists.call_args_list, [mock.call('file4'), mock.call('file5')]) @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.exec_cmd_in_container') @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_make_pg_dump_succeed(self, mock_utils, exec_mock): self.assertTrue( self.upgrader.make_pg_dump('tmp_path', self.pg_dump_path)) self.method_was_not_called(mock_utils.file_exists) self.method_was_not_called(mock_utils.remove_if_exists) exec_mock.assert_called_once_with( 'fuel-core-0-postgres', "su postgres -c 'pg_dumpall --clean' > tmp_path") @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.exec_cmd_in_container', side_effect=errors.ExecutedErrorNonZeroExitCode()) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_make_pg_dump_error_failed_to_execute_dump_command( self, mock_utils, _): mock_utils.file_exists.return_value = False self.assertFalse( self.upgrader.make_pg_dump('tmp_path', self.pg_dump_path)) mock_utils.file_exists.assert_called_once_with(self.pg_dump_path) mock_utils.remove_if_exists.assert_called_once_with('tmp_path') @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.exec_cmd_in_container', side_effect=errors.CannotFindContainerError()) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_make_pg_dump_error_failed_because_of_stopped_container( self, mock_utils, exec_cmd_mock): mock_utils.file_exists.return_value = False self.assertFalse( self.upgrader.make_pg_dump('tmp_path', self.pg_dump_path)) mock_utils.file_exists.assert_called_once_with(self.pg_dump_path) mock_utils.remove_if_exists.assert_called_once_with('tmp_path') @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.exec_cmd_in_container', side_effect=errors.ExecutedErrorNonZeroExitCode()) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_make_pg_dump_second_run_failed_to_execute_dump_command( self, mock_utils, exec_cmd_mock): mock_utils.file_exists.return_value = True with mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.VersionedFile') as version_mock: version_mock.return_value.sorted_files.return_value = [ 'file1', 'file2'] self.assertTrue( self.upgrader.make_pg_dump('tmp_path', self.pg_dump_path)) mock_utils.file_exists.assert_called_once_with(self.pg_dump_path) self.called_once(mock_utils.remove_if_exists) @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.exec_cmd_in_container', side_effect=errors.CannotFindContainerError()) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_make_pg_dump_second_run_failed_because_of_stopped_container( self, mock_utils, _): mock_utils.file_exists.return_value = True with mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.VersionedFile') as version_mock: version_mock.return_value.sorted_files.return_value = ['file1'] self.assertTrue( self.upgrader.make_pg_dump('tmp_path', self.pg_dump_path))
class TestUtils(BaseTestCase): def make_process_mock(self, return_code=0): process_mock = mock.Mock() process_mock.stdout = ['Stdout line 1', 'Stdout line 2'] process_mock.returncode = return_code return process_mock def test_exec_cmd_executes_sucessfuly(self): cmd = 'some command' process_mock = self.make_process_mock() with patch.object(subprocess, 'Popen', return_value=process_mock) as popen_mock: exec_cmd(cmd) popen_mock.assert_called_once_with(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) @mock.patch('fuel_upgrade.utils.exec_cmd', side_effect=errors.ExecutedErrorNonZeroExitCode()) def test_safe_exec_cmd(self, exec_mock): cmd = 'some command' utils.safe_exec_cmd(cmd) exec_mock.assert_called_once_with(cmd) def test_exec_cmd_raises_error_in_case_of_non_zero_exit_code(self): cmd = 'some command' return_code = 1 process_mock = self.make_process_mock(return_code=return_code) with patch.object(subprocess, 'Popen', return_value=process_mock): self.assertRaisesRegexp( errors.ExecutedErrorNonZeroExitCode, 'Shell command executed with "{0}" ' 'exit code: {1} '.format(return_code, cmd), exec_cmd, cmd) def test_exec_cmd_iterator_executes_sucessfuly(self): cmd = 'some command' process_mock = self.make_process_mock() with patch.object(subprocess, 'Popen', return_value=process_mock) as popen_mock: for line in exec_cmd_iterator(cmd): self.assertTrue(line.startswith('Stdout line ')) popen_mock.assert_called_once_with(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) def test_exec_cmd_iterator_raises_error_in_case_of_non_zero_exit_code( self): cmd = 'some command' return_code = 1 process_mock = self.make_process_mock(return_code=return_code) with patch.object(subprocess, 'Popen', return_value=process_mock): with self.assertRaisesRegexp( errors.ExecutedErrorNonZeroExitCode, 'Shell command executed with "{0}" ' 'exit code: {1} '.format(return_code, cmd)): for line in exec_cmd_iterator(cmd): self.assertTrue(line.startswith('Stdout line ')) def test_get_request(self): url = 'http://some-url.com/path' response = mock.MagicMock() response.read.return_value = '{"key": "value"}' response.getcode.return_value = 200 with patch.object(urllib2, 'urlopen', return_value=response) as urlopen: resp = get_request(url) self.assertEqual(({'key': 'value'}, 200), resp) urlopen.assert_called_once_with(url) def test_topological_sorting(self): graph = { 'D': ['C', 'G'], 'E': ['A', 'D'], 'A': [], 'B': ['A'], 'C': ['A'], 'G': [] } order = topological_sorting(graph) self.assertEqual(order, ['A', 'B', 'C', 'G', 'D', 'E']) def test_topological_sorting_raises_cycle_dependencies_error(self): graph = {'A': ['C', 'D'], 'B': ['A'], 'C': ['B'], 'D': []} self.assertRaisesRegexp(errors.CyclicDependenciesError, "Cyclic dependencies error ", topological_sorting, graph) @mock.patch('fuel_upgrade.utils.os.makedirs') def test_create_dir_if_not_exists_does_not_create_dir(self, mock_makedirs): path = 'some_path' with mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=True) as mock_isdir: create_dir_if_not_exists(path) mock_isdir.assert_called_once_with(path) self.method_was_not_called(mock_makedirs) @mock.patch('fuel_upgrade.utils.os.makedirs') def test_create_dir_if_not_exists(self, mock_makedirs): path = 'some_path' with mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=False) as mock_isdir: create_dir_if_not_exists(path) mock_isdir.assert_called_once_with(path) mock_makedirs.assert_called_once_with(path) def test_wait_for_true_does_not_raise_errors(self): self.assertEqual(wait_for_true(lambda: True, timeout=0), True) def test_wait_for_true_raises_timeout_error(self): self.assertRaisesRegexp(errors.TimeoutError, 'Failed to execute command with timeout 0', wait_for_true, lambda: False, timeout=0) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=True) @mock.patch('fuel_upgrade.utils.copy_dir') def test_copy_with_dir(self, copy_mock, _): from_path = '/from_path' to_path = '/to_path' utils.copy(from_path, to_path) copy_mock.assert_called_once_with(from_path, to_path, True, True) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=False) @mock.patch('fuel_upgrade.utils.copy_file') def test_copy_with_file(self, copy_mock, _): from_path = '/from_path' to_path = '/to_path' utils.copy(from_path, to_path) copy_mock.assert_called_once_with(from_path, to_path, True) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=False) @mock.patch('fuel_upgrade.utils.shutil.copy') def test_copy_file(self, copy_mock, _): from_path = '/from_path.txt' to_path = '/to_path.txt' utils.copy_file(from_path, to_path) copy_mock.assert_called_once_with(from_path, to_path) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=True) @mock.patch('fuel_upgrade.utils.shutil.copy') def test_copy_file_to_dir(self, copy_mock, _): from_path = '/from_path.txt' to_path = '/to_path' utils.copy_file(from_path, to_path) copy_mock.assert_called_once_with(from_path, '/to_path/from_path.txt') @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=False) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.shutil.copy') def test_copy_file_do_not_overwrite(self, copy_mock, _, __): from_path = '/from_path.txt' to_path = '/to_path.txt' utils.copy_file(from_path, to_path, overwrite=False) self.method_was_not_called(copy_mock) @mock.patch('fuel_upgrade.utils.shutil.copytree') def test_copy_dir(self, copy_mock): from_path = '/from_path' to_path = '/to_path' utils.copy_dir(from_path, to_path) copy_mock.assert_called_once_with(from_path, to_path, symlinks=True) @mock.patch('fuel_upgrade.utils.os.path.lexists', return_value=True) @mock.patch('fuel_upgrade.utils.shutil.copytree') @mock.patch('fuel_upgrade.utils.remove') def test_copy_dir_overwrite(self, rm_mock, copy_mock, _): from_path = '/from_path' to_path = '/to_path' utils.copy_dir(from_path, to_path) rm_mock.assert_called_once_with(to_path, ignore_errors=True) copy_mock.assert_called_once_with(from_path, to_path, symlinks=True) def test_file_contains_lines_returns_true(self): with mock.patch('__builtin__.open', self.mock_open("line 1\n line2\n line3")): self.assertTrue( utils.file_contains_lines('/some/path', ['line 1', 'line3'])) def test_file_contains_lines_returns_false(self): with mock.patch('__builtin__.open', self.mock_open("line 1\n line2\n line3")): self.assertFalse( utils.file_contains_lines('/some/path', ['line 4', 'line3'])) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.os.symlink') @mock.patch('fuel_upgrade.utils.remove') def test_symlink(self, remove_mock, symlink_mock, _): from_path = '/tmp/from/path' to_path = '/tmp/to/path' utils.symlink(from_path, to_path) symlink_mock.assert_called_once_with(from_path, to_path) remove_mock.assert_called_once_with(to_path) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=False) @mock.patch('fuel_upgrade.utils.os.symlink') @mock.patch('fuel_upgrade.utils.remove') def test_symlink_no_exist(self, remove_mock, symlink_mock, _): from_path = '/tmp/from/path' to_path = '/tmp/to/path' utils.symlink(from_path, to_path) symlink_mock.assert_called_once_with(from_path, to_path) self.called_once(remove_mock) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.os.remove') def test_remove_if_exists(self, remove_mock, exists_mock): path = '/tmp/some/path' utils.remove_if_exists(path) remove_mock.assert_called_once_with(path) exists_mock.assert_called_once_with(path) def test_load_fixture(self): fixture = StringIO.StringIO(''' - &base fields: a: 1 b: 2 c: 3 - pk: 1 extend: *base fields: a: 13 - pk: 2 extend: *base fields: d: 42 ''') setattr(fixture, 'name', 'some.yaml') result = utils.load_fixture(fixture) self.assertEqual(len(result), 2) self.assertEqual(result[0], { 'a': 13, 'b': 2, 'c': 3, }) self.assertEqual(result[1], { 'a': 1, 'b': 2, 'c': 3, 'd': 42, }) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.shutil.rmtree') def test_rmtree(self, rm_mock, exists_mock): path = '/some/file/path' utils.rmtree(path) rm_mock.assert_called_once_with(path, ignore_errors=True) exists_mock.assert_called_once_with(path) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=False) @mock.patch('fuel_upgrade.utils.shutil.rmtree') def test_rmtree_no_errors_if_file_does_not_exist(self, rm_mock, exists_mock): path = '/some/file/path' utils.rmtree(path) self.method_was_not_called(rm_mock) exists_mock.assert_called_once_with(path) def test_check_file_is_valid_json(self): path = '/path/to/file.json' with mock.patch('__builtin__.open', self.mock_open('{"valid": "json"}')): self.assertTrue(utils.check_file_is_valid_json(path)) def test_check_file_is_valid_json_returns_false(self): path = '/path/to/file.json' with mock.patch('__builtin__.open', self.mock_open('{"invalid: "json"}')): self.assertFalse(utils.check_file_is_valid_json(path)) def test_check_file_is_valid_json_false_if_problems_with_access(self): path = '/path/to/file.json' with mock.patch('__builtin__.open', side_effect=IOError()): self.assertFalse(utils.check_file_is_valid_json(path)) def test_byte_to_megabyte(self): self.assertEqual(utils.byte_to_megabyte(0), 0) self.assertEqual(utils.byte_to_megabyte(1048576), 1) def test_calculate_free_space(self): dev_info = mock.Mock() dev_info.f_bsize = 1048576 dev_info.f_bavail = 2 with mock.patch('fuel_upgrade.utils.os.statvfs', return_value=dev_info) as st_mock: self.assertEqual(utils.calculate_free_space('/tmp/dir'), 2) st_mock.assert_called_once_with('/tmp/dir/') @mock.patch('fuel_upgrade.utils.os.path.ismount', side_effect=[False, False, True]) def test_find_mount_point(self, mock_ismount): path = '/dir1/dir2/dir3/dir4' self.assertEqual(utils.find_mount_point(path), '/dir1/dir2') self.called_times(mock_ismount, 3) @mock.patch('fuel_upgrade.utils.os.path.getsize', return_value=1048576) @mock.patch('fuel_upgrade.utils.os.walk', return_value=[('', '', ['file1', 'file2'])]) @mock.patch('fuel_upgrade.utils.os.path.isfile', return_value=True) def test_dir_size(self, _, __, ___): path = '/path/dir' self.assertEqual(utils.dir_size(path), 2) @mock.patch('fuel_upgrade.utils.os.path.getsize', return_value=1048576) @mock.patch('fuel_upgrade.utils.os.path.isfile', return_value=True) def test_files_size(self, _, __): path = ['/path/file1', '/path/file2'] self.assertEqual(utils.files_size(path), 2) def test_compare_version(self): self.assertEqual(utils.compare_version('0.1', '0.2'), 1) self.assertEqual(utils.compare_version('0.1', '0.1.5'), 1) self.assertEqual(utils.compare_version('0.2', '0.1'), -1) self.assertEqual(utils.compare_version('0.2', '0.2'), 0) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.copy') def test_copy_if_does_not_exist_file_exists(self, copy_mock, exists_mock): utils.copy_if_does_not_exist('from', 'to') exists_mock.assert_called_once_with('to') self.method_was_not_called(copy_mock) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=False) @mock.patch('fuel_upgrade.utils.copy') def test_copy_if_does_not_exist_file_does_not_exist( self, copy_mock, exists_mock): utils.copy_if_does_not_exist('from', 'to') exists_mock.assert_called_once_with('to') copy_mock.assert_called_once_with('from', 'to') @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=False) @mock.patch('fuel_upgrade.utils.copy') def test_copy_if_exists_file_does_not_exist(self, copy_mock, exists_mock): utils.copy_if_exists('from', 'to') exists_mock.assert_called_once_with('from') self.method_was_not_called(copy_mock) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.copy') def test_copy_if_exists_file_exists(self, copy_mock, exists_mock): utils.copy_if_exists('from', 'to') exists_mock.assert_called_once_with('from') copy_mock.assert_called_once_with('from', 'to') @mock.patch('fuel_upgrade.utils.os.rename') def test_rename(self, rename_mock): utils.rename('source', 'destination') rename_mock.assert_called_once_with('source', 'destination') @mock.patch('fuel_upgrade.utils.os.path.lexists', return_value=True) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=False) @mock.patch('fuel_upgrade.utils.os.remove') def test_remove_file(self, remove_mock, _, __): utils.remove('path') remove_mock.assert_called_once_with('path') @mock.patch('fuel_upgrade.utils.os.path.lexists', return_value=True) @mock.patch('fuel_upgrade.utils.os.path.islink', return_value=True) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=True) @mock.patch('fuel_upgrade.utils.os.remove') def test_remove_link_to_dir(self, remove_mock, _, __, ___): utils.remove('path') remove_mock.assert_called_once_with('path') @mock.patch('fuel_upgrade.utils.os.path.lexists', return_value=False) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=False) @mock.patch('fuel_upgrade.utils.os.remove') def test_remove_file_does_not_exist(self, remove_mock, _, __): utils.remove('path') self.method_was_not_called(remove_mock) @mock.patch('fuel_upgrade.utils.os.path.lexists', return_value=True) @mock.patch('fuel_upgrade.utils.os.path.isdir', return_value=True) @mock.patch('fuel_upgrade.utils.shutil.rmtree') def test_remove_dir(self, remove_mock, _, __): utils.remove('path') remove_mock.assert_called_once_with('path', ignore_errors=True) @mock.patch('fuel_upgrade.utils.yaml') def test_save_as_yaml(self, yaml_mock): path = '/tmp/path' data = {'a': 'b'} mock_open = self.mock_open('') with mock.patch('__builtin__.open', mock_open): utils.save_as_yaml(path, data) yaml_mock.dump.assert_called_once_with(data, default_flow_style=False) def test_generate_uuid_string(self): random_string = utils.generate_uuid_string() self.assertEqual(len(random_string), 36) self.assertTrue(isinstance(random_string, str)) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.utils.file_contains_lines', returns_value=True) def test_verify_postgres_dump(self, file_contains_mock, exists_mock): pg_dump_path = '/tmp/some/path' utils.verify_postgres_dump(pg_dump_path) patterns = [ '-- PostgreSQL database cluster dump', '-- PostgreSQL database dump', '-- PostgreSQL database dump complete', '-- PostgreSQL database cluster dump complete' ] exists_mock.assert_called_once_with(pg_dump_path) file_contains_mock.assert_called_once_with(pg_dump_path, patterns) def test_file_extension(self): cases = [('', ''), ('asdf', ''), ('asdf.', ''), ('asdf.txt', 'txt'), ('asdf.txt.trtr', 'trtr')] for case in cases: self.assertEqual(utils.file_extension(case[0]), case[1]) @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=True) def test_file_exists_returns_true(self, exists_mock): self.assertTrue(utils.file_exists('path')) exists_mock.assert_called_once_with('path') @mock.patch('fuel_upgrade.utils.os.path.exists', return_value=False) def test_file_exists_returns_false(self, exists_mock): self.assertFalse(utils.file_exists('path')) exists_mock.assert_called_once_with('path') @mock.patch('fuel_upgrade.utils.os.walk') def test_iterfiles(self, walk): for _ in utils.iterfiles('path/to/dir'): pass walk.assert_called_once_with('path/to/dir', topdown=True)
class TestDockerUpgrader(BaseTestCase): def setUp(self): # NOTE (eli): mocking doesn't work correctly # when we try to patch docker client with # class decorator, it's the reason why # we have to do it explicitly self.docker_patcher = mock.patch( 'fuel_upgrade.engines.docker_engine.docker.Client') self.docker_mock_class = self.docker_patcher.start() self.docker_mock = mock.MagicMock() self.docker_mock_class.return_value = self.docker_mock self.supervisor_patcher = mock.patch( 'fuel_upgrade.engines.docker_engine.SupervisorClient') self.supervisor_class = self.supervisor_patcher.start() self.supervisor_mock = mock.MagicMock() self.supervisor_class.return_value = self.supervisor_mock with mock.patch('fuel_upgrade.engines.docker_engine.utils'): self.upgrader = DockerUpgrader(self.fake_config) self.upgrader.upgrade_verifier = mock.MagicMock() def tearDown(self): self.docker_patcher.stop() self.supervisor_patcher.stop() def mock_methods(self, obj, methods): for method in methods: setattr(obj, method, mock.MagicMock()) def test_upgrade(self): mocked_methods = [ 'stop_fuel_containers', 'save_db', 'save_cobbler_configs', 'save_astute_keys', 'upload_images', 'create_containers', 'generate_configs', 'switch_to_new_configs', 'switch_version_to_new' ] self.mock_methods(self.upgrader, mocked_methods) self.upgrader.upgrade() # Check that all methods was called once # except stop_fuel_containers method for method in mocked_methods[1:-1]: self.called_once(getattr(self.upgrader, method)) self.called_times(self.upgrader.stop_fuel_containers, 3) self.called_once(self.supervisor_mock.stop_all_services) self.called_once(self.supervisor_mock.restart_and_wait) self.called_once(self.upgrader.upgrade_verifier.verify) def test_rollback(self): self.upgrader.stop_fuel_containers = mock.MagicMock() self.upgrader.switch_version_file_to_previous_version = \ mock.MagicMock() self.upgrader.rollback() self.called_times(self.upgrader.stop_fuel_containers, 1) self.called_once(self.supervisor_mock.switch_to_previous_configs) self.called_once(self.supervisor_mock.stop_all_services) self.called_once(self.supervisor_mock.restart_and_wait) self.called_once(self.upgrader.switch_version_file_to_previous_version) @mock.patch('fuel_upgrade.engines.docker_engine.utils.symlink') def test_switch_version_file_to_previous_version(self, symlink_mock): self.upgrader.switch_version_file_to_previous_version() symlink_mock.assert_called_once_with('/etc/fuel/0/version.yaml', '/etc/fuel/version.yaml') @mock.patch('fuel_upgrade.engines.docker_engine.utils') @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=['file1', 'file2']) def test_on_success(self, glob_mock, utils_mock): self.upgrader.on_success() glob_mock.assert_called_once_with(self.fake_config.version_files_mask) self.assertEqual(utils_mock.remove.call_args_list, [(('file1', ), ), (('file2', ), )]) def test_stop_fuel_containers(self): non_fuel_images = [ 'first_image_1.0', 'second_image_2.0', 'third_image_2.0' ] fuel_images = ['fuel/image_1.0', 'fuel/image_2.0'] all_images = [{ 'Image': v, 'Id': i } for i, v in enumerate(non_fuel_images + fuel_images)] ports = [1, 2, 3] self.upgrader._get_docker_container_public_ports = mock.MagicMock( return_value=ports) self.upgrader.clean_docker_iptables_rules = mock.MagicMock() self.docker_mock.containers.return_value = all_images self.upgrader.stop_fuel_containers() self.assertEqual(self.docker_mock.stop.call_args_list, [((3, 10), ), ((4, 10), )]) self.upgrader.clean_docker_iptables_rules.assert_called_once_with( ports) @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd') @mock.patch('fuel_upgrade.engines.docker_engine.os.path.exists', return_value=True) def test_upload_images(self, _, exec_mock): self.upgrader.new_release_images = [{ 'docker_image': 'image1' }, { 'docker_image': 'image2' }] self.upgrader.upload_images() self.assertEqual(exec_mock.call_args_list, [(('docker load < "image1"', ), ), (('docker load < "image2"', ), )]) def test_create_containers(self): self.upgrader.new_release_containers = [{ 'id': 'id1', 'container_name': 'name1', 'image_name': 'i_name1', 'volumes_from': ['id2'] }, { 'id': 'id2', 'image_name': 'i_name2', 'container_name': 'name2', 'after_container_creation_command': 'cmd' }] def mocked_create_container(*args, **kwargs): """Return name of the container """ return kwargs['name'] self.upgrader.create_container = mock.MagicMock( side_effect=mocked_create_container) self.upgrader.start_container = mock.MagicMock() self.upgrader.run_after_container_creation_command = mock.MagicMock() self.upgrader.create_containers() create_container_calls = [(('i_name2', ), { 'detach': False, 'ports': None, 'volumes': None, 'name': 'name2' }), (('i_name1', ), { 'detach': False, 'ports': None, 'volumes': None, 'name': 'name1' })] start_container_calls = [(('name2', ), { 'volumes_from': [], 'binds': None, 'port_bindings': None, 'privileged': False, 'links': [] }), (('name1', ), { 'volumes_from': ['name2'], 'binds': None, 'port_bindings': None, 'privileged': False, 'links': [] })] self.assertEqual(self.upgrader.create_container.call_args_list, create_container_calls) self.assertEqual(self.upgrader.start_container.call_args_list, start_container_calls) self.called_once(self.upgrader.run_after_container_creation_command) def test_run_after_container_creation_command(self): self.upgrader.exec_with_retries = mock.MagicMock() self.upgrader.run_after_container_creation_command({ 'after_container_creation_command': 'cmd', 'container_name': 'name' }) self.called_once(self.upgrader.exec_with_retries) def test_create_container(self): self.upgrader.create_container('image_name', param1=1, param2=2, ports=[1234]) self.docker_mock.create_container.assert_called_once_with('image_name', param2=2, param1=1, ports=[1234]) def test_start_container(self): self.upgrader.start_container({'Id': 'container_id'}, param1=1, param2=2) self.docker_mock.start.assert_called_once_with('container_id', param2=2, param1=1) def test_build_dependencies_graph(self): containers = [{ 'id': '1', 'volumes_from': ['2'], 'links': [{ 'id': '3' }] }, { 'id': '2', 'volumes_from': [], 'links': [] }, { 'id': '3', 'volumes_from': [], 'links': [{ 'id': '2' }] }] actual_graph = self.upgrader.build_dependencies_graph(containers) expected_graph = {'1': ['2', '3'], '2': [], '3': ['2']} self.assertEqual(actual_graph, expected_graph) def test_get_container_links(self): fake_containers = [{ 'id': 'id1', 'container_name': 'container_name1', 'links': [{ 'id': 'id2', 'alias': 'alias2' }] }, { 'id': 'id2', 'container_name': 'container_name2' }] self.upgrader.new_release_containers = fake_containers links = self.upgrader.get_container_links(fake_containers[0]) self.assertEqual(links, [('container_name2', 'alias2')]) def test_get_port_bindings(self): port_bindings = {'port_bindings': {'53/udp': ['0.0.0.0', 53]}} bindings = self.upgrader.get_port_bindings(port_bindings) self.assertEqual({'53/udp': ('0.0.0.0', 53)}, bindings) def test_get_ports(self): ports = self.upgrader.get_ports({'ports': [[53, 'udp'], 100]}) self.assertEqual([(53, 'udp'), 100], ports) def test_generate_configs(self): fake_containers = [{ 'id': 'id1', 'container_name': 'container_name1', 'supervisor_config': False }, { 'id': 'id2', 'container_name': 'container_name2', 'supervisor_config': True }, { 'id': 'cobbler', 'container_name': 'cobbler_container', 'supervisor_config': False }] self.upgrader.new_release_containers = fake_containers self.upgrader.generate_configs() self.supervisor_mock.generate_configs.assert_called_once_with([{ 'service_name': 'id2', 'command': 'docker start -a container_name2' }]) self.supervisor_mock.generate_cobbler_config.assert_called_once_with({ 'service_name': 'cobbler', 'container_name': 'cobbler_container' }) def test_switch_to_new_configs(self): self.upgrader.switch_to_new_configs() self.supervisor_mock.switch_to_new_configs.called_once() @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd') def test_exec_cmd_in_container(self, exec_cmd_mock): name = 'container_name' cmd = 'some command' self.upgrader.container_docker_id = mock.MagicMock(return_value=name) self.upgrader.exec_cmd_in_container(name, cmd) self.called_once(self.upgrader.container_docker_id) exec_cmd_mock.assert_called_once_with( "lxc-attach --name {0} -- {1}".format(name, cmd)) @mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.exec_cmd') @mock.patch('fuel_upgrade.engines.docker_engine.' 'DockerUpgrader.verify_cobbler_configs') def test_save_cobbler_configs(self, verify_mock, exec_cmd_mock): self.upgrader.save_cobbler_configs() exec_cmd_mock.assert_called_once_with( 'docker cp fuel-core-0-cobbler:/var/lib/cobbler/config ' '/var/lib/fuel_upgrade/9999/cobbler_configs') self.called_once(verify_mock) @mock.patch('fuel_upgrade.engines.docker_engine.utils.rmtree') @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd', side_effect=errors.ExecutedErrorNonZeroExitCode()) def test_save_cobbler_configs_removes_dir_in_case_of_error( self, exec_cmd_mock, rm_mock): with self.assertRaises(errors.ExecutedErrorNonZeroExitCode): self.upgrader.save_cobbler_configs() cobbler_config_path = '/var/lib/fuel_upgrade/9999/cobbler_configs' exec_cmd_mock.assert_called_once_with( 'docker cp fuel-core-0-cobbler:/var/lib/cobbler/config ' '{0}'.format(cobbler_config_path)) rm_mock.assert_called_once_with(cobbler_config_path) @mock.patch('fuel_upgrade.engines.docker_engine.' 'utils.exec_cmd') def test_save_astute_keys(self, exec_cmd_mock): self.upgrader.save_astute_keys() exec_cmd_mock.assert_called_once_with( 'docker cp fuel-core-0-astute:/var/lib/astute ' '/var/lib/fuel_upgrade/9999') self.called_once(exec_cmd_mock) @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=['1.json']) @mock.patch('fuel_upgrade.engines.docker_engine.utils.' 'check_file_is_valid_json') def test_verify_cobbler_configs(self, json_checker_mock, glob_mock): self.upgrader.verify_cobbler_configs() glob_mock.assert_called_once_with( '/var/lib/fuel_upgrade/9999/' 'cobbler_configs/config/systems.d/*.json') json_checker_mock.assert_called_once_with('1.json') @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=[]) def test_verify_cobbler_configs_raises_error_if_not_enough_systems( self, glob_mock): with self.assertRaises(errors.WrongCobblerConfigsError): self.upgrader.verify_cobbler_configs() self.called_once(glob_mock) @mock.patch('fuel_upgrade.engines.docker_engine.glob.glob', return_value=['1.json']) @mock.patch('fuel_upgrade.engines.docker_engine.utils.' 'check_file_is_valid_json', return_value=False) def test_verify_cobbler_configs_raises_error_if_invalid_file( self, json_checker_mock, glob_mock): with self.assertRaises(errors.WrongCobblerConfigsError): self.upgrader.verify_cobbler_configs() self.called_once(glob_mock) self.called_once(json_checker_mock) def test_save_db(self): self.upgrader.verify_postgres_dump = mock.MagicMock(return_value=True) self.upgrader.exec_cmd_in_container = mock.MagicMock() self.upgrader.save_db() def test_save_db_failed_verification(self): self.upgrader.verify_postgres_dump = mock.MagicMock(return_value=False) self.upgrader.exec_cmd_in_container = mock.MagicMock() self.assertRaises(errors.DatabaseDumpError, self.upgrader.save_db) @mock.patch('fuel_upgrade.engines.docker_engine.utils.file_contains_lines', returns_value=True) @mock.patch('fuel_upgrade.engines.docker_engine.os.path.exists', side_effect=[False, True]) @mock.patch('fuel_upgrade.engines.docker_engine.os.remove') def test_save_db_removes_file_in_case_of_error(self, remove_mock, _, __): self.upgrader.exec_cmd_in_container = mock.MagicMock( side_effect=errors.ExecutedErrorNonZeroExitCode()) self.assertRaises(errors.ExecutedErrorNonZeroExitCode, self.upgrader.save_db) self.called_once(remove_mock) @mock.patch('fuel_upgrade.engines.docker_engine.os.path.exists', return_value=True) @mock.patch('fuel_upgrade.engines.docker_engine.utils.file_contains_lines', returns_value=True) def test_verify_postgres_dump(self, file_contains_mock, exists_mock): self.upgrader.verify_postgres_dump() patterns = [ '-- PostgreSQL database cluster dump', '-- PostgreSQL database dump', '-- PostgreSQL database dump complete', '-- PostgreSQL database cluster dump complete' ] exists_mock.assert_called_once_with(self.upgrader.pg_dump_path) file_contains_mock.assert_called_once_with(self.upgrader.pg_dump_path, patterns) def test_get_docker_container_public_ports(self): docker_ports_mapping = [{ 'Ports': [{ 'PublicPort': 514 }, { 'PublicPort': 515 }] }, { 'Ports': [{ 'PublicPort': 516 }, { 'PublicPort': 517 }] }] self.assertEquals([514, 515, 516, 517], self.upgrader._get_docker_container_public_ports( docker_ports_mapping)) @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd') @mock.patch('fuel_upgrade.engines.docker_engine.utils.exec_cmd_iterator') def test_clean_docker_iptables_rules(self, exec_cmd_iterator_mock, exec_cmd_mock): iptables_rules = [ '-A DOCKER -p tcp -m tcp --dport 1 -j DNAT ' '--to-destination 172.17.0.7:1', '-A POSTROUTING -p tcp -m tcp --dport 3 -j DNAT ' '--to-destination 172.17.0.7:3', '-A DOCKER -p tcp -m tcp --dport 2 -j DNAT ' '--to-destination 172.17.0.3:2' ] exec_cmd_iterator_mock.return_value = iter(iptables_rules) self.upgrader.clean_docker_iptables_rules([1, 2, 3]) expected_calls = [ (('iptables -t nat -D DOCKER -p tcp -m tcp --dport 1 -j DNAT ' '--to-destination 172.17.0.7:1', ), ), (('iptables -t nat -D DOCKER -p tcp -m tcp --dport 2 -j DNAT ' '--to-destination 172.17.0.3:2', ), ) ] self.assertEquals(exec_cmd_mock.call_args_list, expected_calls) @mock.patch('fuel_upgrade.engines.docker_engine.utils.files_size', return_value=5) def test_required_free_space(self, _): self.assertEqual( self.upgrader.required_free_space, { '/var/lib/fuel_upgrade/9999': 50, '/var/lib/docker': 5, '/etc/fuel/': 10, '/etc/supervisord.d/': 10 }) @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_save_current_version_file(self, mock_utils): self.upgrader.save_current_version_file() mock_utils.copy_if_does_not_exist.assert_called_once_with( '/etc/fuel/version.yaml', '/var/lib/fuel_upgrade/9999/version.yaml') @mock.patch('fuel_upgrade.engines.docker_engine.utils') def test_switch_version_to_new(self, mock_utils): self.upgrader.switch_version_to_new() mock_utils.create_dir_if_not_exists.assert_called_once_with( '/etc/fuel/9999') mock_utils.copy.assert_called_once_with( '/tmp/upgrade_path/config/version.yaml', '/etc/fuel/9999/version.yaml') mock_utils.symlink.assert_called_once_with( '/etc/fuel/9999/version.yaml', '/etc/fuel/version.yaml')