From 48cc3497eb19059a7acf14268a722e46b12e59be Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Fri, 21 Apr 2017 15:53:51 +0200
Subject: [PATCH] Use correct grain constants for timezone

Adjust the test so it is using the right grain for SUSE systems

Bugfix: use correct grain constant for platform

Refactor with setup/teardown

Add UT for RedHat's set_zone

Fix doc for RH UT

Remove unnecessary mock patch

Doc fix

Add UT for set_zone on SUSE series

Adjust UT to use correct grain for SUSE series

Bugfix: use correct os_family grain value for SUSE series

Add UT for gentoo on set_zone

Add UT for Debian on set_zone

Remove duplicate code

Add UT for get_hwclock on UTC/localtime

Remove dead code

Add UT for get_hwclock on SUSE platform

Bugfix: use correct grain for SUSE and RedHat platform

Add UT for RedHat/SUSE platforms on get_hwclock

Add UT for Debian on get_hwclock

Add UT on Solaris

Add UT for AIX on get_hwclock

Add UT for set_hwclock on AIX

Fix docstrings

Add UT for set_hwclock on solaris

Add UT for set_hwclock on Arch

Add UT for set_hwclock on RedHat

Fix UT names

Add UT set_hwclock on SUSE

Bugfix: use correct grain name for SUSE platform

Add UT for set_hwclock on Debian

Add UT on set_hw_clock on Gentoo

Fix lint issues

Rewrite test case for using no patch decorators

Disable the test for a while

Do not use multiple variables in "with" statement as of lint issues
---
 salt/modules/timezone.py            |  13 +-
 tests/unit/modules/timezone_test.py | 390 ++++++++++++++++++++++++++++++++++++
 2 files changed, 395 insertions(+), 8 deletions(-)
 create mode 100644 tests/unit/modules/timezone_test.py

diff --git a/salt/modules/timezone.py b/salt/modules/timezone.py
index 69fb4fb663..e0d079f50a 100644
--- a/salt/modules/timezone.py
+++ b/salt/modules/timezone.py
@@ -160,7 +160,7 @@ def get_zone():
         if __grains__['os'].lower() == 'centos':
             return _get_zone_etc_localtime()
         os_family = __grains__['os_family']
-        for family in ('RedHat', 'SUSE'):
+        for family in ('RedHat', 'Suse'):
             if family in os_family:
                 return _get_zone_sysconfig()
         for family in ('Debian', 'Gentoo'):
@@ -273,16 +273,13 @@ def set_zone(timezone):
     if 'RedHat' in __grains__['os_family']:
         __salt__['file.sed'](
             '/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="{0}"'.format(timezone))
-    elif 'SUSE' in __grains__['os_family']:
+    elif 'Suse' in __grains__['os_family']:
         __salt__['file.sed'](
             '/etc/sysconfig/clock', '^TIMEZONE=.*', 'TIMEZONE="{0}"'.format(timezone))
-    elif 'Debian' in __grains__['os_family']:
+    elif 'Debian' in __grains__['os_family'] or 'Gentoo' in __grains__['os_family']:
         with salt.utils.fopen('/etc/timezone', 'w') as ofh:
             ofh.write(timezone.strip())
             ofh.write('\n')
-    elif 'Gentoo' in __grains__['os_family']:
-        with salt.utils.fopen('/etc/timezone', 'w') as ofh:
-            ofh.write(timezone)
 
     return True
 
@@ -373,7 +370,7 @@ def get_hwclock():
 
     else:
         os_family = __grains__['os_family']
-        for family in ('RedHat', 'SUSE'):
+        for family in ('RedHat', 'Suse'):
             if family in os_family:
                 cmd = ['tail', '-n', '1', '/etc/adjtime']
                 return __salt__['cmd.run'](cmd, python_shell=False)
@@ -505,7 +502,7 @@ def set_hwclock(clock):
     elif 'RedHat' in __grains__['os_family']:
         __salt__['file.sed'](
             '/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="{0}"'.format(timezone))
-    elif 'SUSE' in __grains__['os_family']:
+    elif 'Suse' in __grains__['os_family']:
         __salt__['file.sed'](
             '/etc/sysconfig/clock', '^TIMEZONE=.*', 'TIMEZONE="{0}"'.format(timezone))
     elif 'Debian' in __grains__['os_family']:
diff --git a/tests/unit/modules/timezone_test.py b/tests/unit/modules/timezone_test.py
new file mode 100644
index 0000000000..ebf28e28ee
--- /dev/null
+++ b/tests/unit/modules/timezone_test.py
@@ -0,0 +1,390 @@
+# -*- coding: utf-8 -*-
+'''
+    :codeauthor: :email:`Bo Maryniuk <bo@suse.de>`
+'''
+
+# Import Python Libs
+from __future__ import absolute_import
+
+# Import Salt Testing Libs
+from salttesting import TestCase, skipIf
+from salttesting.mock import (
+    MagicMock,
+    patch,
+    NO_MOCK,
+    NO_MOCK_REASON
+)
+
+from salttesting.helpers import ensure_in_syspath
+from salt.exceptions import SaltInvocationError
+
+ensure_in_syspath('../../')
+
+# Import Salt Libs
+from salt.modules import timezone
+
+
+@skipIf(NO_MOCK, NO_MOCK_REASON)
+class TimezoneTestCase(TestCase):
+    '''
+    Timezone test case
+    '''
+    TEST_TZ = 'UTC'
+
+    def setUp(self):
+        '''
+        Setup test
+        :return:
+        '''
+        timezone.__salt__ = {'file.sed': MagicMock(),
+                             'cmd.run': MagicMock(),
+                             'cmd.retcode': MagicMock(return_value=0)}
+        timezone.__grains__ = {'os': 'unknown'}
+
+    def tearDown(self):
+        '''
+        Teardown test
+        :return:
+        '''
+        timezone.__salt__ = timezone.__grains__ = None
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    def test_get_zone_centos(self):
+        '''
+        Test CentOS is recognized
+        :return:
+        '''
+        timezone.__grains__['os'] = 'centos'
+        with patch('salt.modules.timezone._get_zone_etc_localtime', MagicMock(return_value=self.TEST_TZ)):
+            assert timezone.get_zone() == self.TEST_TZ
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    def test_get_zone_os_family_rh_suse(self):
+        '''
+        Test RedHat and Suse are recognized
+        :return:
+        '''
+        for osfamily in ['RedHat', 'Suse']:
+            timezone.__grains__['os_family'] = [osfamily]
+            with patch('salt.modules.timezone._get_zone_sysconfig', MagicMock(return_value=self.TEST_TZ)):
+                assert timezone.get_zone() == self.TEST_TZ
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    def test_get_zone_os_family_debian_gentoo(self):
+        '''
+        Test Debian and Gentoo are recognized
+        :return:
+        '''
+        for osfamily in ['Debian', 'Gentoo']:
+            timezone.__grains__['os_family'] = [osfamily]
+            with patch('salt.modules.timezone._get_zone_etc_timezone', MagicMock(return_value=self.TEST_TZ)):
+                assert timezone.get_zone() == self.TEST_TZ
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    def test_get_zone_os_family_allbsd_nilinuxrt(self):
+        '''
+        Test *BSD and NILinuxRT are recognized
+        :return:
+        '''
+        for osfamily in ['FreeBSD', 'OpenBSD', 'NetBSD', 'NILinuxRT']:
+            timezone.__grains__['os_family'] = osfamily
+            with patch('salt.modules.timezone._get_zone_etc_localtime', MagicMock(return_value=self.TEST_TZ)):
+                assert timezone.get_zone() == self.TEST_TZ
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    def test_get_zone_os_family_slowlaris(self):
+        '''
+        Test Slowlaris is recognized
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Solaris']
+        with patch('salt.modules.timezone._get_zone_solaris', MagicMock(return_value=self.TEST_TZ)):
+            assert timezone.get_zone() == self.TEST_TZ
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    def test_get_zone_os_family_aix(self):
+        '''
+        Test IBM AIX is recognized
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['AIX']
+        with patch('salt.modules.timezone._get_zone_aix', MagicMock(return_value=self.TEST_TZ)):
+            assert timezone.get_zone() == self.TEST_TZ
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_set_zone_redhat(self):
+        '''
+        Test zone set on RH series
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['RedHat']
+        assert timezone.set_zone(self.TEST_TZ)
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[0]
+        assert args == ('/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="UTC"')
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_set_zone_suse(self):
+        '''
+        Test zone set on SUSE series
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Suse']
+        assert timezone.set_zone(self.TEST_TZ)
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[0]
+        assert args == ('/etc/sysconfig/clock', '^TIMEZONE=.*', 'TIMEZONE="UTC"')
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_set_zone_gentoo(self):
+        '''
+        Test zone set on Gentoo series
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Gentoo']
+        _fopen = MagicMock(return_value=MagicMock(spec=file))
+        with patch('salt.utils.fopen', _fopen):
+            assert timezone.set_zone(self.TEST_TZ)
+            name, args, kwargs = _fopen.mock_calls[0]
+            assert args == ('/etc/timezone', 'w')
+            name, args, kwargs = _fopen.return_value.__enter__.return_value.write.mock_calls[0]
+            assert args == ('UTC',)
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_set_zone_debian(self):
+        '''
+        Test zone set on Debian series
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Debian']
+        _fopen = MagicMock(return_value=MagicMock(spec=file))
+        with patch('salt.utils.fopen', _fopen):
+            assert timezone.set_zone(self.TEST_TZ)
+            name, args, kwargs = _fopen.mock_calls[0]
+            assert args == ('/etc/timezone', 'w')
+            name, args, kwargs = _fopen.return_value.__enter__.return_value.write.mock_calls[0]
+            assert args == ('UTC',)
+
+    @patch('salt.utils.which', MagicMock(return_value=True))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_get_hwclock_timedate_utc(self):
+        '''
+        Test get hwclock UTC/localtime
+        :return:
+        '''
+        with patch('salt.modules.timezone._timedatectl', MagicMock(return_value={'stdout': 'rtc in local tz'})):
+            assert timezone.get_hwclock() == 'UTC'
+        with patch('salt.modules.timezone._timedatectl', MagicMock(return_value={'stdout': 'rtc in local tz:yes'})):
+            assert timezone.get_hwclock() == 'localtime'
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_get_hwclock_suse(self):
+        '''
+        Test get hwclock on SUSE
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Suse']
+        timezone.get_hwclock()
+        name, args, kwarg = timezone.__salt__['cmd.run'].mock_calls[0]
+        assert args == (['tail', '-n', '1', '/etc/adjtime'],)
+        assert kwarg == {'python_shell': False}
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_get_hwclock_redhat(self):
+        '''
+        Test get hwclock on RedHat
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['RedHat']
+        timezone.get_hwclock()
+        name, args, kwarg = timezone.__salt__['cmd.run'].mock_calls[0]
+        assert args == (['tail', '-n', '1', '/etc/adjtime'],)
+        assert kwarg == {'python_shell': False}
+
+    def _test_get_hwclock_debian(self):  # TODO: Enable this when testing environment is working properly
+        '''
+        Test get hwclock on Debian
+        :return:
+        '''
+        with patch('salt.utils.which', MagicMock(return_value=False)):
+            with patch('os.path.exists', MagicMock(return_value=True)):
+                with patch('os.unlink', MagicMock()):
+                    with patch('os.symlink', MagicMock()):
+                        timezone.__grains__['os_family'] = ['Debian']
+                        timezone.get_hwclock()
+                        name, args, kwarg = timezone.__salt__['cmd.run'].mock_calls[0]
+                        assert args == (['tail', '-n', '1', '/etc/adjtime'],)
+                        assert kwarg == {'python_shell': False}
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_get_hwclock_solaris(self):
+        '''
+        Test get hwclock on Solaris
+        :return:
+        '''
+        # Incomplete
+        timezone.__grains__['os_family'] = ['Solaris']
+        assert timezone.get_hwclock() == 'UTC'
+        _fopen = MagicMock(return_value=MagicMock(spec=file))
+        with patch('salt.utils.fopen', _fopen):
+            assert timezone.get_hwclock() == 'localtime'
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_get_hwclock_aix(self):
+        '''
+        Test get hwclock on AIX
+        :return:
+        '''
+        # Incomplete
+        timezone.__grains__['os_family'] = ['AIX']
+        assert timezone.get_hwclock() == 'localtime'
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    def test_set_hwclock_aix(self):
+        '''
+        Test set hwclock on AIX
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['AIX']
+        with self.assertRaises(SaltInvocationError):
+            assert timezone.set_hwclock('forty two')
+        assert timezone.set_hwclock('UTC')
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    @patch('salt.modules.timezone.get_zone', MagicMock(return_value='TEST_TIMEZONE'))
+    def test_set_hwclock_solaris(self):
+        '''
+        Test set hwclock on Solaris
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Solaris']
+        timezone.__grains__['cpuarch'] = 'x86'
+
+        with self.assertRaises(SaltInvocationError):
+            assert timezone.set_hwclock('forty two')
+        assert timezone.set_hwclock('UTC')
+        name, args, kwargs = timezone.__salt__['cmd.retcode'].mock_calls[0]
+        assert args == (['rtc', '-z', 'GMT'],)
+        assert kwargs == {'python_shell': False}
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    @patch('salt.modules.timezone.get_zone', MagicMock(return_value='TEST_TIMEZONE'))
+    def test_set_hwclock_arch(self):
+        '''
+        Test set hwclock on arch
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Arch']
+
+        assert timezone.set_hwclock('UTC')
+        name, args, kwargs = timezone.__salt__['cmd.retcode'].mock_calls[0]
+        assert args == (['timezonectl', 'set-local-rtc', 'false'],)
+        assert kwargs == {'python_shell': False}
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    @patch('salt.modules.timezone.get_zone', MagicMock(return_value='TEST_TIMEZONE'))
+    def test_set_hwclock_redhat(self):
+        '''
+        Test set hwclock on RedHat
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['RedHat']
+
+        assert timezone.set_hwclock('UTC')
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[0]
+        assert args == ('/etc/sysconfig/clock', '^ZONE=.*', 'ZONE="TEST_TIMEZONE"')
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    @patch('salt.modules.timezone.get_zone', MagicMock(return_value='TEST_TIMEZONE'))
+    def test_set_hwclock_suse(self):
+        '''
+        Test set hwclock on SUSE
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Suse']
+
+        assert timezone.set_hwclock('UTC')
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[0]
+        assert args == ('/etc/sysconfig/clock', '^TIMEZONE=.*', 'TIMEZONE="TEST_TIMEZONE"')
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    @patch('salt.modules.timezone.get_zone', MagicMock(return_value='TEST_TIMEZONE'))
+    def test_set_hwclock_debian(self):
+        '''
+        Test set hwclock on Debian
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Debian']
+
+        assert timezone.set_hwclock('UTC')
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[0]
+        assert args == ('/etc/default/rcS', '^UTC=.*', 'UTC=yes')
+
+        assert timezone.set_hwclock('localtime')
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[1]
+        assert args == ('/etc/default/rcS', '^UTC=.*', 'UTC=no')
+
+    @patch('salt.utils.which', MagicMock(return_value=False))
+    @patch('os.path.exists', MagicMock(return_value=True))
+    @patch('os.unlink', MagicMock())
+    @patch('os.symlink', MagicMock())
+    @patch('salt.modules.timezone.get_zone', MagicMock(return_value='TEST_TIMEZONE'))
+    def test_set_hwclock_gentoo(self):
+        '''
+        Test set hwclock on Gentoo
+        :return:
+        '''
+        timezone.__grains__['os_family'] = ['Gentoo']
+
+        with self.assertRaises(SaltInvocationError):
+            timezone.set_hwclock('forty two')
+
+        timezone.set_hwclock('UTC')
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[0]
+        assert args == ('/etc/conf.d/hwclock', '^clock=.*', 'clock="UTC"')
+
+        timezone.set_hwclock('localtime')
+        name, args, kwargs = timezone.__salt__['file.sed'].mock_calls[1]
+        assert args == ('/etc/conf.d/hwclock', '^clock=.*', 'clock="local"')
-- 
2.11.0


