diff --git a/salt/modules/win_pkg.py b/salt/modules/win_pkg.py index 74876c4159ba..622fbb12a20a 100644 --- a/salt/modules/win_pkg.py +++ b/salt/modules/win_pkg.py @@ -478,7 +478,7 @@ def _get_reg_software(include_components=True, # https://github.com/aws/amazon-ssm-agent/blob/master/agent/plugins/inventory/gatherers/application/dataProvider_windows.go reg_software = {} - def skip_component(hive, key, sub_key, use_32bit): + def skip_component(hive, key, sub_key, use_32bit_registry): ''' 'SystemComponent' must be either absent or present with a value of 0, because this value is usually set on programs that have been installed @@ -493,16 +493,16 @@ def skip_component(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='SystemComponent', - use_32bit_registry=use_32bit): + use_32bit_registry=use_32bit_registry): if __utils__['reg.read_value']( hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='SystemComponent', - use_32bit_registry=use_32bit)['vdata'] > 0: + use_32bit_registry=use_32bit_registry)['vdata'] > 0: return True return False - def skip_win_installer(hive, key, sub_key, use_32bit): + def skip_win_installer(hive, key, sub_key, use_32bit_registry): ''' 'WindowsInstaller' must be either absent or present with a value of 0. If the value is set to 1, then the application is included in the list @@ -517,21 +517,21 @@ def skip_win_installer(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='WindowsInstaller', - use_32bit_registry=use_32bit): + use_32bit_registry=use_32bit_registry): if __utils__['reg.read_value']( hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='WindowsInstaller', - use_32bit_registry=use_32bit)['vdata'] > 0: + use_32bit_registry=use_32bit_registry)['vdata'] > 0: squid = salt.utils.win_functions.guid_to_squid(sub_key) if not __utils__['reg.key_exists']( hive='HKLM', key=products_key.format(squid), - use_32bit_registry=use_32bit): + use_32bit_registry=use_32bit_registry): return True return False - def skip_uninstall_string(hive, key, sub_key, use_32bit): + def skip_uninstall_string(hive, key, sub_key, use_32bit_registry): ''' 'UninstallString' must be present, because it stores the command line that gets executed by Add/Remove programs, when the user tries to @@ -544,11 +544,11 @@ def skip_uninstall_string(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='UninstallString', - use_32bit_registry=use_32bit): + use_32bit_registry=use_32bit_registry): return True return False - def skip_release_type(hive, key, sub_key, use_32bit): + def skip_release_type(hive, key, sub_key, use_32bit_registry): ''' 'ReleaseType' must either be absent or if present must not have a value set to 'Security Update', 'Update Rollup', or 'Hotfix', because @@ -566,16 +566,16 @@ def skip_release_type(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='ReleaseType', - use_32bit_registry=use_32bit): + use_32bit_registry=use_32bit_registry): if __utils__['reg.read_value']( hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='ReleaseType', - use_32bit_registry=use_32bit)['vdata'] in skip_types: + use_32bit_registry=use_32bit_registry)['vdata'] in skip_types: return True return False - def skip_parent_key(hive, key, sub_key, use_32bit): + def skip_parent_key(hive, key, sub_key, use_32bit_registry): ''' 'ParentKeyName' must NOT be present, because that indicates it's an update to the parent program. @@ -587,12 +587,12 @@ def skip_parent_key(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='ParentKeyName', - use_32bit_registry=use_32bit): + use_32bit_registry=use_32bit_registry): return True return False - def add_software(hive, key, sub_key, use_32bit): + def add_software(hive, key, sub_key, use_32bit_registry): ''' 'DisplayName' must be present with a valid value, as this is reflected as the software name returned by pkg.list_pkgs. Also, its value must @@ -603,7 +603,7 @@ def add_software(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='DisplayName', - use_32bit_registry=use_32bit) + use_32bit_registry=use_32bit_registry) if (not d_name_regdata['success'] or d_name_regdata['vtype'] not in ['REG_SZ', 'REG_EXPAND_SZ'] or @@ -619,7 +619,7 @@ def add_software(hive, key, sub_key, use_32bit): hive=hive, key='{0}\\{1}'.format(key, sub_key), vname='DisplayVersion', - use_32bit_registry=use_32bit) + use_32bit_registry=use_32bit_registry) d_vers = 'Not Found' if (d_vers_regdata['success'] and @@ -635,9 +635,8 @@ def add_software(hive, key, sub_key, use_32bit): # HKLM Uninstall 64 bit kwargs = {'hive': 'HKLM', 'key': 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall', - 'use_32bit': False} - for sub_key in __utils__['reg.list_keys'](hive=kwargs['hive'], - key=kwargs['key']): + 'use_32bit_registry': False} + for sub_key in __utils__['reg.list_keys'](**kwargs): kwargs['sub_key'] = sub_key if skip_component(**kwargs): continue @@ -652,10 +651,9 @@ def add_software(hive, key, sub_key, use_32bit): add_software(**kwargs) # HKLM Uninstall 32 bit - kwargs['use_32bit'] = True - for sub_key in __utils__['reg.list_keys'](hive=kwargs['hive'], - key=kwargs['key'], - use_32bit_registry=kwargs['use_32bit']): + kwargs['use_32bit_registry'] = True + kwargs.pop('sub_key', False) + for sub_key in __utils__['reg.list_keys'](**kwargs): kwargs['sub_key'] = sub_key if skip_component(**kwargs): continue @@ -672,10 +670,10 @@ def add_software(hive, key, sub_key, use_32bit): # HKLM Uninstall 64 bit kwargs = {'hive': 'HKLM', 'key': 'Software\\Classes\\Installer\\Products', - 'use_32bit': False} + 'use_32bit_registry': False} userdata_key = 'Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\' \ 'UserData\\S-1-5-18\\Products' - for sub_key in __utils__['reg.list_keys'](hive=kwargs['hive'], key=kwargs['key']): + for sub_key in __utils__['reg.list_keys'](**kwargs): # If the key does not exist in userdata, skip it if not __utils__['reg.key_exists']( hive=kwargs['hive'], @@ -699,72 +697,73 @@ def add_software(hive, key, sub_key, use_32bit): for user_guid in __utils__['reg.list_keys'](hive=hive_hku): kwargs = {'hive': hive_hku, 'key': uninstall_key.format(user_guid), - 'use_32bit': False} - for sub_key in __utils__['reg.list_keys'](hive=kwargs['hive'], - key=kwargs['key']): - kwargs['sub_key'] = sub_key - if skip_component(**kwargs): - continue - if skip_win_installer(**kwargs): - continue - if skip_uninstall_string(**kwargs): - continue - if skip_release_type(**kwargs): - continue - if skip_parent_key(**kwargs): - continue - add_software(**kwargs) - - # While we have the user guid, we're gong to check userdata in HKLM - for sub_key in __utils__['reg.list_keys'](hive=hive_hku, - key=product_key.format(user_guid)): - kwargs = {'hive': 'HKLM', - 'key': user_data_key.format(user_guid, sub_key), - 'sub_key': 'InstallProperties', - 'use_32bit': False} - if __utils__['reg.key_exists'](hive=kwargs['hive'], - key=kwargs['key']): + 'use_32bit_registry': False} + if __utils__['reg.key_exists'](**kwargs): + for sub_key in __utils__['reg.list_keys'](**kwargs): + kwargs['sub_key'] = sub_key if skip_component(**kwargs): continue + if skip_win_installer(**kwargs): + continue + if skip_uninstall_string(**kwargs): + continue + if skip_release_type(**kwargs): + continue + if skip_parent_key(**kwargs): + continue add_software(**kwargs) + # While we have the user guid, we're gong to check userdata in HKLM + kwargs = {'hive': hive_hku, + 'key': product_key.format(user_guid), + 'use_32bit_registry': False} + if __utils__['reg.key_exists'](**kwargs): + for sub_key in __utils__['reg.list_keys'](**kwargs): + kwargs = {'hive': 'HKLM', + 'key': user_data_key.format(user_guid, sub_key), + 'use_32bit_registry': False} + if __utils__['reg.key_exists'](**kwargs): + kwargs['sub_key'] = 'InstallProperties' + if skip_component(**kwargs): + continue + add_software(**kwargs) + # Uninstall for each user on the system (HKU), 32 bit for user_guid in __utils__['reg.list_keys'](hive=hive_hku, use_32bit_registry=True): kwargs = {'hive': hive_hku, 'key': uninstall_key.format(user_guid), - 'use_32bit': True} - for sub_key in __utils__['reg.list_keys'](hive=kwargs['hive'], - key=kwargs['key'], - use_32bit_registry=kwargs['use_32bit']): - kwargs['sub_key'] = sub_key - if skip_component(**kwargs): - continue - if skip_win_installer(**kwargs): - continue - if skip_uninstall_string(**kwargs): - continue - if skip_release_type(**kwargs): - continue - if skip_parent_key(**kwargs): - continue - add_software(**kwargs) - - # While we have the user guid, we're gong to check userdata in HKLM - for sub_key_2 in __utils__['reg.list_keys'](hive=hive_hku, - key=product_key.format(user_guid), - use_32bit_registry=True): - kwargs = {'hive': 'HKLM', - 'key': user_data_key.format(user_guid, sub_key_2), - 'sub_key': 'InstallProperties', - 'use_32bit': True} - if __utils__['reg.key_exists'](hive=kwargs['hive'], - key=kwargs['key'], - use_32bit_registry=kwargs['use_32bit']): + 'use_32bit_registry': True} + if __utils__['reg.key_exists'](**kwargs): + for sub_key in __utils__['reg.list_keys'](**kwargs): + kwargs['sub_key'] = sub_key if skip_component(**kwargs): continue + if skip_win_installer(**kwargs): + continue + if skip_uninstall_string(**kwargs): + continue + if skip_release_type(**kwargs): + continue + if skip_parent_key(**kwargs): + continue add_software(**kwargs) + kwargs = {'hive': hive_hku, + 'key': product_key.format(user_guid), + 'use_32bit_registry': True} + if __utils__['reg.key_exists'](**kwargs): + # While we have the user guid, we're going to check userdata in HKLM + for sub_key_2 in __utils__['reg.list_keys'](**kwargs): + kwargs = {'hive': 'HKLM', + 'key': user_data_key.format(user_guid, sub_key_2), + 'use_32bit_registry': True} + if __utils__['reg.key_exists'](**kwargs): + kwargs['sub_key'] = 'InstallProperties' + if skip_component(**kwargs): + continue + add_software(**kwargs) + return reg_software diff --git a/salt/utils/win_reg.py b/salt/utils/win_reg.py index 40c45c4d77aa..ce2054a0a575 100644 --- a/salt/utils/win_reg.py +++ b/salt/utils/win_reg.py @@ -39,7 +39,6 @@ import win32gui import win32api import win32con - import pywintypes HAS_WINDOWS_MODULES = True except ImportError: HAS_WINDOWS_MODULES = False @@ -198,7 +197,7 @@ def key_exists(hive, key, use_32bit_registry=False): try: handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask) return True - except pywintypes.error as exc: + except win32api.error as exc: if exc.winerror == 2: return False raise @@ -231,7 +230,9 @@ def value_exists(hive, key, vname, use_32bit_registry=False): .. code-block:: python import salt.utils.win_reg - winreg.key_exists(hive='HKLM', key='SOFTWARE\\Microsoft') + winreg.value_exists(hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='CommonFilesDir') ''' local_hive = _to_unicode(hive) local_key = _to_unicode(key) @@ -246,7 +247,7 @@ def value_exists(hive, key, vname, use_32bit_registry=False): try: handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask) - except pywintypes.error as exc: + except win32api.error as exc: if exc.winerror == 2: # The key containing the value/data pair does not exist return False @@ -257,7 +258,7 @@ def value_exists(hive, key, vname, use_32bit_registry=False): _, _ = win32api.RegQueryValueEx(handle, local_vname) # value/data pair exists return True - except pywintypes.error as exc: + except win32api.error as exc: if exc.winerror == 2 and vname is None: # value/data pair exists but is empty return True @@ -349,9 +350,12 @@ def list_keys(hive, key=None, use_32bit_registry=False): else: subkeys.append(subkey) - except Exception: # pylint: disable=broad-except - log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True) - return False, r'Cannot find key: {0}\{1}'.format(hive, key) + except win32api.error as exc: + if exc.winerror == 2: + log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True) + return False, r'Cannot find key: {0}\{1}'.format(hive, key) + raise + finally: if handle: handle.Close() @@ -359,10 +363,14 @@ def list_keys(hive, key=None, use_32bit_registry=False): return subkeys -def list_values(hive, key=None, use_32bit_registry=False, include_default=True): +def list_values(hive, key=None, use_32bit_registry=False): ''' Enumerates the values in a registry key or hive. + .. note:: + The ``(Default)`` value will only be returned if it is set, otherwise it + will not be returned in the list of values. + Args: hive (str): @@ -382,9 +390,6 @@ def list_values(hive, key=None, use_32bit_registry=False, include_default=True): Accesses the 32bit portion of the registry on 64 bit installations. On 32bit machines this is ignored. - include_default (bool): - Toggle whether to include the '(Default)' value. - Returns: list: A list of values under the hive or key. @@ -429,9 +434,13 @@ def list_values(hive, key=None, use_32bit_registry=False, include_default=True): else: value['vdata'] = vdata values.append(value) - except Exception as exc: # pylint: disable=broad-except - log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True) - return False, r'Cannot find key: {0}\{1}'.format(hive, key) + + except win32api.error as exc: + if exc.winerror == 2: + log.debug(r'Cannot find key: %s\%s', hive, key) + return False, r'Cannot find key: {0}\{1}'.format(hive, key) + raise + finally: if handle: handle.Close() @@ -535,23 +544,28 @@ def read_value(hive, key, vname=None, use_32bit_registry=False): ret['vdata'] = vdata else: ret['comment'] = 'Empty Value' - except Exception as exc: # pylint: disable=broad-except + except win32api.error as exc: if exc.winerror == 2 and vname is None: ret['vdata'] = ('(value not set)') ret['vtype'] = 'REG_SZ' - else: + elif exc.winerror == 2: msg = 'Cannot find {0} in {1}\\{2}' \ ''.format(local_vname, local_hive, local_key) log.trace(exc) log.trace(msg) ret['comment'] = msg ret['success'] = False - except Exception as exc: # pylint: disable=broad-except - msg = 'Cannot find key: {0}\\{1}'.format(local_hive, local_key) - log.trace(exc) - log.trace(msg) - ret['comment'] = msg - ret['success'] = False + else: + raise + except win32api.error as exc: + if exc.winerror == 2: + msg = 'Cannot find key: {0}\\{1}'.format(local_hive, local_key) + log.trace(exc) + log.trace(msg) + ret['comment'] = msg + ret['success'] = False + else: + raise return ret @@ -705,15 +719,30 @@ def set_value(hive, handle = None try: - handle, _ = win32api.RegCreateKeyEx(hkey, local_key, access_mask, - Options=create_options) - win32api.RegSetValueEx(handle, local_vname, 0, vtype_value, local_vdata) - win32api.RegFlushKey(handle) - broadcast_change() - return True - except (win32api.error, SystemError, ValueError, TypeError): # pylint: disable=E0602 - log.exception('Encountered error setting registry value') + handle, result = win32api.RegCreateKeyEx(hkey, local_key, access_mask, + Options=create_options) + msg = 'Created new key: %s\\%s' if result == 1 else \ + 'Opened existing key: %s\\%s' + log.debug(msg, local_hive, local_key) + + try: + win32api.RegSetValueEx(handle, local_vname, 0, vtype_value, local_vdata) + win32api.RegFlushKey(handle) + broadcast_change() + return True + except TypeError as exc: + log.exception('"vdata" does not match the expected data type.\n%s', + exc) + return False + except (SystemError, ValueError) as exc: + log.exception('Encountered error setting registry value.\n%s', exc) + return False + + except win32api.error as exc: + log.exception('Error creating/opening key: %s\\%s\n%s', local_hive, + local_key, exc.winerror) return False + finally: if handle: win32api.RegCloseKey(handle) @@ -771,7 +800,7 @@ def cast_vdata(vdata=None, vtype='REG_SZ'): return [_to_unicode(i) for i in vdata] # Make sure REG_QWORD is a 64 bit integer elif vtype_value == win32con.REG_QWORD: - return vdata if six.PY3 else long(vdata) # pylint: disable=undefined-variable,incompatible-py3-code + return int(vdata) if six.PY3 else long(vdata) # pylint: disable=undefined-variable,incompatible-py3-code # Everything else is int else: return int(vdata) @@ -829,13 +858,12 @@ def delete_key_recursive(hive, key, use_32bit_registry=False): access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS if not key_exists(local_hive, local_key, use_32bit_registry): + log.debug('"%s\\%s" not found', hive, key) return False if (len(key) > 1) and (key.count('\\', 1) < registry.subkey_slash_check[hkey]): log.error( - 'Hive:%s Key:%s; key is too close to root, not safe to remove', - hive, key - ) + '"%s\\%s" is too close to root, not safe to remove', hive, key) return False # Functions for traversing the registry tree @@ -849,7 +877,7 @@ def _subkeys(_key): subkey = win32api.RegEnumKey(_key, i) yield _to_mbcs(subkey) i += 1 - except Exception: # pylint: disable=broad-except + except win32api.error: break def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask): @@ -874,13 +902,21 @@ def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask): # Delete all sub_keys for sub_key_path in key_list: + key_handle = None try: key_handle = win32api.RegOpenKeyEx(hkey, sub_key_path, 0, access_mask) - win32api.RegDeleteKey(key_handle, '') - ret['Deleted'].append(r'{0}\{1}'.format(hive, sub_key_path)) - except WindowsError as exc: # pylint: disable=E0602 + try: + win32api.RegDeleteKey(key_handle, '') + ret['Deleted'].append(r'{0}\{1}'.format(hive, sub_key_path)) + except WindowsError as exc: # pylint: disable=undefined-variable + log.error(exc, exc_info=True) + ret['Failed'].append(r'{0}\{1} {2}'.format(hive, sub_key_path, exc)) + except win32api.error as exc: log.error(exc, exc_info=True) - ret['Failed'].append(r'{0}\{1} {2}'.format(hive, sub_key_path, exc)) + ret['Failed'].append(r'{0}\{1} {2}'.format(hive, sub_key_path, exc.strerror)) + finally: + if key_handle: + win32api.CloseHandle(key_handle) broadcast_change() @@ -940,16 +976,10 @@ def delete_value(hive, key, vname=None, use_32bit_registry=False): win32api.RegDeleteValue(handle, local_vname) broadcast_change() return True - except Exception as exc: # pylint: disable=broad-except + except win32api.error as exc: if exc.winerror == 2: return None - else: - log.error(exc, exc_info=True) - log.error('Hive: %s', local_hive) - log.error('Key: %s', local_key) - log.error('ValueName: %s', local_vname) - log.error('32bit Reg: %s', use_32bit_registry) - return False + raise finally: if handle: win32api.RegCloseKey(handle) diff --git a/tests/unit/modules/test_win_pkg.py b/tests/unit/modules/test_win_pkg.py index e0dedb9520bc..18f4f6ca8241 100644 --- a/tests/unit/modules/test_win_pkg.py +++ b/tests/unit/modules/test_win_pkg.py @@ -17,6 +17,10 @@ import salt.modules.win_pkg as win_pkg import salt.utils.data import salt.utils.platform +import salt.utils.win_reg as win_reg + +# Import 3rd Party Libs +from salt.ext import six @skipIf(not salt.utils.platform.is_windows(), "Must be on Windows!") @@ -57,6 +61,12 @@ def setup_loader_modules(self): 'pkg_resource.stringify': pkg_resource.stringify, 'config.valid_fileproto': config.valid_fileproto, }, + '__utils__': { + 'reg.key_exists': win_reg.key_exists, + 'reg.list_keys': win_reg.list_keys, + 'reg.read_value': win_reg.read_value, + 'reg.value_exists': win_reg.value_exists, + }, }, pkg_resource: { '__grains__': { @@ -65,6 +75,16 @@ def setup_loader_modules(self): }, } + def test_pkg__get_reg_software(self): + result = win_pkg._get_reg_software() + self.assertTrue(isinstance(result, dict)) + found_python = False + search = 'Python 2' if six.PY2 else 'Python 3' + for key in result: + if search in key: + found_python = True + self.assertTrue(found_python) + def test_pkg_install_not_found(self): ''' Test pkg.install when the Version is NOT FOUND in the Software diff --git a/tests/unit/utils/test_win_reg.py b/tests/unit/utils/test_win_reg.py index 61c704c56a38..728800ad0dcc 100644 --- a/tests/unit/utils/test_win_reg.py +++ b/tests/unit/utils/test_win_reg.py @@ -2,24 +2,31 @@ # Import Python Libs from __future__ import absolute_import, unicode_literals, print_function -from salt.ext import six # Import Salt Testing Libs from tests.support.helpers import destructiveTest, generate_random_name -from tests.support.mock import patch +from tests.support.mock import patch, MagicMock from tests.support.unit import TestCase, skipIf # Import Salt Libs -import salt.utils.platform +import salt.utils.stringutils import salt.utils.win_reg as win_reg +from salt.exceptions import CommandExecutionError +from salt.ext import six + +try: + import win32api + HAS_WIN32 = True +except ImportError: + HAS_WIN32 = False UNICODE_KEY = 'Unicode Key \N{TRADE MARK SIGN}' UNICODE_VALUE = 'Unicode Value ' \ '\N{COPYRIGHT SIGN},\N{TRADE MARK SIGN},\N{REGISTERED SIGN}' -FAKE_KEY = 'SOFTWARE\\{0}'.format(generate_random_name('SaltTesting-')) +FAKE_KEY = '\\'.join(['SOFTWARE', generate_random_name('SaltTesting-')]) -@skipIf(not salt.utils.platform.is_windows(), 'System is not Windows') +@skipIf(not HAS_WIN32, 'Tests require win32 libraries') class WinFunctionsTestCase(TestCase): ''' Test cases for salt.utils.win_reg @@ -29,38 +36,132 @@ def test_broadcast_change_success(self): Tests the broadcast_change function ''' with patch('win32gui.SendMessageTimeout', return_value=('', 0)): - self.assertEqual(win_reg.broadcast_change(), True) + self.assertTrue(win_reg.broadcast_change()) def test_broadcast_change_fail(self): ''' Tests the broadcast_change function failure ''' with patch('win32gui.SendMessageTimeout', return_value=('', 1)): - self.assertEqual(win_reg.broadcast_change(), False) + self.assertFalse(win_reg.broadcast_change()) def test_key_exists_existing(self): ''' - Tests the key exists function using a well known registry key + Tests the key_exists function using a well known registry key ''' - self.assertEqual( - win_reg.key_exists( - hive='HKLM', - key='SOFTWARE\\Microsoft' - ), - True - ) + self.assertTrue( + win_reg.key_exists(hive='HKLM', key='SOFTWARE\\Microsoft')) def test_key_exists_non_existing(self): ''' - Tests the key exists function using a non existing registry key + Tests the key_exists function using a non existing registry key + ''' + self.assertFalse(win_reg.key_exists(hive='HKLM', key=FAKE_KEY)) + + def test_key_exists_invalid_hive(self): + ''' + Tests the key_exists function using an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.key_exists, + hive='BADHIVE', + key='SOFTWARE\\Microsoft') + + def test_key_exists_unknown_key_error(self): + ''' + Tests the key_exists function with an unknown key error + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertRaises(win32api.error, + win_reg.key_exists, + hive='HKLM', + key='SOFTWARE\\Microsoft') + + def test_value_exists_existing(self): + ''' + Tests the value_exists function using a well known registry key + ''' + self.assertTrue( + win_reg.value_exists( + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='CommonFilesDir')) + + def test_value_exists_non_existing(self): + ''' + Tests the value_exists function using a non existing registry key ''' - self.assertEqual( - win_reg.key_exists( + self.assertFalse( + win_reg.value_exists( hive='HKLM', - key=FAKE_KEY - ), - False - ) + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='NonExistingValueName')) + + def test_value_exists_invalid_hive(self): + ''' + Tests the value_exists function using an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.value_exists, + hive='BADHIVE', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='CommonFilesDir') + + def test_value_exists_key_not_exist(self): + ''' + Tests the value_exists function when the key does not exist + ''' + mock_error = MagicMock( + side_effect=win32api.error(2, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertFalse( + win_reg.value_exists( + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='CommonFilesDir')) + + def test_value_exists_unknown_key_error(self): + ''' + Tests the value_exists function with an unknown error when opening the + key + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertRaises( + win32api.error, + win_reg.value_exists, + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='CommonFilesDir') + + def test_value_exists_empty_default_value(self): + ''' + Tests the value_exists function when querying the default value + ''' + mock_error = MagicMock( + side_effect=win32api.error(2, 'RegQueryValueEx', 'Empty Value')) + with patch('salt.utils.win_reg.win32api.RegQueryValueEx', mock_error): + self.assertTrue( + win_reg.value_exists( + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname=None)) + + def test_value_exists_no_vname(self): + ''' + Tests the value_exists function when the vname does not exist + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegQueryValueEx', 'Empty Value')) + with patch('salt.utils.win_reg.win32api.RegQueryValueEx', mock_error): + self.assertFalse( + win_reg.value_exists( + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='NonExistingValuePair')) def test_list_keys_existing(self): ''' @@ -68,24 +169,35 @@ def test_list_keys_existing(self): ''' self.assertIn( 'Microsoft', - win_reg.list_keys( - hive='HKLM', - key='SOFTWARE' - ) - ) + win_reg.list_keys(hive='HKLM', key='SOFTWARE')) def test_list_keys_non_existing(self): ''' Test the list_keys function using a non existing registry key ''' expected = (False, 'Cannot find key: HKLM\\{0}'.format(FAKE_KEY)) - self.assertEqual( - win_reg.list_keys( - hive='HKLM', - key=FAKE_KEY - ), - expected - ) + self.assertEqual(win_reg.list_keys(hive='HKLM', key=FAKE_KEY), expected) + + def test_list_keys_invalid_hive(self): + ''' + Test the list_keys function when passing an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.list_keys, + hive='BADHIVE', + key='SOFTWARE\\Microsoft') + + def test_list_keys_unknown_key_error(self): + ''' + Tests the list_keys function with an unknown key error + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertRaises(win32api.error, + win_reg.list_keys, + hive='HKLM', + key='SOFTWARE\\Microsoft') def test_list_values_existing(self): ''' @@ -93,8 +205,7 @@ def test_list_values_existing(self): ''' values = win_reg.list_values( hive='HKLM', - key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion' - ) + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion') keys = [] for value in values: keys.append(value['vname']) @@ -105,13 +216,29 @@ def test_list_values_non_existing(self): Test the list_values function using a non existing registry key ''' expected = (False, 'Cannot find key: HKLM\\{0}'.format(FAKE_KEY)) - self.assertEqual( - win_reg.list_values( - hive='HKLM', - key=FAKE_KEY - ), - expected - ) + self.assertEqual(win_reg.list_values(hive='HKLM', key=FAKE_KEY), + expected) + + def test_list_values_invalid_hive(self): + ''' + Test the list_values function when passing an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.list_values, + hive='BADHIVE', + key='SOFTWARE\\Microsoft') + + def test_list_values_unknown_key_error(self): + ''' + Tests the list_values function with an unknown key error + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertRaises(win32api.error, + win_reg.list_values, + hive='HKLM', + key='SOFTWARE\\Microsoft') def test_read_value_existing(self): ''' @@ -120,8 +247,7 @@ def test_read_value_existing(self): ret = win_reg.read_value( hive='HKLM', key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', - vname='ProgramFilesPath' - ) + vname='ProgramFilesPath') self.assertEqual(ret['vdata'], '%ProgramFiles%') def test_read_value_default(self): @@ -131,8 +257,7 @@ def test_read_value_default(self): ''' ret = win_reg.read_value( hive='HKLM', - key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion' - ) + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion') self.assertEqual(ret['vdata'], '(value not set)') def test_read_value_non_existing(self): @@ -140,21 +265,19 @@ def test_read_value_non_existing(self): Test the read_value function using a non existing value pair ''' expected = { - 'comment': 'Cannot find fake_name in HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + 'comment': 'Cannot find fake_name in HKLM\\SOFTWARE\\Microsoft\\' + 'Windows\\CurrentVersion', 'vdata': None, 'vname': 'fake_name', 'success': False, 'hive': 'HKLM', - 'key': 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion' - } - self.assertEqual( + 'key': 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'} + self.assertDictEqual( win_reg.read_value( hive='HKLM', key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', - vname='fake_name' - ), - expected - ) + vname='fake_name'), + expected) def test_read_value_non_existing_key(self): ''' @@ -166,16 +289,51 @@ def test_read_value_non_existing_key(self): 'vname': 'fake_name', 'success': False, 'hive': 'HKLM', - 'key': FAKE_KEY - } - self.assertEqual( + 'key': FAKE_KEY} + self.assertDictEqual( win_reg.read_value( hive='HKLM', key=FAKE_KEY, - vname='fake_name' - ), - expected - ) + vname='fake_name'), + expected) + + def test_read_value_invalid_hive(self): + ''' + Test the read_value function when passing an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.read_value, + hive='BADHIVE', + key='SOFTWARE\\Microsoft', + vname='ProgramFilesPath') + + def test_read_value_unknown_key_error(self): + ''' + Tests the read_value function with an unknown key error + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertRaises( + win32api.error, + win_reg.read_value, + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='ProgramFilesPath') + + def test_read_value_unknown_value_error(self): + ''' + Tests the read_value function with an unknown value error + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegQueryValueEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegQueryValueEx', mock_error): + self.assertRaises( + win32api.error, + win_reg.read_value, + hive='HKLM', + key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion', + vname='ProgramFilesPath') @destructiveTest def test_read_value_multi_sz_empty_list(self): @@ -222,25 +380,20 @@ def test_set_value(self): hive='HKLM', key=FAKE_KEY, vname='fake_name', - vdata='fake_data' - ) - ) + vdata='fake_data')) expected = { 'hive': 'HKLM', 'key': FAKE_KEY, 'success': True, 'vdata': 'fake_data', 'vname': 'fake_name', - 'vtype': 'REG_SZ' - } + 'vtype': 'REG_SZ'} self.assertEqual( win_reg.read_value( hive='HKLM', key=FAKE_KEY, - vname='fake_name' - ), - expected - ) + vname='fake_name'), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @@ -254,24 +407,19 @@ def test_set_value_default(self): win_reg.set_value( hive='HKLM', key=FAKE_KEY, - vdata='fake_default_data' - ) - ) + vdata='fake_default_data')) expected = { 'hive': 'HKLM', 'key': FAKE_KEY, 'success': True, 'vdata': 'fake_default_data', 'vname': '(Default)', - 'vtype': 'REG_SZ' - } + 'vtype': 'REG_SZ'} self.assertEqual( win_reg.read_value( hive='HKLM', - key=FAKE_KEY, - ), - expected - ) + key=FAKE_KEY), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @@ -284,27 +432,22 @@ def test_set_value_unicode_key(self): self.assertTrue( win_reg.set_value( hive='HKLM', - key='{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY), + key='\\'.join([FAKE_KEY, UNICODE_KEY]), vname='fake_name', - vdata='fake_value' - ) - ) + vdata='fake_value')) expected = { 'hive': 'HKLM', - 'key': '{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY), + 'key': '\\'.join([FAKE_KEY, UNICODE_KEY]), 'success': True, 'vdata': 'fake_value', 'vname': 'fake_name', - 'vtype': 'REG_SZ' - } + 'vtype': 'REG_SZ'} self.assertEqual( win_reg.read_value( hive='HKLM', - key='{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY), - vname='fake_name' - ), - expected - ) + key='\\'.join([FAKE_KEY, UNICODE_KEY]), + vname='fake_name'), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @@ -319,32 +462,27 @@ def test_set_value_unicode_value(self): hive='HKLM', key=FAKE_KEY, vname='fake_unicode', - vdata=UNICODE_VALUE - ) - ) + vdata=UNICODE_VALUE)) expected = { 'hive': 'HKLM', 'key': FAKE_KEY, 'success': True, 'vdata': UNICODE_VALUE, 'vname': 'fake_unicode', - 'vtype': 'REG_SZ' - } + 'vtype': 'REG_SZ'} self.assertEqual( win_reg.read_value( hive='HKLM', key=FAKE_KEY, - vname='fake_unicode' - ), - expected - ) + vname='fake_unicode'), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @destructiveTest def test_set_value_reg_dword(self): ''' - Test the set_value function on a unicode value + Test the set_value function on a REG_DWORD value ''' try: self.assertTrue( @@ -353,32 +491,27 @@ def test_set_value_reg_dword(self): key=FAKE_KEY, vname='dword_value', vdata=123, - vtype='REG_DWORD' - ) - ) + vtype='REG_DWORD')) expected = { 'hive': 'HKLM', 'key': FAKE_KEY, 'success': True, 'vdata': 123, 'vname': 'dword_value', - 'vtype': 'REG_DWORD' - } + 'vtype': 'REG_DWORD'} self.assertEqual( win_reg.read_value( hive='HKLM', key=FAKE_KEY, - vname='dword_value' - ), - expected - ) + vname='dword_value'), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @destructiveTest def test_set_value_reg_qword(self): ''' - Test the set_value function on a unicode value + Test the set_value function on a REG_QWORD value ''' try: self.assertTrue( @@ -387,28 +520,181 @@ def test_set_value_reg_qword(self): key=FAKE_KEY, vname='qword_value', vdata=123, - vtype='REG_QWORD' - ) - ) + vtype='REG_QWORD')) expected = { 'hive': 'HKLM', 'key': FAKE_KEY, 'success': True, 'vdata': 123, 'vname': 'qword_value', - 'vtype': 'REG_QWORD' - } + 'vtype': 'REG_QWORD'} self.assertEqual( win_reg.read_value( hive='HKLM', key=FAKE_KEY, - vname='qword_value' - ), - expected - ) + vname='qword_value'), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) + def test_set_value_invalid_hive(self): + ''' + Test the set_value function when passing an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.set_value, + hive='BADHIVE', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_data') + + def test_set_value_open_create_failure(self): + ''' + Test the set_value function when there is a problem opening/creating + the key + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegCreateKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegCreateKeyEx', mock_error): + self.assertFalse( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_data')) + + def test_set_value_type_error(self): + ''' + Test the set_value function when the wrong type of data is passed + ''' + mock_error = MagicMock( + side_effect=TypeError('Mocked TypeError')) + with patch('salt.utils.win_reg.win32api.RegSetValueEx', mock_error): + self.assertFalse( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_data')) + + def test_set_value_system_error(self): + ''' + Test the set_value function when a SystemError occurs while setting the + value + ''' + mock_error = MagicMock( + side_effect=SystemError('Mocked SystemError')) + with patch('salt.utils.win_reg.win32api.RegSetValueEx', mock_error): + self.assertFalse( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_data')) + + def test_set_value_value_error(self): + ''' + Test the set_value function when a ValueError occurs while setting the + value + ''' + mock_error = MagicMock( + side_effect=ValueError('Mocked ValueError')) + with patch('salt.utils.win_reg.win32api.RegSetValueEx', mock_error): + self.assertFalse( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_data')) + + def test_cast_vdata_reg_binary(self): + ''' + Test the cast_vdata function with REG_BINARY + Should always return binary data + ''' + vdata = salt.utils.stringutils.to_bytes('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_BINARY') + self.assertTrue(isinstance(result, six.binary_type)) + + vdata = salt.utils.stringutils.to_str('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_BINARY') + self.assertTrue(isinstance(result, six.binary_type)) + + vdata = salt.utils.stringutils.to_unicode('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_BINARY') + self.assertTrue(isinstance(result, six.binary_type)) + + def test_cast_vdata_reg_dword(self): + ''' + Test the cast_vdata function with REG_DWORD + Should always return integer + ''' + vdata = 1 + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_DWORD') + self.assertTrue(isinstance(result, six.integer_types)) + + vdata = '1' + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_DWORD') + self.assertTrue(isinstance(result, six.integer_types)) + + def test_cast_vdata_reg_expand_sz(self): + ''' + Test the cast_vdata function with REG_EXPAND_SZ + Should always return unicode + ''' + vdata = salt.utils.stringutils.to_str('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_EXPAND_SZ') + self.assertTrue(isinstance(result, six.text_type)) + + vdata = salt.utils.stringutils.to_bytes('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_EXPAND_SZ') + self.assertTrue(isinstance(result, six.text_type)) + + def test_cast_vdata_reg_multi_sz(self): + ''' + Test the cast_vdata function with REG_MULTI_SZ + Should always return a list of unicode strings + ''' + vdata = [salt.utils.stringutils.to_str('test string'), + salt.utils.stringutils.to_bytes('test bytes')] + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_MULTI_SZ') + self.assertTrue(isinstance(result, list)) + for item in result: + self.assertTrue(isinstance(item, six.text_type)) + + def test_cast_vdata_reg_qword(self): + ''' + Test the cast_vdata function with REG_QWORD + Should always return a long integer + `int` is `long` is default on Py3 + ''' + vdata = 1 + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_QWORD') + if six.PY2: + self.assertTrue(isinstance(result, long)) # pylint: disable=incompatible-py3-code,undefined-variable + else: + self.assertTrue(isinstance(result, int)) + + vdata = '1' + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_QWORD') + if six.PY2: + self.assertTrue(isinstance(result, long)) # pylint: disable=incompatible-py3-code,undefined-variable + else: + self.assertTrue(isinstance(result, int)) + + def test_cast_vdata_reg_sz(self): + ''' + Test the cast_vdata function with REG_SZ + Should always return unicode + ''' + vdata = salt.utils.stringutils.to_str('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_SZ') + self.assertTrue(isinstance(result, six.text_type)) + + vdata = salt.utils.stringutils.to_bytes('test data') + result = win_reg.cast_vdata(vdata=vdata, vtype='REG_SZ') + self.assertTrue(isinstance(result, six.text_type)) + @destructiveTest def test_delete_value(self): ''' @@ -420,16 +706,12 @@ def test_delete_value(self): hive='HKLM', key=FAKE_KEY, vname='fake_name', - vdata='fake_data' - ) - ) + vdata='fake_data')) self.assertTrue( win_reg.delete_value( hive='HKLM', key=FAKE_KEY, - vname='fake_name' - ) - ) + vname='fake_name')) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @@ -437,14 +719,37 @@ def test_delete_value_non_existing(self): ''' Test the delete_value function on non existing value ''' - self.assertEqual( - win_reg.delete_value( - hive='HKLM', - key=FAKE_KEY, - vname='fake_name' - ), - None - ) + mock_error = MagicMock( + side_effect=win32api.error(2, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertIsNone( + win_reg.delete_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name')) + + def test_delete_value_invalid_hive(self): + ''' + Test the delete_value function when passing an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.delete_value, + hive='BADHIVE', + key=FAKE_KEY, + vname='fake_name') + + def test_delete_value_unknown_error(self): + ''' + Test the delete_value function when there is a problem opening the key + ''' + mock_error = MagicMock( + side_effect=win32api.error(123, 'RegOpenKeyEx', 'Unknown error')) + with patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertRaises(win32api.error, + win_reg.delete_value, + hive='HKLM', + key=FAKE_KEY, + vname='fake_name') @destructiveTest def test_delete_value_unicode(self): @@ -457,44 +762,185 @@ def test_delete_value_unicode(self): hive='HKLM', key=FAKE_KEY, vname='fake_unicode', - vdata=UNICODE_VALUE - ) - ) + vdata=UNICODE_VALUE)) self.assertTrue( win_reg.delete_value( hive='HKLM', key=FAKE_KEY, - vname='fake_unicode' - ) - ) + vname='fake_unicode')) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) @destructiveTest - def test_delete_key_unicode(self): + def test_delete_value_unicode_vname(self): ''' - Test the delete_value function on value within a unicode key + Test the delete_value function on a unicode vname ''' try: self.assertTrue( win_reg.set_value( hive='HKLM', - key='{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY), + key=FAKE_KEY, + vname=UNICODE_KEY, + vdata='junk data')) + self.assertTrue( + win_reg.delete_value( + hive='HKLM', + key=FAKE_KEY, + vname=UNICODE_KEY)) + finally: + win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) + + @destructiveTest + def test_delete_value_unicode_key(self): + ''' + Test the delete_value function on a unicode key + ''' + try: + self.assertTrue( + win_reg.set_value( + hive='HKLM', + key='\\'.join([FAKE_KEY, UNICODE_KEY]), vname='fake_name', - vdata='fake_value' - ) - ) + vdata='junk data')) + self.assertTrue( + win_reg.delete_value( + hive='HKLM', + key='\\'.join([FAKE_KEY, UNICODE_KEY]), + vname='fake_name')) + finally: + win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) + + def test_delete_key_recursive_invalid_hive(self): + ''' + Test the delete_key_recursive function when passing an invalid hive + ''' + self.assertRaises(CommandExecutionError, + win_reg.delete_key_recursive, + hive='BADHIVE', + key=FAKE_KEY) + + def test_delete_key_recursive_key_not_found(self): + ''' + Test the delete_key_recursive function when the passed key to delete is + not found. + ''' + self.assertFalse( + win_reg.key_exists(hive='HKLM', key=FAKE_KEY)) + self.assertFalse( + win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)) + + def test_delete_key_recursive_too_close(self): + ''' + Test the delete_key_recursive function when the passed key to delete is + too close to root, such as + ''' + mock_true = MagicMock(return_value=True) + with patch('salt.utils.win_reg.key_exists', mock_true): + self.assertFalse( + win_reg.delete_key_recursive(hive='HKLM', key='FAKE_KEY')) + + @destructiveTest + def test_delete_key_recursive(self): + ''' + Test the delete_key_recursive function + ''' + try: + self.assertTrue( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_value')) expected = { - 'Deleted': ['HKLM\\{0}\\{1}\\'.format(FAKE_KEY, UNICODE_KEY)], - 'Failed': [] - } - self.assertEqual( + 'Deleted': ['\\'.join(['HKLM', FAKE_KEY])], + 'Failed': []} + self.assertDictEqual( win_reg.delete_key_recursive( hive='HKLM', - key='{0}\\{1}\\'.format(FAKE_KEY, UNICODE_KEY), - ), - expected - ) + key=FAKE_KEY), + expected) + finally: + win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) + + @destructiveTest + def test_delete_key_recursive_failed_to_open_key(self): + ''' + Test the delete_key_recursive function on failure to open the key + ''' + try: + self.assertTrue( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_value')) + expected = { + 'Deleted': [], + 'Failed': ['\\'.join(['HKLM', FAKE_KEY]) + + ' Failed to connect to key']} + mock_true = MagicMock(return_value=True) + mock_error = MagicMock( + side_effect=[ + 1, + win32api.error(3, 'RegOpenKeyEx', + 'Failed to connect to key') + ]) + with patch('salt.utils.win_reg.key_exists', mock_true), \ + patch('salt.utils.win_reg.win32api.RegOpenKeyEx', mock_error): + self.assertDictEqual( + win_reg.delete_key_recursive( + hive='HKLM', + key=FAKE_KEY), + expected) + finally: + win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) + + @destructiveTest + def test_delete_key_recursive_failed_to_delete(self): + ''' + Test the delete_key_recursive function on failure to delete a key + ''' + try: + self.assertTrue( + win_reg.set_value( + hive='HKLM', + key=FAKE_KEY, + vname='fake_name', + vdata='fake_value')) + expected = { + 'Deleted': [], + 'Failed': ['\\'.join(['HKLM', FAKE_KEY]) + ' Unknown error']} + mock_error = MagicMock(side_effect=WindowsError('Unknown error')) # pylint: disable=undefined-variable + with patch('salt.utils.win_reg.win32api.RegDeleteKey', mock_error): + self.assertDictEqual( + win_reg.delete_key_recursive( + hive='HKLM', + key=FAKE_KEY), + expected) + finally: + win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY) + + @destructiveTest + def test_delete_key_recursive_unicode(self): + ''' + Test the delete_key_recursive function on value within a unicode key + ''' + try: + self.assertTrue( + win_reg.set_value( + hive='HKLM', + key='\\'.join([FAKE_KEY, UNICODE_KEY]), + vname='fake_name', + vdata='fake_value')) + expected = { + 'Deleted': ['\\'.join(['HKLM', FAKE_KEY, UNICODE_KEY])], + 'Failed': []} + self.assertDictEqual( + win_reg.delete_key_recursive( + hive='HKLM', + key='\\'.join([FAKE_KEY, UNICODE_KEY])), + expected) finally: win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)