TestExecuteResource.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. '''
  2. Licensed to the Apache Software Foundation (ASF) under one
  3. or more contributor license agreements. See the NOTICE file
  4. distributed with this work for additional information
  5. regarding copyright ownership. The ASF licenses this file
  6. to you under the Apache License, Version 2.0 (the
  7. "License"); you may not use this file except in compliance
  8. with the License. You may obtain a copy of the License at
  9. http://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing, software
  11. distributed under the License is distributed on an "AS IS" BASIS,
  12. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. See the License for the specific language governing permissions and
  14. limitations under the License.
  15. '''
  16. from unittest import TestCase
  17. from mock.mock import patch, MagicMock, call
  18. from resource_management.core.system import System
  19. from resource_management.core.resources.system import Execute
  20. from resource_management.core.environment import Environment
  21. import subprocess
  22. import logging
  23. import os
  24. from resource_management import Fail
  25. import grp
  26. import pwd
  27. @patch.object(System, "os_family", new='redhat')
  28. class TestExecuteResource(TestCase):
  29. @patch.object(logging.Logger, "info")
  30. @patch.object(subprocess, "Popen")
  31. def test_attribute_logoutput(self, popen_mock, info_mock):
  32. subproc_mock = MagicMock()
  33. subproc_mock.returncode = 0
  34. subproc_mock.communicate.side_effect = [["1"], ["2"]]
  35. popen_mock.return_value = subproc_mock
  36. with Environment("/") as env:
  37. Execute('echo "1"',
  38. logoutput=True)
  39. Execute('echo "2"',
  40. logoutput=False)
  41. info_mock.assert_called('1')
  42. self.assertTrue("call('2')" not in str(info_mock.mock_calls))
  43. @patch('subprocess.Popen.communicate')
  44. @patch('subprocess.Popen')
  45. def test_attribute_wait(self, popen_mock, proc_communicate_mock):
  46. with Environment("/") as env:
  47. Execute('echo "1"',
  48. wait_for_finish=False)
  49. Execute('echo "2"',
  50. wait_for_finish=False)
  51. self.assertTrue(popen_mock.called, 'subprocess.Popen should have been called!')
  52. self.assertFalse(proc_communicate_mock.called, 'proc.communicate should not have been called!')
  53. @patch.object(os.path, "exists")
  54. @patch.object(subprocess, "Popen")
  55. def test_attribute_creates(self, popen_mock, exists_mock):
  56. exists_mock.return_value = True
  57. subproc_mock = MagicMock()
  58. subproc_mock.returncode = 0
  59. subproc_mock.communicate.side_effect = [["1"]]
  60. popen_mock.return_value = subproc_mock
  61. with Environment("/") as env:
  62. Execute('echo "1"',
  63. creates="/must/be/created")
  64. exists_mock.assert_called_with("/must/be/created")
  65. self.assertEqual(subproc_mock.call_count, 0)
  66. @patch.object(subprocess, "Popen")
  67. def test_attribute_path(self, popen_mock):
  68. subproc_mock = MagicMock()
  69. subproc_mock.returncode = 0
  70. subproc_mock.communicate.side_effect = [["1"]]
  71. popen_mock.return_value = subproc_mock
  72. with Environment("/") as env:
  73. execute_resource = Execute('echo "1"',
  74. path=["/test/one", "test/two"]
  75. )
  76. expected_command = ['/bin/bash', '--login', '--noprofile', '-c', 'echo "1"']
  77. self.assertEqual(popen_mock.call_args_list[0][0][0], expected_command)
  78. @patch('time.sleep')
  79. @patch.object(subprocess, "Popen")
  80. def test_attribute_try_sleep_tries(self, popen_mock, time_mock):
  81. expected_call = "call('Retrying after %d seconds. Reason: %s', 1, 'Fail')"
  82. subproc_mock = MagicMock()
  83. subproc_mock.returncode = 0
  84. subproc_mock.communicate.side_effect = [Fail("Fail"), ["1"]]
  85. popen_mock.return_value = subproc_mock
  86. with Environment("/") as env:
  87. Execute('echo "1"',
  88. tries=2,
  89. try_sleep=10
  90. )
  91. pass
  92. time_mock.assert_called_once_with(10)
  93. @patch.object(pwd, "getpwnam")
  94. def test_attribute_group(self, getpwnam_mock):
  95. def error(argument):
  96. self.assertEqual(argument, "test_user")
  97. raise KeyError("fail")
  98. getpwnam_mock.side_effect = error
  99. try:
  100. with Environment("/") as env:
  101. Execute('echo "1"',
  102. user="test_user",
  103. )
  104. except Fail as e:
  105. pass
  106. @patch.object(grp, "getgrnam")
  107. @patch.object(pwd, "getpwnam")
  108. def test_attribute_group(self, getpwnam_mock, getgrnam_mock):
  109. def error(argument):
  110. self.assertEqual(argument, "test_group")
  111. raise KeyError("fail")
  112. getpwnam_mock.side_effect = 1
  113. getgrnam_mock.side_effect = error
  114. try:
  115. with Environment("/") as env:
  116. Execute('echo "1"',
  117. group="test_group",
  118. )
  119. except Fail as e:
  120. pass
  121. @patch.object(subprocess, "Popen")
  122. def test_attribute_environment(self, popen_mock):
  123. expected_dict = {"JAVA_HOME": "/test/java/home"}
  124. subproc_mock = MagicMock()
  125. subproc_mock.returncode = 0
  126. subproc_mock.communicate.side_effect = [["1"]]
  127. popen_mock.return_value = subproc_mock
  128. with Environment("/") as env:
  129. Execute('echo "1"',
  130. environment=expected_dict
  131. )
  132. self.assertEqual(popen_mock.call_args_list[0][1]["env"], expected_dict)
  133. pass
  134. @patch.object(subprocess, "Popen")
  135. def test_attribute_environment_non_root(self, popen_mock):
  136. expected_user = 'test_user'
  137. subproc_mock = MagicMock()
  138. subproc_mock.returncode = 0
  139. subproc_mock.communicate.side_effect = [["1"]]
  140. popen_mock.return_value = subproc_mock
  141. with Environment("/") as env:
  142. execute_resource = Execute('echo "1"',
  143. user=expected_user,
  144. environment={'JAVA_HOME': '/test/java/home',
  145. 'PATH': "/bin"}
  146. )
  147. expected_command = ['/bin/bash', '--login', '--noprofile', '-c', '/usr/bin/sudo su test_user -l -s /bin/bash -c \'export PATH=' + os.environ['PATH'] + ':/bin JAVA_HOME=/test/java/home ; echo "1"\'']
  148. self.assertEqual(popen_mock.call_args_list[0][0][0], expected_command)
  149. @patch.object(subprocess, "Popen")
  150. def test_attribute_cwd(self, popen_mock):
  151. expected_cwd = "/test/work/directory"
  152. subproc_mock = MagicMock()
  153. subproc_mock.returncode = 0
  154. subproc_mock.communicate.side_effect = [["1"]]
  155. popen_mock.return_value = subproc_mock
  156. with Environment("/") as env:
  157. Execute('echo "1"',
  158. cwd=expected_cwd
  159. )
  160. self.assertEqual(popen_mock.call_args_list[0][1]["cwd"], expected_cwd)
  161. @patch.object(subprocess, "Popen")
  162. def test_attribute_command_escaping(self, popen_mock):
  163. expected_command0 = "arg1 arg2 'quoted arg'"
  164. expected_command1 = "arg1 arg2 'command \"arg\"'"
  165. expected_command2 = 'arg1 arg2 \'command \'"\'"\'arg\'"\'"\'\''
  166. expected_command3 = "arg1 arg2 'echo `ls /root`'"
  167. expected_command4 = "arg1 arg2 '$ROOT'"
  168. expected_command5 = "arg1 arg2 '`ls /root`'"
  169. subproc_mock = MagicMock()
  170. subproc_mock.returncode = 0
  171. popen_mock.return_value = subproc_mock
  172. with Environment("/") as env:
  173. Execute(('arg1', 'arg2', 'quoted arg'),
  174. )
  175. Execute(('arg1', 'arg2', 'command "arg"'),
  176. )
  177. Execute(('arg1', 'arg2', "command 'arg'"),
  178. )
  179. Execute(('arg1', 'arg2', "echo `ls /root`"),
  180. )
  181. Execute(('arg1', 'arg2', "$ROOT"),
  182. )
  183. Execute(('arg1', 'arg2', "`ls /root`"),
  184. )
  185. self.assertEqual(popen_mock.call_args_list[0][0][0][4], expected_command0)
  186. self.assertEqual(popen_mock.call_args_list[1][0][0][4], expected_command1)
  187. self.assertEqual(popen_mock.call_args_list[2][0][0][4], expected_command2)
  188. self.assertEqual(popen_mock.call_args_list[3][0][0][4], expected_command3)
  189. self.assertEqual(popen_mock.call_args_list[4][0][0][4], expected_command4)
  190. self.assertEqual(popen_mock.call_args_list[5][0][0][4], expected_command5)
  191. @patch.object(subprocess, "Popen")
  192. def test_attribute_command_one_line(self, popen_mock):
  193. expected_command = "rm -rf /somedir"
  194. subproc_mock = MagicMock()
  195. subproc_mock.returncode = 0
  196. popen_mock.return_value = subproc_mock
  197. with Environment("/") as env:
  198. Execute(expected_command)
  199. self.assertEqual(popen_mock.call_args_list[0][0][0][4], expected_command)