test_augeas.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # -*- coding: utf-8 -*-
  2. """
  3. :codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
  4. :codeauthor: Andrew Colin Kissa <andrew@topdog.za.net>
  5. """
  6. # Import Python libs
  7. from __future__ import absolute_import, print_function, unicode_literals
  8. import os
  9. # Import Salt Libs
  10. import salt.states.augeas as augeas
  11. # Import Salt Testing Libs
  12. from tests.support.mixins import LoaderModuleMockMixin
  13. from tests.support.mock import MagicMock, mock_open, patch
  14. from tests.support.unit import TestCase
  15. class AugeasTestCase(TestCase, LoaderModuleMockMixin):
  16. """
  17. Test cases for salt.states.augeas
  18. """
  19. def setup_loader_modules(self):
  20. return {augeas: {}}
  21. # 'change' function tests: 1
  22. def setUp(self):
  23. self.name = "zabbix"
  24. self.context = "/files/etc/services"
  25. self.changes = [
  26. "ins service-name after service-name[last()]",
  27. "set service-name[last()] zabbix-agent",
  28. ]
  29. self.fp_changes = [
  30. "ins service-name after /files/etc/services/service-name[last()]",
  31. "set /files/etc/services/service-name[last()] zabbix-agent",
  32. ]
  33. self.ret = {"name": self.name, "result": False, "changes": {}, "comment": ""}
  34. method_map = {
  35. "set": "set",
  36. "setm": "setm",
  37. "mv": "move",
  38. "move": "move",
  39. "ins": "insert",
  40. "insert": "insert",
  41. "rm": "remove",
  42. "remove": "remove",
  43. }
  44. self.mock_method_map = MagicMock(return_value=method_map)
  45. def tearDown(self):
  46. del self.ret
  47. del self.changes
  48. del self.fp_changes
  49. del self.mock_method_map
  50. def test_change_non_list_changes(self):
  51. """
  52. Test if none list changes handled correctly
  53. """
  54. comt = "'changes' must be specified as a list"
  55. self.ret.update({"comment": comt})
  56. self.assertDictEqual(augeas.change(self.name), self.ret)
  57. def test_change_non_list_load_path(self):
  58. """
  59. Test if none list load_path is handled correctly
  60. """
  61. comt = "'load_path' must be specified as a list"
  62. self.ret.update({"comment": comt})
  63. self.assertDictEqual(
  64. augeas.change(self.name, self.context, self.changes, load_path="x"),
  65. self.ret,
  66. )
  67. def test_change_in_test_mode(self):
  68. """
  69. Test test mode handling
  70. """
  71. comt = (
  72. 'Executing commands in file "/files/etc/services":\n'
  73. "ins service-name after service-name[last()]"
  74. "\nset service-name[last()] zabbix-agent"
  75. )
  76. self.ret.update({"comment": comt, "result": True})
  77. with patch.dict(augeas.__opts__, {"test": True}):
  78. self.assertDictEqual(
  79. augeas.change(self.name, self.context, self.changes), self.ret
  80. )
  81. def test_change_no_context_without_full_path(self):
  82. """
  83. Test handling of no context without full path
  84. """
  85. comt = (
  86. "Error: Changes should be prefixed with /files if no "
  87. "context is provided, change: {0}".format(self.changes[0])
  88. )
  89. self.ret.update({"comment": comt, "result": False})
  90. with patch.dict(augeas.__opts__, {"test": False}):
  91. mock_dict_ = {"augeas.method_map": self.mock_method_map}
  92. with patch.dict(augeas.__salt__, mock_dict_):
  93. self.assertDictEqual(
  94. augeas.change(self.name, changes=self.changes), self.ret
  95. )
  96. def test_change_no_context_with_full_path_fail(self):
  97. """
  98. Test handling of no context with full path with execute fail
  99. """
  100. self.ret.update({"comment": "Error: error", "result": False})
  101. with patch.dict(augeas.__opts__, {"test": False}):
  102. mock_execute = MagicMock(return_value=dict(retval=False, error="error"))
  103. mock_dict_ = {
  104. "augeas.execute": mock_execute,
  105. "augeas.method_map": self.mock_method_map,
  106. }
  107. with patch.dict(augeas.__salt__, mock_dict_):
  108. self.assertDictEqual(
  109. augeas.change(self.name, changes=self.fp_changes), self.ret
  110. )
  111. def test_change_no_context_with_full_path_pass(self):
  112. """
  113. Test handling of no context with full path with execute pass
  114. """
  115. self.ret.update(
  116. dict(
  117. comment="Changes have been saved",
  118. result=True,
  119. changes={"diff": "+ zabbix-agent"},
  120. )
  121. )
  122. with patch.dict(augeas.__opts__, {"test": False}):
  123. mock_execute = MagicMock(return_value=dict(retval=True))
  124. mock_dict_ = {
  125. "augeas.execute": mock_execute,
  126. "augeas.method_map": self.mock_method_map,
  127. }
  128. with patch.dict(augeas.__salt__, mock_dict_):
  129. mock_filename = MagicMock(return_value="/etc/services")
  130. with patch.object(augeas, "_workout_filename", mock_filename), patch(
  131. "os.path.isfile", MagicMock(return_value=True)
  132. ):
  133. with patch("salt.utils.files.fopen", MagicMock(mock_open)):
  134. mock_diff = MagicMock(return_value=["+ zabbix-agent"])
  135. with patch("difflib.unified_diff", mock_diff):
  136. self.assertDictEqual(
  137. augeas.change(self.name, changes=self.fp_changes),
  138. self.ret,
  139. )
  140. def test_change_no_context_without_full_path_invalid_cmd(self):
  141. """
  142. Test handling of invalid commands when no context supplied
  143. """
  144. self.ret.update(
  145. dict(comment="Error: Command det is not supported (yet)", result=False)
  146. )
  147. with patch.dict(augeas.__opts__, {"test": False}):
  148. mock_execute = MagicMock(return_value=dict(retval=True))
  149. mock_dict_ = {
  150. "augeas.execute": mock_execute,
  151. "augeas.method_map": self.mock_method_map,
  152. }
  153. with patch.dict(augeas.__salt__, mock_dict_):
  154. changes = ["det service-name[last()] zabbix-agent"]
  155. self.assertDictEqual(
  156. augeas.change(self.name, changes=changes), self.ret
  157. )
  158. def test_change_no_context_without_full_path_invalid_change(self):
  159. """
  160. Test handling of invalid change when no context supplied
  161. """
  162. comt = "Error: Invalid formatted command, see " "debug log for details: require"
  163. self.ret.update(dict(comment=comt, result=False))
  164. changes = ["require"]
  165. with patch.dict(augeas.__opts__, {"test": False}):
  166. mock_execute = MagicMock(return_value=dict(retval=True))
  167. mock_dict_ = {
  168. "augeas.execute": mock_execute,
  169. "augeas.method_map": self.mock_method_map,
  170. }
  171. with patch.dict(augeas.__salt__, mock_dict_):
  172. self.assertDictEqual(
  173. augeas.change(self.name, changes=changes), self.ret
  174. )
  175. def test_change_no_context_with_full_path_multiple_files(self):
  176. """
  177. Test handling of different paths with no context supplied
  178. """
  179. changes = [
  180. "set /files/etc/hosts/service-name test",
  181. "set /files/etc/services/service-name test",
  182. ]
  183. filename = "/etc/hosts/service-name"
  184. filename_ = "/etc/services/service-name"
  185. comt = (
  186. "Error: Changes should be made to one file at a time, "
  187. "detected changes to {0} and {1}".format(filename, filename_)
  188. )
  189. self.ret.update(dict(comment=comt, result=False))
  190. with patch.dict(augeas.__opts__, {"test": False}):
  191. mock_execute = MagicMock(return_value=dict(retval=True))
  192. mock_dict_ = {
  193. "augeas.execute": mock_execute,
  194. "augeas.method_map": self.mock_method_map,
  195. }
  196. with patch.dict(augeas.__salt__, mock_dict_):
  197. self.assertDictEqual(
  198. augeas.change(self.name, changes=changes), self.ret
  199. )
  200. def test_change_with_context_without_full_path_fail(self):
  201. """
  202. Test handling of context without full path fails
  203. """
  204. self.ret.update(dict(comment="Error: error", result=False))
  205. with patch.dict(augeas.__opts__, {"test": False}):
  206. mock_execute = MagicMock(return_value=dict(retval=False, error="error"))
  207. mock_dict_ = {
  208. "augeas.execute": mock_execute,
  209. "augeas.method_map": self.mock_method_map,
  210. }
  211. with patch.dict(augeas.__salt__, mock_dict_):
  212. with patch("salt.utils.files.fopen", MagicMock(mock_open)):
  213. self.assertDictEqual(
  214. augeas.change(
  215. self.name, context=self.context, changes=self.changes
  216. ),
  217. self.ret,
  218. )
  219. def test_change_with_context_without_old_file(self):
  220. """
  221. Test handling of context without oldfile pass
  222. """
  223. self.ret.update(
  224. dict(
  225. comment="Changes have been saved",
  226. result=True,
  227. changes={"updates": self.changes},
  228. )
  229. )
  230. with patch.dict(augeas.__opts__, {"test": False}):
  231. mock_execute = MagicMock(return_value=dict(retval=True))
  232. mock_dict_ = {
  233. "augeas.execute": mock_execute,
  234. "augeas.method_map": self.mock_method_map,
  235. }
  236. with patch.dict(augeas.__salt__, mock_dict_):
  237. mock_isfile = MagicMock(return_value=False)
  238. with patch.object(os.path, "isfile", mock_isfile):
  239. self.assertDictEqual(
  240. augeas.change(
  241. self.name, context=self.context, changes=self.changes
  242. ),
  243. self.ret,
  244. )