From bf894c378bba0ea5ffc0eb25116118ab80aaf24e Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 17:32:41 -0700 Subject: [PATCH 01/40] utils.abs_readlink: return abs path, dereference symlinks --- salt/utils/__init__.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/salt/utils/__init__.py b/salt/utils/__init__.py index f19c2a986d..bd111bea78 100644 --- a/salt/utils/__init__.py +++ b/salt/utils/__init__.py @@ -858,6 +858,41 @@ def path_join(*parts): )) +def abs_readlink(path): + ''' + Return the absolute path. If path is a link, dereference it first. + + .. code-block:: python + + >>> import os + >>> os.makedirs('/tmp/dir') + >>> os.chdir('/tmp/dir') + >>> open('/tmp/dir/target', 'w').close() + >>> os.symlink('target', 'link1') + >>> os.symlink('../dir/target', 'link2') + >>> os.symlink('/tmp/dir/target', 'link3') + >>> abs_readlink('/tmp/dir/target') + '/tmp/dir/target' + >>> abs_readlink('/tmp/dir/link1') + '/tmp/dir/target' + >>> abs_readlink('/tmp/dir/link2') + '/tmp/dir/target' + >>> abs_readlink('/tmp/dir/link3') + '/tmp/dir/target' + >>> from subprocess import call + >>> call(['rm', '-r', '/tmp/dir']) + ''' + if os.path.islink(path): + base, lname = os.path.split(os.path.abspath(path)) + target = os.readlink(path) + if target.startswith(os.sep): + return os.path.abspath(target) + else: # target path is relative to supplied path + return os.path.abspath(os.path.join(base, target)) + else: + return os.path.abspath(path) + + def pem_finger(path=None, key=None, sum_type='sha256'): ''' Pass in either a raw pem string, or the path on disk to the location of a From 6b99798b1ea22256e40f4cd649d0d09699622afe Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 17:34:48 -0700 Subject: [PATCH 02/40] tests.integration: use system tmpdir on darwin --- tests/integration/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index 2e728cdc67..a30160e03d 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -78,10 +78,7 @@ if salt.utils.is_windows(): import win32api -if platform.uname()[0] == 'Darwin': - SYS_TMP_DIR = '/tmp' -else: - SYS_TMP_DIR = os.environ.get('TMPDIR', tempfile.gettempdir()) +SYS_TMP_DIR = salt.utils.abs_readlink(os.environ.get('TMPDIR', tempfile.gettempdir())) # Gentoo Portage prefers ebuild tests are rooted in ${TMPDIR} TMP = os.path.join(SYS_TMP_DIR, 'salt-tests-tmpdir') From 4028d80eee47b9b27ec28916c5f2d59e61481748 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 19:08:38 -0700 Subject: [PATCH 03/40] tests...runtests_helpers: use system tmpdir --- .../files/file/base/_modules/runtests_helpers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/integration/files/file/base/_modules/runtests_helpers.py b/tests/integration/files/file/base/_modules/runtests_helpers.py index 5438d51f24..d6885d5726 100644 --- a/tests/integration/files/file/base/_modules/runtests_helpers.py +++ b/tests/integration/files/file/base/_modules/runtests_helpers.py @@ -12,7 +12,11 @@ from __future__ import absolute_import import os import tempfile -SYS_TMP_DIR = tempfile.gettempdir() +# Import salt libs +import salt.utils + + +SYS_TMP_DIR = salt.utils.abs_readlink(os.environ.get('TMPDIR', tempfile.gettempdir())) # This tempdir path is defined on tests.integration.__init__ TMP = os.path.join(SYS_TMP_DIR, 'salt-tests-tmpdir') From 3a77e7d383d70fa4f4e3d10ea7878e27f63fd203 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 12:53:17 -0700 Subject: [PATCH 04/40] tests.runtests: increase file limit for MacOS unit tests --- tests/runtests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/runtests.py b/tests/runtests.py index f571599562..dff3f09df9 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -480,6 +480,9 @@ class SaltTestsuiteParser(SaltCoverageTestingParser): status = [] if self.options.unit: + # MacOS needs more open filehandles for running unit test suite + self.set_filehandle_limits() + results = self.run_suite( os.path.join(TEST_DIR, 'unit'), 'Unit', '*_test.py' ) From 34ba477b095a90be41e6385a4824e406fecec4b3 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 16:53:29 -0700 Subject: [PATCH 05/40] tests.runtests: configurable filehandle limits --- tests/runtests.py | 69 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/tests/runtests.py b/tests/runtests.py index dff3f09df9..17f0f2bd7a 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -40,7 +40,17 @@ try: except OSError as err: print('Failed to change directory to salt\'s source: {0}'.format(err)) -REQUIRED_OPEN_FILES = 3072 +# Soft and hard limits on max open filehandles +MAX_OPEN_FILES = { + 'integration': { + 'soft_limit': 3072, + 'hard_limit': 4096, + }, + 'unit': { + 'soft_limit': 1024, + 'hard_limit': 2048, + }, +} class SaltTestsuiteParser(SaltCoverageTestingParser): @@ -292,7 +302,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser): def start_daemons_only(self): if not salt.utils.is_windows(): - self.prep_filehandles() + self.set_filehandle_limits('integration') try: print_header( ' * Setting up Salt daemons for interactive use', @@ -335,32 +345,51 @@ class SaltTestsuiteParser(SaltCoverageTestingParser): while True: time.sleep(1) - def prep_filehandles(self): - smax_open_files, hmax_open_files = resource.getrlimit( - resource.RLIMIT_NOFILE - ) - if smax_open_files < REQUIRED_OPEN_FILES: + def set_filehandle_limits(self, limits='integration'): + ''' + Set soft and hard limits on open file handles at required thresholds + for integration tests or unit tests + ''' + # Get current limits + prev_soft, prev_hard = resource.getrlimit(resource.RLIMIT_NOFILE) + + # Get required limits + min_soft = MAX_OPEN_FILES[limits]['soft_limit'] + min_hard = MAX_OPEN_FILES[limits]['hard_limit'] + + # Check minimum required limits + set_limits = False + if prev_soft < min_soft: + soft = min_soft + set_limits = True + else: + soft = prev_soft + + if prev_hard < min_hard: + hard = min_hard + set_limits = True + else: + hard = prev_hard + + # Increase limits + if set_limits: print( - ' * Max open files setting is too low({0}) for running the ' - 'tests'.format(smax_open_files) + ' * Max open files settings is too low (soft: {0}, hard: {1}) ' + 'for running the tests'.format(prev_soft, prev_hard) ) print( - ' * Trying to raise the limit to {0}'.format(REQUIRED_OPEN_FILES) + ' * Trying to raise the limits to soft: ' + '{0}, hard: {1}'.format(soft, hard) ) - if hmax_open_files < 4096: - hmax_open_files = 4096 # Decent default? try: - resource.setrlimit( - resource.RLIMIT_NOFILE, - (REQUIRED_OPEN_FILES, hmax_open_files) - ) + resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard)) except Exception as err: print( - 'ERROR: Failed to raise the max open files setting -> ' + 'ERROR: Failed to raise the max open files settings -> ' '{0}'.format(err) ) print('Please issue the following command on your console:') - print(' ulimit -n {0}'.format(REQUIRED_OPEN_FILES)) + print(' ulimit -n {0}'.format(soft)) self.exit() finally: print('~' * getattr(self.options, 'output_columns', PNUM)) @@ -401,7 +430,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser): # We don't need the tests daemon running return [True] if not salt.utils.is_windows(): - self.prep_filehandles() + self.set_filehandle_limits('integration') try: print_header( @@ -481,7 +510,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser): status = [] if self.options.unit: # MacOS needs more open filehandles for running unit test suite - self.set_filehandle_limits() + self.set_filehandle_limits('unit') results = self.run_suite( os.path.join(TEST_DIR, 'unit'), 'Unit', '*_test.py' From c94dfb870f9f7102bd8b6f4b73993b67144793d3 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Mon, 29 Feb 2016 13:13:48 -0700 Subject: [PATCH 06/40] shell tests: comment on shell return data --- tests/integration/shell/enabled.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/integration/shell/enabled.py b/tests/integration/shell/enabled.py index 185738157c..eb86c0959b 100644 --- a/tests/integration/shell/enabled.py +++ b/tests/integration/shell/enabled.py @@ -31,7 +31,7 @@ class EnabledTest(integration.ModuleCase): ''' ensure that python_shell defaults to True for cmd.run ''' - enabled_ret = '3\nsaltines' + enabled_ret = '3\nsaltines' # the result of running self.cmd in a shell ret = self.run_function('cmd.run', [self.cmd]) self.assertEqual(ret, enabled_ret) @@ -52,7 +52,7 @@ class EnabledTest(integration.ModuleCase): state_filename = state_name + '.sls' state_file = os.path.join(STATE_DIR, state_filename) - enabled_ret = '3 saltines' + enabled_ret = '3 saltines' # the result of running self.cmd in a shell ret_key = 'test_|-shell_enabled_|-{0}_|-configurable_test_state'.format(enabled_ret) try: @@ -77,6 +77,7 @@ class EnabledTest(integration.ModuleCase): state_filename = state_name + '.sls' state_file = os.path.join(STATE_DIR, state_filename) + # the result of running self.cmd not in a shell disabled_ret = ('first second third | wc -l ; export SALTY_VARIABLE=saltines ' '&& echo $SALTY_VARIABLE ; echo duh &> /dev/null') ret_key = 'test_|-shell_enabled_|-{0}_|-configurable_test_state'.format(disabled_ret) From 2f1c0cf809ee9470c04f20dcdfb77ec8a5bfe66c Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Mon, 29 Feb 2016 13:13:57 -0700 Subject: [PATCH 07/40] shell tests: strip whitespace from shell return --- tests/integration/shell/enabled.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/shell/enabled.py b/tests/integration/shell/enabled.py index eb86c0959b..9e80a63d5e 100644 --- a/tests/integration/shell/enabled.py +++ b/tests/integration/shell/enabled.py @@ -57,7 +57,7 @@ class EnabledTest(integration.ModuleCase): try: salt.utils.fopen(state_file, 'w').write(textwrap.dedent('''\ - {{% set shell_enabled = salt['cmd.run']("{0}") %}} + {{% set shell_enabled = salt['cmd.run']("{0}").strip() %}} shell_enabled: test.configurable_test_state: From 0098c1c554ff73e947f3a66229043c0d709b3c2e Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Mon, 29 Feb 2016 11:34:47 -0700 Subject: [PATCH 08/40] modules.blockdev test: mock utils.which --- tests/unit/modules/blockdev_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/modules/blockdev_test.py b/tests/unit/modules/blockdev_test.py index 77b574e149..6009a101e9 100644 --- a/tests/unit/modules/blockdev_test.py +++ b/tests/unit/modules/blockdev_test.py @@ -37,6 +37,8 @@ class TestBlockdevModule(TestCase): ret = blockdev.tune('/dev/sda', **kwargs) self.assertTrue(ret) + @skipIf(not salt.utils.which('sync'), 'sync not found') + @skipIf(not salt.utils.which('mkfs'), 'mkfs not found') def test_format(self): ''' unit tests for blockdev.format From 73ad02e91768a2a083b435c82dcfdabc7aa27d4b Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 14:22:52 -0700 Subject: [PATCH 09/40] modules.disk: run both integration test cases manually --- tests/integration/modules/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/modules/disk.py b/tests/integration/modules/disk.py index 449d055a7d..67cb3e9676 100644 --- a/tests/integration/modules/disk.py +++ b/tests/integration/modules/disk.py @@ -81,4 +81,4 @@ class DiskModuleTest(integration.ModuleCase): if __name__ == '__main__': from integration import run_tests - run_tests(DiskModuleTest) + run_tests([DiskModuleVirtualizationTest, DiskModuleTest]) From bdb210dc132cb190de6917008b9674221bda78bf Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 14:23:27 -0700 Subject: [PATCH 10/40] modules.disk int tests: assert darwin disk usage --- tests/integration/modules/disk.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/integration/modules/disk.py b/tests/integration/modules/disk.py index 67cb3e9676..165264ea5d 100644 --- a/tests/integration/modules/disk.py +++ b/tests/integration/modules/disk.py @@ -56,12 +56,23 @@ class DiskModuleTest(integration.ModuleCase): self.assertTrue(isinstance(ret, dict)) if not isinstance(ret, dict): return - for key, val in six.iteritems(ret): - self.assertTrue('filesystem' in val) - self.assertTrue('1K-blocks' in val) - self.assertTrue('used' in val) - self.assertTrue('available' in val) - self.assertTrue('capacity' in val) + if salt.utils.is_darwin(): + for key, val in six.iteritems(ret): + self.assertTrue('filesystem' in val) + self.assertTrue('512-blocks' in val) + self.assertTrue('used' in val) + self.assertTrue('available' in val) + self.assertTrue('capacity' in val) + self.assertTrue('iused' in val) + self.assertTrue('ifree' in val) + self.assertTrue('%iused' in val) + else: + for key, val in six.iteritems(ret): + self.assertTrue('filesystem' in val) + self.assertTrue('1K-blocks' in val) + self.assertTrue('used' in val) + self.assertTrue('available' in val) + self.assertTrue('capacity' in val) def test_inodeusage(self): ''' From d818810200a18a7c940613f5599bba240e4dec09 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 17:46:48 -0700 Subject: [PATCH 11/40] modules.disk int tests: move decorators to class --- tests/integration/modules/disk.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/integration/modules/disk.py b/tests/integration/modules/disk.py index 165264ea5d..b87090cc25 100644 --- a/tests/integration/modules/disk.py +++ b/tests/integration/modules/disk.py @@ -18,27 +18,23 @@ import salt.utils import salt.ext.six as six +@destructiveTest +@skipIf(salt.utils.is_windows(), 'No mtab on Windows') class DiskModuleVirtualizationTest(integration.ModuleCase): ''' Test to make sure we return a clean result under Docker. Refs #8976 This is factored into its own class so that we can have some certainty that setUp() and tearDown() are run. ''' - @destructiveTest - @skipIf(salt.utils.is_windows(), 'No mtab on Windows') def setUp(self): # Make /etc/mtab unreadable if os.path.isfile('/etc/mtab'): shutil.move('/etc/mtab', '/tmp/mtab') - @destructiveTest - @skipIf(salt.utils.is_windows(), 'No mtab on Windows') def test_no_mtab(self): ret = self.run_function('disk.usage') self.assertDictEqual(ret, {}) - @destructiveTest - @skipIf(salt.utils.is_windows(), 'No mtab on Windows') def tearDown(self): if os.path.isfile('/tmp/mtab'): shutil.move('/tmp/mtab', '/etc/mtab') From f69ab83623eeb1ec01d6499f0193be170cfc0057 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 17:47:11 -0700 Subject: [PATCH 12/40] modules.disk int tests: mtab not used on darwin --- tests/integration/modules/disk.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/modules/disk.py b/tests/integration/modules/disk.py index b87090cc25..299ed4b6a1 100644 --- a/tests/integration/modules/disk.py +++ b/tests/integration/modules/disk.py @@ -20,6 +20,7 @@ import salt.ext.six as six @destructiveTest @skipIf(salt.utils.is_windows(), 'No mtab on Windows') +@skipIf(salt.utils.is_darwin(), 'No mtab on Darwin') class DiskModuleVirtualizationTest(integration.ModuleCase): ''' Test to make sure we return a clean result under Docker. Refs #8976 From ddea2361de596e09b1160c5e947d0b30ca196304 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:42:12 -0700 Subject: [PATCH 13/40] modules.useradd int tests: move decorators to class --- tests/integration/modules/useradd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/modules/useradd.py b/tests/integration/modules/useradd.py index 335a02c7b7..fcdbeab32c 100644 --- a/tests/integration/modules/useradd.py +++ b/tests/integration/modules/useradd.py @@ -22,6 +22,8 @@ import integration from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin +@destructiveTest +@skipIf(os.geteuid() != 0, 'you must be root to run these tests') class UseraddModuleTest(integration.ModuleCase): def setUp(self): @@ -40,8 +42,6 @@ class UseraddModuleTest(integration.ModuleCase): for x in range(size) ) - @destructiveTest - @skipIf(os.geteuid() != 0, 'you must be root to run this test') @requires_system_grains def test_groups_includes_primary(self, grains=None): # Let's create a user, which usually creates the group matching the From ba19f395d17b4019bd3d3724b00fcc536b2282db Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 18:41:38 -0700 Subject: [PATCH 14/40] modules.useradd int tests: disable testcase on nonlinux --- tests/integration/modules/useradd.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/modules/useradd.py b/tests/integration/modules/useradd.py index fcdbeab32c..8334c347ad 100644 --- a/tests/integration/modules/useradd.py +++ b/tests/integration/modules/useradd.py @@ -16,6 +16,7 @@ from salttesting.helpers import ( ensure_in_syspath('../../') # Import salt libs +import salt.utils import integration # Import 3rd-party libs @@ -24,6 +25,9 @@ from salt.ext.six.moves import range # pylint: disable=import-error,redefined-b @destructiveTest @skipIf(os.geteuid() != 0, 'you must be root to run these tests') +# Only run on linux for now until or if we can figure out a way to use +# __grains__ inside of useradd.__virtual__ +@skipIf(not salt.utils.is_linux(), 'These tests can only be run on linux') class UseraddModuleTest(integration.ModuleCase): def setUp(self): From 528a9d19961f35d8ec0ae4cfdfc40f23cc4108ca Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:21:23 -0700 Subject: [PATCH 15/40] modules.useradd.primary_group: return user's primary group --- salt/modules/useradd.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/salt/modules/useradd.py b/salt/modules/useradd.py index b9050881cf..3f321c4ca2 100644 --- a/salt/modules/useradd.py +++ b/salt/modules/useradd.py @@ -14,6 +14,7 @@ import copy # Import salt libs import salt.utils +import salt.utils.decorators as decorators from salt.ext import six from salt.exceptions import CommandExecutionError @@ -574,6 +575,22 @@ def _format_info(data): 'homephone': gecos_field[3]} +@decorators.which('id') +def primary_group(name): + ''' + Return the primary group of the named user + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt '*' user.primary_group saltadmin + ''' + return __salt__['cmd.run'](['id', '-g', '-n', name]) + + def list_groups(name): ''' Return a list of groups the named user belongs to From e53ae6c44e2bd55cd4db8381b4ae41a815b8312c Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 21:23:28 -0700 Subject: [PATCH 16/40] modules.useradd.primary_group: add integration test --- tests/integration/modules/useradd.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/integration/modules/useradd.py b/tests/integration/modules/useradd.py index 8334c347ad..cf5fa23202 100644 --- a/tests/integration/modules/useradd.py +++ b/tests/integration/modules/useradd.py @@ -89,6 +89,27 @@ class UseraddModuleTest(integration.ModuleCase): self.run_function('user.delete', [uname, True, True]) raise + def test_linux_user_primary_group(self, grains=None): + ''' + Tests the primary_group function + ''' + name = 'saltyuser' + + # Create a user to test primary group function + if self.run_function('user.add', [name]) is not True: + self.run_function('user.delete', [name]) + self.skipTest('Failed to create a user') + + try: + # Test useradd.primary_group + primary_group = self.run_function('user.primary_group', [name]) + uid_info = self.run_function('user.info', [name]) + self.assertIn(primary_group, uid_info['groups']) + + except: + self.run_function('user.delete', [name]) + raise + if __name__ == '__main__': from integration import run_tests From 86b2522a7f412abb102550ac89831bf14f30df82 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:21:37 -0700 Subject: [PATCH 17/40] modules.mac_user.primary_group: return user's primary group --- salt/modules/mac_user.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/salt/modules/mac_user.py b/salt/modules/mac_user.py index c08441b2ab..687ecbd91e 100644 --- a/salt/modules/mac_user.py +++ b/salt/modules/mac_user.py @@ -18,6 +18,7 @@ from salt.ext.six import string_types # Import salt libs import salt.utils +import salt.utils.decorators as decorators from salt.utils.locales import sdecode from salt.exceptions import CommandExecutionError, SaltInvocationError @@ -396,6 +397,22 @@ def _format_info(data): 'fullname': data.pw_gecos} +@decorators.which('id') +def primary_group(name): + ''' + Return the primary group of the named user + + .. versionadded:: 2016.3.0 + + CLI Example: + + .. code-block:: bash + + salt '*' user.primary_group saltadmin + ''' + return __salt__['cmd.run'](['id', '-g', '-n', name]) + + def list_groups(name): ''' Return a list of groups the named user belongs to From fea37b303e2c059e6514b89d65fddc5bcc562054 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:23:17 -0700 Subject: [PATCH 18/40] modules.mac_user int tests: move common decorators to class --- tests/integration/modules/mac_user.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/integration/modules/mac_user.py b/tests/integration/modules/mac_user.py index f64c9edfc5..1ec3e6a2fa 100644 --- a/tests/integration/modules/mac_user.py +++ b/tests/integration/modules/mac_user.py @@ -41,6 +41,9 @@ DEL_USER = __random_string() CHANGE_USER = __random_string() +@destructiveTest +@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test') +@requires_system_grains class MacUserModuleTest(integration.ModuleCase): ''' Integration tests for the mac_user module @@ -59,9 +62,6 @@ class MacUserModuleTest(integration.ModuleCase): ) ) - @destructiveTest - @skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test') - @requires_system_grains def test_mac_user_add(self, grains=None): ''' Tests the add function @@ -74,9 +74,6 @@ class MacUserModuleTest(integration.ModuleCase): self.run_function('user.delete', [ADD_USER]) raise - @destructiveTest - @skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test') - @requires_system_grains def test_mac_user_delete(self, grains=None): ''' Tests the delete function @@ -94,9 +91,6 @@ class MacUserModuleTest(integration.ModuleCase): except CommandExecutionError: raise - @destructiveTest - @skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test') - @requires_system_grains def test_mac_user_changes(self, grains=None): ''' Tests mac_user functions that change user properties @@ -141,9 +135,6 @@ class MacUserModuleTest(integration.ModuleCase): self.run_function('user.delete', [CHANGE_USER]) raise - @destructiveTest - @skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test') - @requires_system_grains def tearDown(self, grains=None): ''' Clean up after tests From 5905518ee56d2a988a5a436164a89a88809989ac Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:28:49 -0700 Subject: [PATCH 19/40] modules.mac_user int tests: fix comment typo --- tests/integration/modules/mac_user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/modules/mac_user.py b/tests/integration/modules/mac_user.py index 1ec3e6a2fa..8adef35459 100644 --- a/tests/integration/modules/mac_user.py +++ b/tests/integration/modules/mac_user.py @@ -101,7 +101,7 @@ class MacUserModuleTest(integration.ModuleCase): self.skipTest('Failed to create a user') try: - # Test mac_user.chudi + # Test mac_user.chuid self.run_function('user.chuid', [CHANGE_USER, 4376]) uid_info = self.run_function('user.info', [CHANGE_USER]) self.assertEqual(uid_info['uid'], 4376) From 2fe116014391efe201694abcca11f2736081654e Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:30:14 -0700 Subject: [PATCH 20/40] modules.mac_user.primary_group: add integration test --- tests/integration/modules/mac_user.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/integration/modules/mac_user.py b/tests/integration/modules/mac_user.py index 8adef35459..d7e512237d 100644 --- a/tests/integration/modules/mac_user.py +++ b/tests/integration/modules/mac_user.py @@ -38,6 +38,7 @@ def __random_string(size=6): # Create user strings for tests ADD_USER = __random_string() DEL_USER = __random_string() +PRIMARY_GROUP_USER = __random_string() CHANGE_USER = __random_string() @@ -91,6 +92,26 @@ class MacUserModuleTest(integration.ModuleCase): except CommandExecutionError: raise + def test_mac_user_primary_group(self, grains=None): + ''' + Tests the primary_group function + ''' + + # Create a user to test primary group function + if self.run_function('user.add', [PRIMARY_GROUP_USER]) is not True: + self.run_function('user.delete', [PRIMARY_GROUP_USER]) + self.skipTest('Failed to create a user') + + try: + # Test mac_user.primary_group + primary_group = self.run_function('user.primary_group', [PRIMARY_GROUP_USER]) + uid_info = self.run_function('user.info', [PRIMARY_GROUP_USER]) + self.assertIn(primary_group, uid_info['groups']) + + except AssertionError: + self.run_function('user.delete', [PRIMARY_GROUP_USER]) + raise + def test_mac_user_changes(self, grains=None): ''' Tests mac_user functions that change user properties From 2dddc63dafcc0042b1bb4eca09085ff6229780df Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 23:01:10 -0700 Subject: [PATCH 21/40] modules.mac_user: add and remove user home dir --- salt/modules/mac_user.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/salt/modules/mac_user.py b/salt/modules/mac_user.py index 687ecbd91e..297c5487e8 100644 --- a/salt/modules/mac_user.py +++ b/salt/modules/mac_user.py @@ -116,7 +116,8 @@ def add(name, _dscl([name_path, 'RealName', fullname]) # Make sure home directory exists - __salt__['file.mkdir'](name) + if createhome: + __salt__['file.mkdir'](home, user=uid, group=gid) # dscl buffers changes, sleep before setting group membership time.sleep(1) @@ -125,7 +126,7 @@ def add(name, return True -def delete(name, *args): +def delete(name, remove=False, force=False): ''' Remove a user from the minion @@ -135,12 +136,19 @@ def delete(name, *args): salt '*' user.delete foo ''' - ### NOTE: *args isn't used here but needs to be included in this function - ### for compatibility with the user.absent state if salt.utils.contains_whitespace(name): raise SaltInvocationError('Username cannot contain whitespace') if not info(name): return True + + # force is added for compatibility with user.absent state function + if force: + log.warn('force option is unsupported on MacOS, ignoring') + + # remove home directory from filesystem + if remove: + __salt__['file.remove'](info(name)['home']) + # Remove from any groups other than primary group. Needs to be done since # group membership is managed separately from users and an entry for the # user will persist even after the user is removed. From 424a8b11bd43c6b635f7f7840fc83acffe7535f3 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 11:53:24 -0700 Subject: [PATCH 22/40] modules.pw_group: mock (BSD) test to run on MacOS --- tests/unit/modules/pw_group_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/modules/pw_group_test.py b/tests/unit/modules/pw_group_test.py index 7b6d87c4ed..696111f417 100644 --- a/tests/unit/modules/pw_group_test.py +++ b/tests/unit/modules/pw_group_test.py @@ -63,8 +63,10 @@ class PwGroupTestCase(TestCase): ''' Tests for return info on all groups ''' - mock = MagicMock(return_value={'group.getent': 1}) - with patch.dict(pw_group.__context__, mock): + mock_getent = [{'passwd': 'x', + 'gid': 0, + 'name': 'root'}] + with patch.dict(pw_group.__context__, {'group.getent': mock_getent}): self.assertDictContainsSubset({'passwd': 'x', 'gid': 0, 'name': 'root'}, pw_group.getent()[0]) From 590c0ad9869d0f71bf2a4856aa8e9bf935a50f98 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 14:54:19 -0700 Subject: [PATCH 23/40] modules.btrfs unit tests: mock /proc/mounts --- tests/unit/modules/btrfs_test.py | 57 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/tests/unit/modules/btrfs_test.py b/tests/unit/modules/btrfs_test.py index 28aa7b34dd..40d116095d 100644 --- a/tests/unit/modules/btrfs_test.py +++ b/tests/unit/modules/btrfs_test.py @@ -7,6 +7,7 @@ from __future__ import absolute_import # Import Salt Testing Libs from salttesting import TestCase, skipIf from salttesting.mock import ( + mock_open, MagicMock, patch, NO_MOCK, @@ -87,23 +88,27 @@ class BtrfsTestCase(TestCase): ret = [{'range': '/dev/sda1', 'mount_point': False, 'log': False, 'passed': True}] - mock = MagicMock(return_value={'retcode': 1, - 'stderr': '', - 'stdout': 'Salt'}) - with patch.dict(btrfs.__salt__, {'cmd.run_all': mock}): - self.assertListEqual(btrfs.defragment('/dev/sda1'), ret) + mock_run = MagicMock(return_value={'retcode': 1, + 'stderr': '', + 'stdout': 'Salt'}) + with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_run}): + mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0') + with patch.object(salt.utils, 'fopen', mock_file): + self.assertListEqual(btrfs.defragment('/dev/sda1'), ret) @patch('salt.utils.fsutils._is_device', MagicMock(return_value=True)) def test_defragment_error(self): ''' Test if it gives device not mount error ''' - mock = MagicMock(return_value={'retcode': 1, - 'stderr': '', - 'stdout': 'Salt'}) - with patch.dict(btrfs.__salt__, {'cmd.run_all': mock}): - self.assertRaises(CommandExecutionError, btrfs.defragment, - '/dev/sda1') + mock_run = MagicMock(return_value={'retcode': 1, + 'stderr': '', + 'stdout': 'Salt'}) + with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_run}): + mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0') + with patch.object(salt.utils, 'fopen', mock_file): + self.assertRaises(CommandExecutionError, btrfs.defragment, + '/dev/sda1') # 'features' function tests: 1 @@ -158,13 +163,15 @@ class BtrfsTestCase(TestCase): ''' Test if it create a file system on the specified device. ''' - mock = MagicMock(return_value={'retcode': 1, - 'stderr': '', - 'stdout': 'Salt'}) + mock_cmd = MagicMock(return_value={'retcode': 1, + 'stderr': '', + 'stdout': 'Salt'}) mock_info = MagicMock(return_value=[]) - with patch.dict(btrfs.__salt__, {'cmd.run_all': mock, + with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_cmd, 'btrfs.info': mock_info}): - self.assertDictEqual(btrfs.mkfs('/dev/sda1'), {'log': 'Salt'}) + mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0') + with patch.object(salt.utils, 'fopen', mock_file): + self.assertDictEqual(btrfs.mkfs('/dev/sda1'), {'log': 'Salt'}) def test_mkfs_error(self): ''' @@ -304,14 +311,16 @@ class BtrfsTestCase(TestCase): ''' Test if it gives migration error ''' - mock = MagicMock(return_value={'retcode': 1, - 'stderr': '', - 'stdout': 'Salt'}) - with patch.dict(btrfs.__salt__, {'cmd.run_all': mock}): - mock = MagicMock(return_value={'/dev/sda1': {'type': 'ext4'}}) - with patch.object(salt.utils.fsutils, '_blkid_output', mock): - self.assertRaises(CommandExecutionError, btrfs.convert, - '/dev/sda1') + mock_run = MagicMock(return_value={'retcode': 1, + 'stderr': '', + 'stdout': 'Salt'}) + with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_run}): + mock_blk = MagicMock(return_value={'/dev/sda1': {'type': 'ext4'}}) + with patch.object(salt.utils.fsutils, '_blkid_output', mock_blk): + mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0') + with patch.object(salt.utils, 'fopen', mock_file): + self.assertRaises(CommandExecutionError, btrfs.convert, + '/dev/sda1') # 'add' function tests: 1 From c2f4da17813b096a1ec8fd3b62e29fc7f143662f Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 15:25:10 -0700 Subject: [PATCH 24/40] modules.gpg: only return (False, reason) in __virtual__ --- salt/modules/gpg.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index c353dc2d28..3d78c33582 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -97,24 +97,25 @@ def _check_gpg(): Looks to see if gpg binary is present on the system. ''' # Get the path to the gpg binary. - if salt.utils.which('gpg'): - return __virtualname__ - return (False, 'The gpg execution module cannot be loaded: ' - 'gpg binary is not in the path.') + return salt.utils.which('gpg') def __virtual__(): ''' Makes sure that python-gnupg and gpg are available. ''' - if _check_gpg() and HAS_LIBS: + if not _check_gpg(): + return (False, 'The gpg execution module cannot be loaded: ' + 'gpg binary is not in the path.') + if HAS_LIBS: gnupg_version = distutils.version.LooseVersion(gnupg.__version__) if gnupg_version >= '1.3.1': global GPG_1_3_1 GPG_1_3_1 = True return __virtualname__ - return (False, 'The gpg execution module cannot be loaded; either the' - ' gnupg module is not installed or the gpg binary is not in the path.') + + return (False, 'The gpg execution module cannot be loaded; the' + ' gnupg python module is not installed.') def _create_gpg(user=None, gnupghome=None): From 3c9f61231c7f68d07a2833d6c8a701a629302107 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Tue, 8 Mar 2016 10:50:39 -0700 Subject: [PATCH 25/40] modules.gpg: rename _gpg function --- salt/modules/gpg.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index 3d78c33582..bf9433da8c 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -92,9 +92,9 @@ except ImportError: pass -def _check_gpg(): +def _gpg(): ''' - Looks to see if gpg binary is present on the system. + Returns the path to the gpg binary ''' # Get the path to the gpg binary. return salt.utils.which('gpg') @@ -104,7 +104,7 @@ def __virtual__(): ''' Makes sure that python-gnupg and gpg are available. ''' - if not _check_gpg(): + if not _gpg(): return (False, 'The gpg execution module cannot be loaded: ' 'gpg binary is not in the path.') if HAS_LIBS: From cfa962fd36da21ed11c3b2be0907156eca084538 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Tue, 8 Mar 2016 10:51:42 -0700 Subject: [PATCH 26/40] modules.gpg: refactor trust_key cmd to bypass shell --- salt/modules/gpg.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index bf9433da8c..be5d00776b 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -851,15 +851,18 @@ def trust_key(keyid=None, if trust_level not in _VALID_TRUST_LEVELS: return 'ERROR: Valid trust levels - {0}'.format(','.join(_VALID_TRUST_LEVELS)) - cmd = 'echo "{0}:{1}" | {2} --import-ownertrust'.format(_cmd_quote(fingerprint), - _cmd_quote(NUM_TRUST_DICT[trust_level]), - _cmd_quote(_check_gpg())) + stdin = '{0}:{1}\n'.format(fingerprint, NUM_TRUST_DICT[trust_level]) + cmd = [_gpg(), '--import-ownertrust'] _user = user + if user == 'salt': homeDir = os.path.join(salt.syspaths.CONFIG_DIR, 'gpgkeys') - cmd = '{0} --homedir {1}'.format(cmd, homeDir) + cmd.extend([' --homedir', homeDir]) _user = 'root' - res = __salt__['cmd.run_all'](cmd, runas=_user, python_shell=True) + res = __salt__['cmd.run_all'](cmd, + stdin=stdin, + runas=_user, + python_shell=False) if not res['retcode'] == 0: ret['res'] = False From 7407392d42f0d78ef2bdf8b64369374abdf3a0ca Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Tue, 8 Mar 2016 10:53:32 -0700 Subject: [PATCH 27/40] modules.gpg: remove unused and duplicate imports --- salt/modules/gpg.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index be5d00776b..a4396e13a9 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -26,19 +26,6 @@ from salt.exceptions import SaltInvocationError # Import 3rd-party libs import salt.ext.six as six -try: - from shlex import quote as _cmd_quote # pylint: disable=E0611 -except ImportError: - from pipes import quote as _cmd_quote - -from salt.exceptions import ( - SaltInvocationError -) - -try: - from shlex import quote as _cmd_quote # pylint: disable=E0611 -except ImportError: - from pipes import quote as _cmd_quote # Set up logging log = logging.getLogger(__name__) From 328d058f224d7236b4e121721607688d49963cfa Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 15:35:32 -0700 Subject: [PATCH 28/40] modules.linux_sysctl unit tests: mock ctl presence --- tests/unit/modules/linux_sysctl_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/modules/linux_sysctl_test.py b/tests/unit/modules/linux_sysctl_test.py index ca93749a33..89bea83e5b 100644 --- a/tests/unit/modules/linux_sysctl_test.py +++ b/tests/unit/modules/linux_sysctl_test.py @@ -97,6 +97,7 @@ class LinuxSysctlTestCase(TestCase): 1, config=None) @patch('os.path.isfile', MagicMock(return_value=False)) + @patch('os.path.exists', MagicMock(return_value=True)) def test_persist_no_conf_success(self): ''' Tests successful add of config file when previously not one @@ -120,6 +121,7 @@ class LinuxSysctlTestCase(TestCase): '#\n# Kernel sysctl configuration\n#\n') @patch('os.path.isfile', MagicMock(return_value=True)) + @patch('os.path.exists', MagicMock(return_value=True)) def test_persist_read_conf_success(self): ''' Tests sysctl.conf read success From eb2964d51741ea45d9ed7eaf8be554bb70215ffd Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 15:41:32 -0700 Subject: [PATCH 29/40] modules.mount unit tests: mock /etc/fstab --- tests/unit/modules/mount_test.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/unit/modules/mount_test.py b/tests/unit/modules/mount_test.py index c304531145..9c4ad6f363 100644 --- a/tests/unit/modules/mount_test.py +++ b/tests/unit/modules/mount_test.py @@ -106,12 +106,13 @@ class MountTestCase(TestCase): ''' Remove the mount point from the fstab ''' - mock = MagicMock(return_value={}) - with patch.object(mount, 'fstab', mock): - self.assertTrue(mount.rm_fstab('name', 'device')) + mock_fstab = MagicMock(return_value={}) + with patch.object(mount, 'fstab', mock_fstab): + with patch('salt.utils.fopen', mock_open()): + self.assertTrue(mount.rm_fstab('name', 'device')) - mock = MagicMock(return_value={'name': 'name'}) - with patch.object(mount, 'fstab', mock): + mock_fstab = MagicMock(return_value={'name': 'name'}) + with patch.object(mount, 'fstab', mock_fstab): with patch('salt.utils.fopen', mock_open()) as m_open: helper_open = m_open() helper_open.write.assertRaises(CommandExecutionError, From fe2fd3f993b70c046d0fc25073d186aebac0a340 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 15:50:46 -0700 Subject: [PATCH 30/40] modules.ps unit tests: check ps __virtual__ --- tests/unit/modules/ps_test.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/unit/modules/ps_test.py b/tests/unit/modules/ps_test.py index 063d724acf..a0accb1161 100644 --- a/tests/unit/modules/ps_test.py +++ b/tests/unit/modules/ps_test.py @@ -13,9 +13,15 @@ from salttesting.mock import MagicMock, patch, call, Mock ensure_in_syspath('../../') +# Import Salt libs from salt.modules import ps +import salt.ext.six as six -HAS_PSUTIL = ps.__virtual__() +ps_virtual = ps.__virtual__() +if ps_virtual is True or isinstance(ps_virtual, six.string_types): + HAS_PSUTIL = True +else: + HAS_PSUTIL = False HAS_PSUTIL_VERSION = False # Import 3rd-party libs From 7a8061cc1ecf3dc1500977addc2d3b96c3d5926f Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 12:12:34 -0700 Subject: [PATCH 31/40] states.file unit tests: use existing file for unmocked tests --- tests/unit/states/file_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/states/file_test.py b/tests/unit/states/file_test.py index 2508fd2238..3858f9349c 100644 --- a/tests/unit/states/file_test.py +++ b/tests/unit/states/file_test.py @@ -963,7 +963,7 @@ class FileTestCase(TestCase): ''' Test to comment out specified lines in a file. ''' - name = '/etc/fstab' + name = '/etc/aliases' if salt.utils.is_darwin() else '/etc/fstab' regex = 'bind 127.0.0.1' ret = {'name': name, @@ -1003,7 +1003,7 @@ class FileTestCase(TestCase): 'file.comment_line': mock_t}): with patch.dict(filestate.__opts__, {'test': True}): comt = ('File {0} is set to be updated'.format(name)) - ret.update({'comment': comt, 'result': None, 'pchanges': {'/etc/fstab': 'updated'}}) + ret.update({'comment': comt, 'result': None, 'pchanges': {name: 'updated'}}) self.assertDictEqual(filestate.comment(name, regex), ret) with patch.dict(filestate.__opts__, {'test': False}): @@ -1020,7 +1020,7 @@ class FileTestCase(TestCase): ''' Test to uncomment specified commented lines in a file ''' - name = '/etc/fstab' + name = '/etc/aliases' if salt.utils.is_darwin() else '/etc/fstab' regex = 'bind 127.0.0.1' ret = {'name': name, @@ -1058,7 +1058,7 @@ class FileTestCase(TestCase): with patch.dict(filestate.__opts__, {'test': True}): comt = ('File {0} is set to be updated'.format(name)) - ret.update({'comment': comt, 'result': None, 'pchanges': {'/etc/fstab': 'updated'}, }) + ret.update({'comment': comt, 'result': None, 'pchanges': {name: 'updated'}, }) self.assertDictEqual(filestate.uncomment(name, regex), ret) with patch.dict(filestate.__opts__, {'test': False}): From 08493d85fd6f819d3881390ea8bfc1bc0ba75273 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 12:15:36 -0700 Subject: [PATCH 32/40] states.file unit tests: mark tests destructive for touching file --- tests/unit/states/file_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/states/file_test.py b/tests/unit/states/file_test.py index 3858f9349c..e9e664072b 100644 --- a/tests/unit/states/file_test.py +++ b/tests/unit/states/file_test.py @@ -7,7 +7,7 @@ import pprint # Import Salt Testing libs from salttesting import skipIf, TestCase -from salttesting.helpers import ensure_in_syspath +from salttesting.helpers import destructiveTest, ensure_in_syspath from salttesting.mock import ( NO_MOCK, NO_MOCK_REASON, @@ -959,6 +959,7 @@ class FileTestCase(TestCase): # 'comment' function tests: 1 + @destructiveTest def test_comment(self): ''' Test to comment out specified lines in a file. @@ -1016,6 +1017,7 @@ class FileTestCase(TestCase): # 'uncomment' function tests: 1 + @destructiveTest def test_uncomment(self): ''' Test to uncomment specified commented lines in a file From aa61e1056f3002e18827698928533451bd62bc78 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 20:33:26 -0700 Subject: [PATCH 33/40] states.file int tests: find root's primary group --- tests/integration/states/file.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/states/file.py b/tests/integration/states/file.py index cd956b522c..a005a67f0e 100644 --- a/tests/integration/states/file.py +++ b/tests/integration/states/file.py @@ -1831,7 +1831,9 @@ class FileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn): self.assertEqual(pwd.getpwuid(onestats.st_uid).pw_name, user) self.assertEqual(pwd.getpwuid(twostats.st_uid).pw_name, 'root') self.assertEqual(grp.getgrgid(onestats.st_gid).gr_name, group) - self.assertEqual(grp.getgrgid(twostats.st_gid).gr_name, 'root') + if salt.utils.which('id'): + root_group = self.run_function('user.primary_group', ['root']) + self.assertEqual(grp.getgrgid(twostats.st_gid).gr_name, root_group) finally: if os.path.isdir(tmp_dir): shutil.rmtree(tmp_dir) From 5d5ce619b7b8a7aa03ea0c978b3cadbb20ba8e7d Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 19:56:09 -0700 Subject: [PATCH 34/40] states.user int tests: disable GECOS for MacOS --- tests/integration/states/user.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/integration/states/user.py b/tests/integration/states/user.py index 0f905f3e32..c781daa8a2 100644 --- a/tests/integration/states/user.py +++ b/tests/integration/states/user.py @@ -22,6 +22,7 @@ from salttesting.helpers import ( ensure_in_syspath('../../') # Import salt libs +import salt.utils import integration @@ -186,9 +187,11 @@ class UserTest(integration.ModuleCase, ret = self.run_function('user.info', ['salt_test']) self.assertReturnNonEmptySaltType(ret) self.assertEqual('', ret['fullname']) - self.assertEqual('', ret['roomnumber']) - self.assertEqual('', ret['workphone']) - self.assertEqual('', ret['homephone']) + # MacOS does not supply the following GECOS fields + if not salt.utils.is_darwin(): + self.assertEqual('', ret['roomnumber']) + self.assertEqual('', ret['workphone']) + self.assertEqual('', ret['homephone']) ret = self.run_state('user.absent', name='salt_test') self.assertSaltTrueReturn(ret) From 7c48cf7ea66f5d0f3dfe2bf5f5ba0c44764b9b3f Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 23:10:34 -0700 Subject: [PATCH 35/40] states.user int tests: check MacOS primary group --- tests/integration/states/user.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/integration/states/user.py b/tests/integration/states/user.py index c781daa8a2..5ff893ce5a 100644 --- a/tests/integration/states/user.py +++ b/tests/integration/states/user.py @@ -108,8 +108,12 @@ class UserTest(integration.ModuleCase, If you run the test and it fails, please fix the code it's testing to work on your operating system. ''' + # MacOS users' primary group defaults to staff (20), not the name of + # user + gid_from_name = False if grains['os_family'] == 'MacOS' else True + ret = self.run_state('user.present', name='salt_test', - gid_from_name=True, home='/var/lib/salt_test') + gid_from_name=gid_from_name, home='/var/lib/salt_test') self.assertSaltTrueReturn(ret) ret = self.run_function('user.info', ['salt_test']) @@ -119,6 +123,8 @@ class UserTest(integration.ModuleCase, self.assertTrue(os.path.isdir('/var/lib/salt_test')) if grains['os_family'] in ('Suse',): self.assertEqual(group_name, 'users') + elif grains['os_family'] == 'MacOS': + self.assertEqual(group_name, 'staff') else: self.assertEqual(group_name, 'salt_test') From 431a247b66688beef2c3922968c0ca468ca56c40 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 19:59:57 -0700 Subject: [PATCH 36/40] states.cmd int tests: echo is more portable than true --- tests/integration/states/cmd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/states/cmd.py b/tests/integration/states/cmd.py index 9657a707df..508dce5004 100644 --- a/tests/integration/states/cmd.py +++ b/tests/integration/states/cmd.py @@ -142,14 +142,14 @@ class CMDTest(integration.ModuleCase, state_filename = state_name + '.sls' state_file = os.path.join(STATE_DIR, state_filename) - saltines_key = 'cmd_|-saltines_|-/bin/true_|-run' + saltines_key = 'cmd_|-saltines_|-echo_|-run' biscuits_key = 'cmd_|-biscuits_|-echo hello_|-wait' try: salt.utils.fopen(state_file, 'w').write(textwrap.dedent('''\ saltines: cmd.run: - - name: /bin/true + - name: echo - cwd: / - stateful: True From d33b36598454124f1683bca841b5bbc5c2eae4b5 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 21:50:36 -0700 Subject: [PATCH 37/40] states.pkg int tests: add pkgs for MacOS --- tests/integration/states/pkg.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration/states/pkg.py b/tests/integration/states/pkg.py index a4e4fa01db..a8481d561d 100644 --- a/tests/integration/states/pkg.py +++ b/tests/integration/states/pkg.py @@ -30,7 +30,8 @@ _PKG_TARGETS = { 'Debian': ['python-plist', 'apg'], 'RedHat': ['xz-devel', 'zsh-html'], 'FreeBSD': ['aalib', 'pth'], - 'Suse': ['aalib', 'python-pssh'] + 'Suse': ['aalib', 'python-pssh'], + 'MacOS': ['libpng', 'jpeg'], } _PKG_TARGETS_32 = { From e0abe23c7e146e8e96ab27f1c90f90f38df61fed Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Wed, 2 Mar 2016 23:00:34 -0700 Subject: [PATCH 38/40] states.ssh int tests: run both test cases manually --- tests/integration/states/ssh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/states/ssh.py b/tests/integration/states/ssh.py index 7cda2bb26b..40359f3fe8 100644 --- a/tests/integration/states/ssh.py +++ b/tests/integration/states/ssh.py @@ -246,4 +246,4 @@ class SSHAuthStateTests(integration.ModuleCase, if __name__ == '__main__': from integration import run_tests - run_tests(SSHKnownHostsStateTest) + run_tests([SSHKnownHostsStateTest, SSHAuthStateTests]) From 992a8af726d0b826c8cf40de49d5fb9c0e476e6e Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 15:55:48 -0700 Subject: [PATCH 39/40] renderers.gpg unit tests: mock gpg command --- tests/unit/renderers/gpg_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/renderers/gpg_test.py b/tests/unit/renderers/gpg_test.py index c8adff5a0f..76245ac6ff 100644 --- a/tests/unit/renderers/gpg_test.py +++ b/tests/unit/renderers/gpg_test.py @@ -51,6 +51,7 @@ class GPGTestCase(TestCase): with patch.dict(gpg.__salt__, {'config.get': MagicMock(return_value=False)}): self.assertEqual(gpg._get_key_dir(), def_dir) + @patch('salt.utils.which', MagicMock()) def test__decrypt_ciphertext(self): ''' test _decrypt_ciphertext From e46bac2d98432492e6ae8513ce90cc55c8950162 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 3 Mar 2016 16:16:08 -0700 Subject: [PATCH 40/40] transport.tcp unit tests: disable hanging tests --- tests/unit/transport/tcp_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/transport/tcp_test.py b/tests/unit/transport/tcp_test.py index 0d4a961afc..8e6f45e707 100644 --- a/tests/unit/transport/tcp_test.py +++ b/tests/unit/transport/tcp_test.py @@ -74,6 +74,7 @@ class BaseTCPReqCase(TestCase): del cls.server_channel +@skipIf(salt.utils.is_darwin(), 'hanging test suite on MacOS') class ClearReqTestCases(BaseTCPReqCase, ReqChannelMixin): ''' Test all of the clear msg stuff @@ -90,6 +91,7 @@ class ClearReqTestCases(BaseTCPReqCase, ReqChannelMixin): raise tornado.gen.Return((payload, {'fun': 'send_clear'})) +@skipIf(salt.utils.is_darwin(), 'hanging test suite on MacOS') class AESReqTestCases(BaseTCPReqCase, ReqChannelMixin): def setUp(self): self.channel = salt.transport.client.ReqChannel.factory(self.minion_opts)