test_win_path.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Tests for win_path states
  4. '''
  5. # Import Python Libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import copy
  8. # Import Salt Testing Libs
  9. from tests.support.mixins import LoaderModuleMockMixin
  10. from tests.support.unit import TestCase
  11. from tests.support.mock import (
  12. Mock,
  13. MagicMock,
  14. patch,
  15. )
  16. # Import Salt Libs
  17. import salt.states.win_path as win_path
  18. NAME = 'salt'
  19. class WinPathTestCase(TestCase, LoaderModuleMockMixin):
  20. '''
  21. Validate the win_path state
  22. '''
  23. def setup_loader_modules(self):
  24. return {win_path: {}}
  25. def test_absent(self):
  26. '''
  27. Test various cases for win_path.absent
  28. '''
  29. ret_base = {'name': NAME, 'result': True, 'changes': {}}
  30. def _mock(retval):
  31. # Return a new MagicMock for each test case
  32. return MagicMock(side_effect=retval)
  33. # We don't really want to run the remove func
  34. with patch.dict(win_path.__salt__, {'win_path.remove': Mock()}):
  35. # Test mode OFF
  36. with patch.dict(win_path.__opts__, {'test': False}):
  37. # Test already absent
  38. with patch.dict(win_path.__salt__, {'win_path.exists': _mock([False])}):
  39. ret = copy.deepcopy(ret_base)
  40. ret['comment'] = '{0} is not in the PATH'.format(NAME)
  41. ret['result'] = True
  42. self.assertDictEqual(win_path.absent(NAME), ret)
  43. # Test successful removal
  44. with patch.dict(win_path.__salt__, {'win_path.exists': _mock([True, False])}):
  45. ret = copy.deepcopy(ret_base)
  46. ret['comment'] = 'Removed {0} from the PATH'.format(NAME)
  47. ret['changes']['removed'] = NAME
  48. ret['result'] = True
  49. self.assertDictEqual(win_path.absent(NAME), ret)
  50. # Test unsucessful removal
  51. with patch.dict(win_path.__salt__, {'win_path.exists': _mock([True, True])}):
  52. ret = copy.deepcopy(ret_base)
  53. ret['comment'] = 'Failed to remove {0} from the PATH'.format(NAME)
  54. ret['result'] = False
  55. self.assertDictEqual(win_path.absent(NAME), ret)
  56. # Test mode ON
  57. with patch.dict(win_path.__opts__, {'test': True}):
  58. # Test already absent
  59. with patch.dict(win_path.__salt__, {'win_path.exists': _mock([False])}):
  60. ret = copy.deepcopy(ret_base)
  61. ret['comment'] = '{0} is not in the PATH'.format(NAME)
  62. ret['result'] = True
  63. self.assertDictEqual(win_path.absent(NAME), ret)
  64. # Test the test-mode return
  65. with patch.dict(win_path.__salt__, {'win_path.exists': _mock([True])}):
  66. ret = copy.deepcopy(ret_base)
  67. ret['comment'] = '{0} would be removed from the PATH'.format(NAME)
  68. ret['result'] = None
  69. self.assertDictEqual(win_path.absent(NAME), ret)
  70. def test_exists_invalid_index(self):
  71. '''
  72. Tests win_path.exists when a non-integer index is specified.
  73. '''
  74. ret = win_path.exists(NAME, index='foo')
  75. self.assertDictEqual(
  76. ret,
  77. {
  78. 'name': NAME,
  79. 'changes': {},
  80. 'result': False,
  81. 'comment': 'Index must be an integer'
  82. }
  83. )
  84. def test_exists_add_no_index_success(self):
  85. '''
  86. Tests win_path.exists when the directory isn't already in the PATH and
  87. no index is specified (successful run).
  88. '''
  89. add_mock = MagicMock(return_value=True)
  90. rehash_mock = MagicMock(return_value=True)
  91. dunder_salt = {
  92. 'win_path.get_path': MagicMock(side_effect=[
  93. ['foo', 'bar', 'baz'],
  94. ['foo', 'bar', 'baz', NAME]
  95. ]),
  96. 'win_path.add': add_mock,
  97. 'win_path.rehash': rehash_mock,
  98. }
  99. dunder_opts = {'test': False}
  100. with patch.dict(win_path.__salt__, dunder_salt), \
  101. patch.dict(win_path.__opts__, dunder_opts):
  102. ret = win_path.exists(NAME)
  103. add_mock.assert_called_once_with(NAME, index=None, rehash=False)
  104. self.assert_called_once(rehash_mock)
  105. self.assertDictEqual(
  106. ret,
  107. {
  108. 'name': NAME,
  109. 'changes': {'index': {'old': None, 'new': 3}},
  110. 'result': True,
  111. 'comment': 'Added {0} to the PATH.'.format(NAME)
  112. }
  113. )
  114. def test_exists_add_no_index_failure(self):
  115. '''
  116. Tests win_path.exists when the directory isn't already in the PATH and
  117. no index is specified (failed run).
  118. '''
  119. add_mock = MagicMock(return_value=False)
  120. rehash_mock = MagicMock(return_value=True)
  121. dunder_salt = {
  122. 'win_path.get_path': MagicMock(side_effect=[
  123. ['foo', 'bar', 'baz'],
  124. ['foo', 'bar', 'baz']
  125. ]),
  126. 'win_path.add': add_mock,
  127. 'win_path.rehash': rehash_mock,
  128. }
  129. dunder_opts = {'test': False}
  130. with patch.dict(win_path.__salt__, dunder_salt), \
  131. patch.dict(win_path.__opts__, dunder_opts):
  132. ret = win_path.exists(NAME)
  133. add_mock.assert_called_once_with(NAME, index=None, rehash=False)
  134. rehash_mock.assert_not_called()
  135. self.assertDictEqual(
  136. ret,
  137. {
  138. 'name': NAME,
  139. 'changes': {},
  140. 'result': False,
  141. 'comment': 'Failed to add {0} to the PATH.'.format(NAME)
  142. }
  143. )
  144. def test_exists_add_no_index_failure_exception(self):
  145. '''
  146. Tests win_path.exists when the directory isn't already in the PATH and
  147. no index is specified (failed run due to exception).
  148. '''
  149. add_mock = MagicMock(side_effect=Exception('Global Thermonuclear War'))
  150. rehash_mock = MagicMock(return_value=True)
  151. dunder_salt = {
  152. 'win_path.get_path': MagicMock(side_effect=[
  153. ['foo', 'bar', 'baz'],
  154. ['foo', 'bar', 'baz']
  155. ]),
  156. 'win_path.add': add_mock,
  157. 'win_path.rehash': rehash_mock,
  158. }
  159. dunder_opts = {'test': False}
  160. with patch.dict(win_path.__salt__, dunder_salt), \
  161. patch.dict(win_path.__opts__, dunder_opts):
  162. ret = win_path.exists(NAME)
  163. add_mock.assert_called_once_with(NAME, index=None, rehash=False)
  164. rehash_mock.assert_not_called()
  165. self.assertDictEqual(
  166. ret,
  167. {
  168. 'name': NAME,
  169. 'changes': {},
  170. 'result': False,
  171. 'comment': 'Encountered error: Global Thermonuclear War. '
  172. 'Failed to add {0} to the PATH.'.format(NAME)
  173. }
  174. )
  175. def test_exists_change_index_success(self):
  176. '''
  177. Tests win_path.exists when the directory is already in the PATH and
  178. needs to be moved to a different position (successful run).
  179. '''
  180. add_mock = MagicMock(return_value=True)
  181. rehash_mock = MagicMock(return_value=True)
  182. dunder_salt = {
  183. 'win_path.get_path': MagicMock(side_effect=[
  184. ['foo', 'bar', 'baz', NAME],
  185. [NAME, 'foo', 'bar', 'baz']
  186. ]),
  187. 'win_path.add': add_mock,
  188. 'win_path.rehash': rehash_mock,
  189. }
  190. dunder_opts = {'test': False}
  191. with patch.dict(win_path.__salt__, dunder_salt), \
  192. patch.dict(win_path.__opts__, dunder_opts):
  193. ret = win_path.exists(NAME, index=0)
  194. add_mock.assert_called_once_with(NAME, index=0, rehash=False)
  195. self.assert_called_once(rehash_mock)
  196. self.assertDictEqual(
  197. ret,
  198. {
  199. 'name': NAME,
  200. 'changes': {'index': {'old': 3, 'new': 0}},
  201. 'result': True,
  202. 'comment': 'Moved {0} from index 3 to 0.'.format(NAME)
  203. }
  204. )
  205. def test_exists_change_negative_index_success(self):
  206. '''
  207. Tests win_path.exists when the directory is already in the PATH and
  208. needs to be moved to a different position (successful run).
  209. This tests a negative index.
  210. '''
  211. add_mock = MagicMock(return_value=True)
  212. rehash_mock = MagicMock(return_value=True)
  213. dunder_salt = {
  214. 'win_path.get_path': MagicMock(side_effect=[
  215. ['foo', 'bar', NAME, 'baz'],
  216. ['foo', 'bar', 'baz', NAME]
  217. ]),
  218. 'win_path.add': add_mock,
  219. 'win_path.rehash': rehash_mock,
  220. }
  221. dunder_opts = {'test': False}
  222. with patch.dict(win_path.__salt__, dunder_salt), \
  223. patch.dict(win_path.__opts__, dunder_opts):
  224. ret = win_path.exists(NAME, index=-1)
  225. add_mock.assert_called_once_with(NAME, index=-1, rehash=False)
  226. self.assert_called_once(rehash_mock)
  227. self.assertDictEqual(
  228. ret,
  229. {
  230. 'name': NAME,
  231. 'changes': {'index': {'old': -2, 'new': -1}},
  232. 'result': True,
  233. 'comment': 'Moved {0} from index -2 to -1.'.format(NAME)
  234. }
  235. )
  236. def test_exists_change_index_add_exception(self):
  237. '''
  238. Tests win_path.exists when the directory is already in the PATH but an
  239. exception is raised when we attempt to add the key to its new location.
  240. '''
  241. add_mock = MagicMock(side_effect=Exception('Global Thermonuclear War'))
  242. rehash_mock = MagicMock(return_value=True)
  243. dunder_salt = {
  244. 'win_path.get_path': MagicMock(side_effect=[
  245. ['foo', 'bar', 'baz', NAME],
  246. ['foo', 'bar', 'baz', NAME],
  247. ]),
  248. 'win_path.add': add_mock,
  249. 'win_path.rehash': rehash_mock,
  250. }
  251. dunder_opts = {'test': False}
  252. with patch.dict(win_path.__salt__, dunder_salt), \
  253. patch.dict(win_path.__opts__, dunder_opts):
  254. ret = win_path.exists(NAME, index=0)
  255. add_mock.assert_called_once_with(NAME, index=0, rehash=False)
  256. rehash_mock.assert_not_called()
  257. self.assertDictEqual(
  258. ret,
  259. {
  260. 'name': NAME,
  261. 'changes': {},
  262. 'result': False,
  263. 'comment': 'Encountered error: Global Thermonuclear War. '
  264. 'Failed to move {0} from index 3 to 0.'.format(NAME)
  265. }
  266. )
  267. def test_exists_change_negative_index_add_exception(self):
  268. '''
  269. Tests win_path.exists when the directory is already in the PATH but an
  270. exception is raised when we attempt to add the key to its new location.
  271. This tests a negative index.
  272. '''
  273. add_mock = MagicMock(side_effect=Exception('Global Thermonuclear War'))
  274. rehash_mock = MagicMock(return_value=True)
  275. dunder_salt = {
  276. 'win_path.get_path': MagicMock(side_effect=[
  277. ['foo', 'bar', NAME, 'baz'],
  278. ['foo', 'bar', NAME, 'baz'],
  279. ]),
  280. 'win_path.add': add_mock,
  281. 'win_path.rehash': rehash_mock,
  282. }
  283. dunder_opts = {'test': False}
  284. with patch.dict(win_path.__salt__, dunder_salt), \
  285. patch.dict(win_path.__opts__, dunder_opts):
  286. ret = win_path.exists(NAME, index=-1)
  287. add_mock.assert_called_once_with(NAME, index=-1, rehash=False)
  288. rehash_mock.assert_not_called()
  289. self.assertDictEqual(
  290. ret,
  291. {
  292. 'name': NAME,
  293. 'changes': {},
  294. 'result': False,
  295. 'comment': 'Encountered error: Global Thermonuclear War. '
  296. 'Failed to move {0} from index -2 to -1.'.format(NAME)
  297. }
  298. )
  299. def test_exists_change_index_failure(self):
  300. '''
  301. Tests win_path.exists when the directory is already in the PATH and
  302. needs to be moved to a different position (failed run).
  303. '''
  304. add_mock = MagicMock(return_value=False)
  305. rehash_mock = MagicMock(return_value=True)
  306. dunder_salt = {
  307. 'win_path.get_path': MagicMock(side_effect=[
  308. ['foo', 'bar', 'baz', NAME],
  309. ['foo', 'bar', 'baz', NAME]
  310. ]),
  311. 'win_path.add': add_mock,
  312. 'win_path.rehash': rehash_mock,
  313. }
  314. dunder_opts = {'test': False}
  315. with patch.dict(win_path.__salt__, dunder_salt), \
  316. patch.dict(win_path.__opts__, dunder_opts):
  317. ret = win_path.exists(NAME, index=0)
  318. add_mock.assert_called_once_with(NAME, index=0, rehash=False)
  319. rehash_mock.assert_not_called()
  320. self.assertDictEqual(
  321. ret,
  322. {
  323. 'name': NAME,
  324. 'changes': {},
  325. 'result': False,
  326. 'comment': 'Failed to move {0} from index 3 to 0.'.format(NAME)
  327. }
  328. )
  329. def test_exists_change_negative_index_failure(self):
  330. '''
  331. Tests win_path.exists when the directory is already in the PATH and
  332. needs to be moved to a different position (failed run).
  333. This tests a negative index.
  334. '''
  335. add_mock = MagicMock(return_value=False)
  336. rehash_mock = MagicMock(return_value=True)
  337. dunder_salt = {
  338. 'win_path.get_path': MagicMock(side_effect=[
  339. ['foo', 'bar', NAME, 'baz'],
  340. ['foo', 'bar', NAME, 'baz']
  341. ]),
  342. 'win_path.add': add_mock,
  343. 'win_path.rehash': rehash_mock,
  344. }
  345. dunder_opts = {'test': False}
  346. with patch.dict(win_path.__salt__, dunder_salt), \
  347. patch.dict(win_path.__opts__, dunder_opts):
  348. ret = win_path.exists(NAME, index=-1)
  349. add_mock.assert_called_once_with(NAME, index=-1, rehash=False)
  350. rehash_mock.assert_not_called()
  351. self.assertDictEqual(
  352. ret,
  353. {
  354. 'name': NAME,
  355. 'changes': {},
  356. 'result': False,
  357. 'comment': 'Failed to move {0} from index -2 to -1.'.format(NAME)
  358. }
  359. )
  360. def test_exists_change_index_test_mode(self):
  361. '''
  362. Tests win_path.exists when the directory is already in the PATH and
  363. needs to be moved to a different position (test mode enabled).
  364. '''
  365. add_mock = Mock()
  366. rehash_mock = MagicMock(return_value=True)
  367. dunder_salt = {
  368. 'win_path.get_path': MagicMock(side_effect=[
  369. ['foo', 'bar', 'baz', NAME],
  370. ]),
  371. 'win_path.add': add_mock,
  372. 'win_path.rehash': rehash_mock,
  373. }
  374. dunder_opts = {'test': True}
  375. with patch.dict(win_path.__salt__, dunder_salt), \
  376. patch.dict(win_path.__opts__, dunder_opts):
  377. ret = win_path.exists(NAME, index=0)
  378. add_mock.assert_not_called()
  379. rehash_mock.assert_not_called()
  380. self.assertDictEqual(
  381. ret,
  382. {
  383. 'name': NAME,
  384. 'changes': {'index': {'old': 3, 'new': 0}},
  385. 'result': None,
  386. 'comment': '{0} would be moved from index 3 to 0.'.format(NAME)
  387. }
  388. )
  389. def test_exists_change_negative_index_test_mode(self):
  390. '''
  391. Tests win_path.exists when the directory is already in the PATH and
  392. needs to be moved to a different position (test mode enabled).
  393. '''
  394. add_mock = Mock()
  395. rehash_mock = MagicMock(return_value=True)
  396. dunder_salt = {
  397. 'win_path.get_path': MagicMock(side_effect=[
  398. ['foo', 'bar', NAME, 'baz'],
  399. ]),
  400. 'win_path.add': add_mock,
  401. 'win_path.rehash': rehash_mock,
  402. }
  403. dunder_opts = {'test': True}
  404. with patch.dict(win_path.__salt__, dunder_salt), \
  405. patch.dict(win_path.__opts__, dunder_opts):
  406. ret = win_path.exists(NAME, index=-1)
  407. add_mock.assert_not_called()
  408. rehash_mock.assert_not_called()
  409. self.assertDictEqual(
  410. ret,
  411. {
  412. 'name': NAME,
  413. 'changes': {'index': {'old': -2, 'new': -1}},
  414. 'result': None,
  415. 'comment': '{0} would be moved from index -2 to -1.'.format(NAME)
  416. }
  417. )
  418. def _test_exists_add_already_present(self, index, test_mode):
  419. '''
  420. Tests win_path.exists when the directory already exists in the PATH.
  421. Helper function to test both with and without and index, and with test
  422. mode both disabled and enabled.
  423. '''
  424. current_path = ['foo', 'bar', 'baz']
  425. if index is None:
  426. current_path.append(NAME)
  427. else:
  428. pos = index if index >= 0 else len(current_path) + index + 1
  429. current_path.insert(pos, NAME)
  430. add_mock = Mock()
  431. rehash_mock = MagicMock(return_value=True)
  432. dunder_salt = {
  433. 'win_path.get_path': MagicMock(side_effect=[current_path]),
  434. 'win_path.add': add_mock,
  435. 'win_path.rehash': rehash_mock,
  436. }
  437. dunder_opts = {'test': test_mode}
  438. with patch.dict(win_path.__salt__, dunder_salt), \
  439. patch.dict(win_path.__opts__, dunder_opts):
  440. ret = win_path.exists(NAME, index=index)
  441. add_mock.assert_not_called()
  442. rehash_mock.assert_not_called()
  443. self.assertDictEqual(
  444. ret,
  445. {
  446. 'name': NAME,
  447. 'changes': {},
  448. 'result': True,
  449. 'comment': '{0} already exists in the PATH{1}.'.format(
  450. NAME,
  451. ' at index {0}'.format(index) if index is not None else ''
  452. )
  453. }
  454. )
  455. def test_exists_add_no_index_already_present(self):
  456. self._test_exists_add_already_present(None, False)
  457. def test_exists_add_no_index_already_present_test_mode(self):
  458. self._test_exists_add_already_present(None, True)
  459. def test_exists_add_index_already_present(self):
  460. self._test_exists_add_already_present(1, False)
  461. self._test_exists_add_already_present(2, False)
  462. self._test_exists_add_already_present(-1, False)
  463. self._test_exists_add_already_present(-2, False)
  464. def test_exists_add_index_already_present_test_mode(self):
  465. self._test_exists_add_already_present(1, True)
  466. self._test_exists_add_already_present(2, True)
  467. self._test_exists_add_already_present(-1, True)
  468. self._test_exists_add_already_present(-2, True)