# -*- coding: utf-8 -*- ''' :codeauthor: Alexander Schwartz ''' # Import python libs from __future__ import absolute_import, print_function, unicode_literals import os # Import Salt Testing libs from tests.support.mixins import LoaderModuleMockMixin from tests.support.unit import TestCase, skipIf from tests.support.mock import ( NO_MOCK, NO_MOCK_REASON, MagicMock, patch ) # Import Salt Libs import salt.states.archive as archive from salt.ext.six.moves import zip # pylint: disable=import-error,redefined-builtin import salt.utils.platform def _isfile_side_effect(path): ''' MagicMock side_effect for os.path.isfile(). We don't want to use dict.get here because we want the test to fail if there's a path we haven't accounted for, so that we can add it. NOTE: This may fall over on some platforms if /usr/bin/tar does not exist. If so, just add an entry in the dictionary for the path being used for tar. ''' return { '/tmp/foo.tar.gz': True, 'c:\\tmp\\foo.tar.gz': True, '/private/tmp/foo.tar.gz': True, '/tmp/out': False, '\\tmp\\out': False, '/usr/bin/tar': True, '/bin/tar': True, '/tmp/test_extracted_tar': False, 'c:\\tmp\\test_extracted_tar': False, '/private/tmp/test_extracted_tar': False, }[path] @skipIf(NO_MOCK, NO_MOCK_REASON) class ArchiveTestCase(TestCase, LoaderModuleMockMixin): def setup_loader_modules(self): return { archive: { '__grains__': {'os': 'FooOS!'}, '__opts__': {'cachedir': '/tmp', 'test': False, 'hash_type': 'sha256'}, '__env__': 'test' } } def test_extracted_tar(self): ''' archive.extracted tar options ''' if salt.utils.platform.is_windows(): source = 'c:\\tmp\\foo.tar.gz' tmp_dir = 'c:\\tmp\\test_extracted_tar' elif salt.utils.platform.is_darwin(): source = '/private/tmp/foo.tar.gz' tmp_dir = '/private/tmp/test_extracted_tar' else: source = '/tmp/foo.tar.gz' tmp_dir = '/tmp/test_extracted_tar' test_tar_opts = [ '--no-anchored foo', 'v -p --opt', '-v -p', '--long-opt -z', 'z -v -weird-long-opt arg', ] ret_tar_opts = [ ['tar', 'x', '--no-anchored', 'foo', '-f'], ['tar', 'xv', '-p', '--opt', '-f'], ['tar', 'x', '-v', '-p', '-f'], ['tar', 'x', '--long-opt', '-z', '-f'], ['tar', 'xz', '-v', '-weird-long-opt', 'arg', '-f'], ] mock_true = MagicMock(return_value=True) mock_false = MagicMock(return_value=False) ret = {'stdout': ['cheese', 'ham', 'saltines'], 'stderr': 'biscuits', 'retcode': '31337', 'pid': '1337'} mock_run = MagicMock(return_value=ret) mock_source_list = MagicMock(return_value=(source, None)) state_single_mock = MagicMock(return_value={'local': {'result': True}}) list_mock = MagicMock(return_value={ 'dirs': [], 'files': ['cheese', 'saltines'], 'links': ['ham'], 'top_level_dirs': [], 'top_level_files': ['cheese', 'saltines'], 'top_level_links': ['ham'], }) isfile_mock = MagicMock(side_effect=_isfile_side_effect) with patch.dict(archive.__opts__, {'test': False, 'cachedir': tmp_dir, 'hash_type': 'sha256'}),\ patch.dict(archive.__salt__, {'file.directory_exists': mock_false, 'file.file_exists': mock_false, 'state.single': state_single_mock, 'file.makedirs': mock_true, 'cmd.run_all': mock_run, 'archive.list': list_mock, 'file.source_list': mock_source_list}),\ patch.dict(archive.__states__, {'file.directory': mock_true}),\ patch.object(os.path, 'isfile', isfile_mock),\ patch('salt.utils.path.which', MagicMock(return_value=True)): for test_opts, ret_opts in zip(test_tar_opts, ret_tar_opts): archive.extracted(tmp_dir, source, options=test_opts, enforce_toplevel=False) ret_opts.append(source) mock_run.assert_called_with(ret_opts, cwd=tmp_dir + os.sep, python_shell=False) def test_tar_gnutar(self): ''' Tests the call of extraction with gnutar ''' gnutar = MagicMock(return_value='tar (GNU tar)') source = '/tmp/foo.tar.gz' mock_false = MagicMock(return_value=False) mock_true = MagicMock(return_value=True) state_single_mock = MagicMock(return_value={'local': {'result': True}}) run_all = MagicMock(return_value={'retcode': 0, 'stdout': 'stdout', 'stderr': 'stderr'}) mock_source_list = MagicMock(return_value=(source, None)) list_mock = MagicMock(return_value={ 'dirs': [], 'files': ['stdout'], 'links': [], 'top_level_dirs': [], 'top_level_files': ['stdout'], 'top_level_links': [], }) isfile_mock = MagicMock(side_effect=_isfile_side_effect) with patch.dict(archive.__salt__, {'cmd.run': gnutar, 'file.directory_exists': mock_false, 'file.file_exists': mock_false, 'state.single': state_single_mock, 'file.makedirs': mock_true, 'cmd.run_all': run_all, 'archive.list': list_mock, 'file.source_list': mock_source_list}),\ patch.dict(archive.__states__, {'file.directory': mock_true}),\ patch.object(os.path, 'isfile', isfile_mock),\ patch('salt.utils.path.which', MagicMock(return_value=True)): ret = archive.extracted(os.path.join(os.sep + 'tmp', 'out'), source, options='xvzf', enforce_toplevel=False, keep=True) self.assertEqual(ret['changes']['extracted_files'], 'stdout') def test_tar_bsdtar(self): ''' Tests the call of extraction with bsdtar ''' bsdtar = MagicMock(return_value='tar (bsdtar)') source = '/tmp/foo.tar.gz' mock_false = MagicMock(return_value=False) mock_true = MagicMock(return_value=True) state_single_mock = MagicMock(return_value={'local': {'result': True}}) run_all = MagicMock(return_value={'retcode': 0, 'stdout': 'stdout', 'stderr': 'stderr'}) mock_source_list = MagicMock(return_value=(source, None)) list_mock = MagicMock(return_value={ 'dirs': [], 'files': ['stderr'], 'links': [], 'top_level_dirs': [], 'top_level_files': ['stderr'], 'top_level_links': [], }) isfile_mock = MagicMock(side_effect=_isfile_side_effect) with patch.dict(archive.__salt__, {'cmd.run': bsdtar, 'file.directory_exists': mock_false, 'file.file_exists': mock_false, 'state.single': state_single_mock, 'file.makedirs': mock_true, 'cmd.run_all': run_all, 'archive.list': list_mock, 'file.source_list': mock_source_list}),\ patch.dict(archive.__states__, {'file.directory': mock_true}),\ patch.object(os.path, 'isfile', isfile_mock),\ patch('salt.utils.path.which', MagicMock(return_value=True)): ret = archive.extracted(os.path.join(os.sep + 'tmp', 'out'), source, options='xvzf', enforce_toplevel=False, keep=True) self.assertEqual(ret['changes']['extracted_files'], 'stderr') def test_extracted_when_if_missing_path_exists(self): ''' When if_missing exists, we should exit without making any changes. NOTE: We're not mocking the __salt__ dunder because if we actually run any functions from that dunder, we're doing something wrong. So, in those cases we'll just let it raise a KeyError and cause the test to fail. ''' name = if_missing = '/tmp/foo' source = 'salt://foo.bar.tar' with patch.object(os.path, 'exists', MagicMock(return_value=True)): ret = archive.extracted( name, source=source, if_missing=if_missing) self.assertTrue(ret['result'], ret) self.assertEqual( ret['comment'], 'Path {0} exists'.format(if_missing) )