# -*- coding: utf-8 -*- ''' Tests for win_path states ''' # Import Python Libs from __future__ import absolute_import, print_function, unicode_literals import copy # Import Salt Testing Libs from tests.support.mixins import LoaderModuleMockMixin from tests.support.unit import TestCase, skipIf from tests.support.mock import ( Mock, MagicMock, patch, NO_MOCK, NO_MOCK_REASON ) # Import Salt Libs import salt.states.win_path as win_path NAME = 'salt' @skipIf(NO_MOCK, NO_MOCK_REASON) class WinPathTestCase(TestCase, LoaderModuleMockMixin): ''' Validate the win_path state ''' def setup_loader_modules(self): return {win_path: {}} def test_absent(self): ''' Test various cases for win_path.absent ''' ret_base = {'name': NAME, 'result': True, 'changes': {}} def _mock(retval): # Return a new MagicMock for each test case return MagicMock(side_effect=retval) # We don't really want to run the remove func with patch.dict(win_path.__salt__, {'win_path.remove': Mock()}): # Test mode OFF with patch.dict(win_path.__opts__, {'test': False}): # Test already absent with patch.dict(win_path.__salt__, {'win_path.exists': _mock([False])}): ret = copy.deepcopy(ret_base) ret['comment'] = '{0} is not in the PATH'.format(NAME) ret['result'] = True self.assertDictEqual(win_path.absent(NAME), ret) # Test successful removal with patch.dict(win_path.__salt__, {'win_path.exists': _mock([True, False])}): ret = copy.deepcopy(ret_base) ret['comment'] = 'Removed {0} from the PATH'.format(NAME) ret['changes']['removed'] = NAME ret['result'] = True self.assertDictEqual(win_path.absent(NAME), ret) # Test unsucessful removal with patch.dict(win_path.__salt__, {'win_path.exists': _mock([True, True])}): ret = copy.deepcopy(ret_base) ret['comment'] = 'Failed to remove {0} from the PATH'.format(NAME) ret['result'] = False self.assertDictEqual(win_path.absent(NAME), ret) # Test mode ON with patch.dict(win_path.__opts__, {'test': True}): # Test already absent with patch.dict(win_path.__salt__, {'win_path.exists': _mock([False])}): ret = copy.deepcopy(ret_base) ret['comment'] = '{0} is not in the PATH'.format(NAME) ret['result'] = True self.assertDictEqual(win_path.absent(NAME), ret) # Test the test-mode return with patch.dict(win_path.__salt__, {'win_path.exists': _mock([True])}): ret = copy.deepcopy(ret_base) ret['comment'] = '{0} would be removed from the PATH'.format(NAME) ret['result'] = None self.assertDictEqual(win_path.absent(NAME), ret) def test_exists_invalid_index(self): ''' Tests win_path.exists when a non-integer index is specified. ''' ret = win_path.exists(NAME, index='foo') self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Index must be an integer' } ) def test_exists_add_no_index_success(self): ''' Tests win_path.exists when the directory isn't already in the PATH and no index is specified (successful run). ''' add_mock = MagicMock(return_value=True) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz'], ['foo', 'bar', 'baz', NAME] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME) add_mock.assert_called_once_with(NAME, index=None, rehash=False) self.assert_called_once(rehash_mock) self.assertDictEqual( ret, { 'name': NAME, 'changes': {'index': {'old': None, 'new': 3}}, 'result': True, 'comment': 'Added {0} to the PATH.'.format(NAME) } ) def test_exists_add_no_index_failure(self): ''' Tests win_path.exists when the directory isn't already in the PATH and no index is specified (failed run). ''' add_mock = MagicMock(return_value=False) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz'], ['foo', 'bar', 'baz'] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME) add_mock.assert_called_once_with(NAME, index=None, rehash=False) rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Failed to add {0} to the PATH.'.format(NAME) } ) def test_exists_add_no_index_failure_exception(self): ''' Tests win_path.exists when the directory isn't already in the PATH and no index is specified (failed run due to exception). ''' add_mock = MagicMock(side_effect=Exception('Global Thermonuclear War')) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz'], ['foo', 'bar', 'baz'] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME) add_mock.assert_called_once_with(NAME, index=None, rehash=False) rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Encountered error: Global Thermonuclear War. ' 'Failed to add {0} to the PATH.'.format(NAME) } ) def test_exists_change_index_success(self): ''' Tests win_path.exists when the directory is already in the PATH and needs to be moved to a different position (successful run). ''' add_mock = MagicMock(return_value=True) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz', NAME], [NAME, 'foo', 'bar', 'baz'] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=0) add_mock.assert_called_once_with(NAME, index=0, rehash=False) self.assert_called_once(rehash_mock) self.assertDictEqual( ret, { 'name': NAME, 'changes': {'index': {'old': 3, 'new': 0}}, 'result': True, 'comment': 'Moved {0} from index 3 to 0.'.format(NAME) } ) def test_exists_change_negative_index_success(self): ''' Tests win_path.exists when the directory is already in the PATH and needs to be moved to a different position (successful run). This tests a negative index. ''' add_mock = MagicMock(return_value=True) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', NAME, 'baz'], ['foo', 'bar', 'baz', NAME] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=-1) add_mock.assert_called_once_with(NAME, index=-1, rehash=False) self.assert_called_once(rehash_mock) self.assertDictEqual( ret, { 'name': NAME, 'changes': {'index': {'old': -2, 'new': -1}}, 'result': True, 'comment': 'Moved {0} from index -2 to -1.'.format(NAME) } ) def test_exists_change_index_add_exception(self): ''' Tests win_path.exists when the directory is already in the PATH but an exception is raised when we attempt to add the key to its new location. ''' add_mock = MagicMock(side_effect=Exception('Global Thermonuclear War')) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz', NAME], ['foo', 'bar', 'baz', NAME], ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=0) add_mock.assert_called_once_with(NAME, index=0, rehash=False) rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Encountered error: Global Thermonuclear War. ' 'Failed to move {0} from index 3 to 0.'.format(NAME) } ) def test_exists_change_negative_index_add_exception(self): ''' Tests win_path.exists when the directory is already in the PATH but an exception is raised when we attempt to add the key to its new location. This tests a negative index. ''' add_mock = MagicMock(side_effect=Exception('Global Thermonuclear War')) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', NAME, 'baz'], ['foo', 'bar', NAME, 'baz'], ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=-1) add_mock.assert_called_once_with(NAME, index=-1, rehash=False) rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Encountered error: Global Thermonuclear War. ' 'Failed to move {0} from index -2 to -1.'.format(NAME) } ) def test_exists_change_index_failure(self): ''' Tests win_path.exists when the directory is already in the PATH and needs to be moved to a different position (failed run). ''' add_mock = MagicMock(return_value=False) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz', NAME], ['foo', 'bar', 'baz', NAME] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=0) add_mock.assert_called_once_with(NAME, index=0, rehash=False) rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Failed to move {0} from index 3 to 0.'.format(NAME) } ) def test_exists_change_negative_index_failure(self): ''' Tests win_path.exists when the directory is already in the PATH and needs to be moved to a different position (failed run). This tests a negative index. ''' add_mock = MagicMock(return_value=False) rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', NAME, 'baz'], ['foo', 'bar', NAME, 'baz'] ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': False} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=-1) add_mock.assert_called_once_with(NAME, index=-1, rehash=False) rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': False, 'comment': 'Failed to move {0} from index -2 to -1.'.format(NAME) } ) def test_exists_change_index_test_mode(self): ''' Tests win_path.exists when the directory is already in the PATH and needs to be moved to a different position (test mode enabled). ''' add_mock = Mock() rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', 'baz', NAME], ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': True} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=0) add_mock.assert_not_called() rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {'index': {'old': 3, 'new': 0}}, 'result': None, 'comment': '{0} would be moved from index 3 to 0.'.format(NAME) } ) def test_exists_change_negative_index_test_mode(self): ''' Tests win_path.exists when the directory is already in the PATH and needs to be moved to a different position (test mode enabled). ''' add_mock = Mock() rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[ ['foo', 'bar', NAME, 'baz'], ]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': True} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=-1) add_mock.assert_not_called() rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {'index': {'old': -2, 'new': -1}}, 'result': None, 'comment': '{0} would be moved from index -2 to -1.'.format(NAME) } ) def _test_exists_add_already_present(self, index, test_mode): ''' Tests win_path.exists when the directory already exists in the PATH. Helper function to test both with and without and index, and with test mode both disabled and enabled. ''' current_path = ['foo', 'bar', 'baz'] if index is None: current_path.append(NAME) else: pos = index if index >= 0 else len(current_path) + index + 1 current_path.insert(pos, NAME) add_mock = Mock() rehash_mock = MagicMock(return_value=True) dunder_salt = { 'win_path.get_path': MagicMock(side_effect=[current_path]), 'win_path.add': add_mock, 'win_path.rehash': rehash_mock, } dunder_opts = {'test': test_mode} with patch.dict(win_path.__salt__, dunder_salt), \ patch.dict(win_path.__opts__, dunder_opts): ret = win_path.exists(NAME, index=index) add_mock.assert_not_called() rehash_mock.assert_not_called() self.assertDictEqual( ret, { 'name': NAME, 'changes': {}, 'result': True, 'comment': '{0} already exists in the PATH{1}.'.format( NAME, ' at index {0}'.format(index) if index is not None else '' ) } ) def test_exists_add_no_index_already_present(self): self._test_exists_add_already_present(None, False) def test_exists_add_no_index_already_present_test_mode(self): self._test_exists_add_already_present(None, True) def test_exists_add_index_already_present(self): self._test_exists_add_already_present(1, False) self._test_exists_add_already_present(2, False) self._test_exists_add_already_present(-1, False) self._test_exists_add_already_present(-2, False) def test_exists_add_index_already_present_test_mode(self): self._test_exists_add_already_present(1, True) self._test_exists_add_already_present(2, True) self._test_exists_add_already_present(-1, True) self._test_exists_add_already_present(-2, True)