TestMain.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #!/usr/bin/env python
  2. '''
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. '''
  17. import StringIO
  18. import sys
  19. import unittest
  20. import logging
  21. import signal
  22. import os
  23. import socket
  24. import tempfile
  25. import ConfigParser
  26. from mock.mock import MagicMock, patch, ANY, Mock
  27. with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
  28. from ambari_agent import NetUtil, security
  29. from ambari_agent import ProcessHelper, main
  30. from ambari_agent import ProcessHelper, main
  31. from ambari_agent.AmbariConfig import AmbariConfig
  32. from ambari_agent.PingPortListener import PingPortListener
  33. from ambari_agent.Controller import Controller
  34. from ambari_agent.DataCleaner import DataCleaner
  35. class TestMain(unittest.TestCase):
  36. def setUp(self):
  37. # disable stdout
  38. out = StringIO.StringIO()
  39. sys.stdout = out
  40. def tearDown(self):
  41. # enable stdout
  42. sys.stdout = sys.__stdout__
  43. @patch("ambari_agent.HeartbeatStopHandler_linux")
  44. @patch("os._exit")
  45. @patch("os.getpid")
  46. @patch.object(ProcessHelper, "stopAgent")
  47. def test_signal_handler(self, stopAgent_mock, os_getpid_mock, os_exit_mock, heartbeat_handler_mock):
  48. # testing exit of children
  49. main.agentPid = 4444
  50. os_getpid_mock.return_value = 5555
  51. main.signal_handler("signum", "frame")
  52. heartbeat_handler_mock.set_stop.assert_called()
  53. os_exit_mock.reset_mock()
  54. # testing exit of main process
  55. os_getpid_mock.return_value = main.agentPid
  56. main.signal_handler("signum", "frame")
  57. heartbeat_handler_mock.set_stop.assert_called()
  58. @patch.object(main.logger, "addHandler")
  59. @patch.object(main.logger, "setLevel")
  60. @patch("logging.handlers.RotatingFileHandler")
  61. def test_setup_logging(self, rfh_mock, setLevel_mock, addHandler_mock):
  62. # Testing silent mode
  63. main.setup_logging(False)
  64. self.assertTrue(addHandler_mock.called)
  65. setLevel_mock.assert_called_with(logging.INFO)
  66. addHandler_mock.reset_mock()
  67. setLevel_mock.reset_mock()
  68. # Testing verbose mode
  69. main.setup_logging(True)
  70. self.assertTrue(addHandler_mock.called)
  71. setLevel_mock.assert_called_with(logging.DEBUG)
  72. @patch.object(main.logger, "setLevel")
  73. @patch("logging.basicConfig")
  74. def test_update_log_level(self, basicConfig_mock, setLevel_mock):
  75. config = AmbariConfig().getConfig()
  76. # Testing with default setup (config file does not contain loglevel entry)
  77. # Log level should not be changed
  78. config.set('agent', 'loglevel', None)
  79. main.update_log_level(config)
  80. self.assertFalse(setLevel_mock.called)
  81. setLevel_mock.reset_mock()
  82. # Testing debug mode
  83. config.set('agent', 'loglevel', 'DEBUG')
  84. main.update_log_level(config)
  85. setLevel_mock.assert_called_with(logging.DEBUG)
  86. setLevel_mock.reset_mock()
  87. # Testing any other mode
  88. config.set('agent', 'loglevel', 'INFO')
  89. main.update_log_level(config)
  90. setLevel_mock.assert_called_with(logging.INFO)
  91. setLevel_mock.reset_mock()
  92. config.set('agent', 'loglevel', 'WRONG')
  93. main.update_log_level(config)
  94. setLevel_mock.assert_called_with(logging.INFO)
  95. @patch("signal.signal")
  96. def test_bind_signal_handlers(self, signal_mock):
  97. main.bind_signal_handlers(os.getpid())
  98. # Check if on SIGINT/SIGTERM agent is configured to terminate
  99. signal_mock.assert_any_call(signal.SIGINT, main.signal_handler)
  100. signal_mock.assert_any_call(signal.SIGTERM, main.signal_handler)
  101. # Check if on SIGUSR1 agent is configured to fall into debug
  102. signal_mock.assert_any_call(signal.SIGUSR1, main.debug)
  103. @patch("os.path.exists")
  104. @patch("ConfigParser.RawConfigParser.read")
  105. def test_resolve_ambari_config(self, read_mock, exists_mock):
  106. # Trying case if conf file exists
  107. exists_mock.return_value = True
  108. main.resolve_ambari_config()
  109. self.assertTrue(read_mock.called)
  110. exists_mock.reset_mock()
  111. read_mock.reset_mock()
  112. # Trying case if conf file does not exist
  113. exists_mock.return_value = False
  114. main.resolve_ambari_config()
  115. self.assertFalse(read_mock.called)
  116. @patch("sys.exit")
  117. @patch("os.path.isfile")
  118. @patch("os.path.isdir")
  119. @patch("hostname.hostname")
  120. def test_perform_prestart_checks(self, hostname_mock, isdir_mock, isfile_mock, exit_mock):
  121. main.config = AmbariConfig().getConfig()
  122. # Check expected hostname test
  123. hostname_mock.return_value = "test.hst"
  124. main.perform_prestart_checks("another.hst")
  125. self.assertTrue(exit_mock.called)
  126. exit_mock.reset_mock()
  127. # Trying case if there is another instance running
  128. isfile_mock.return_value = True
  129. isdir_mock.return_value = True
  130. main.perform_prestart_checks(None)
  131. self.assertTrue(exit_mock.called)
  132. isfile_mock.reset_mock()
  133. isdir_mock.reset_mock()
  134. exit_mock.reset_mock()
  135. # Trying case if agent prefix dir does not exist
  136. isfile_mock.return_value = False
  137. isdir_mock.return_value = False
  138. main.perform_prestart_checks(None)
  139. self.assertTrue(exit_mock.called)
  140. isfile_mock.reset_mock()
  141. isdir_mock.reset_mock()
  142. exit_mock.reset_mock()
  143. # Trying normal case
  144. isfile_mock.return_value = False
  145. isdir_mock.return_value = True
  146. main.perform_prestart_checks(None)
  147. self.assertFalse(exit_mock.called)
  148. @patch("time.sleep")
  149. @patch("os.kill")
  150. @patch("os._exit")
  151. @patch("os.path.exists")
  152. def test_daemonize_and_stop(self, exists_mock, _exit_mock, kill_mock, sleep_mock):
  153. oldpid = ProcessHelper.pidfile
  154. pid = str(os.getpid())
  155. _, tmpoutfile = tempfile.mkstemp()
  156. ProcessHelper.pidfile = tmpoutfile
  157. # Test daemonization
  158. main.daemonize()
  159. saved = open(ProcessHelper.pidfile, 'r').read()
  160. self.assertEqual(pid, saved)
  161. # Reuse pid file when testing agent stop
  162. # Testing normal exit
  163. exists_mock.return_value = False
  164. main.stop_agent()
  165. kill_mock.assert_called_with(int(pid), signal.SIGTERM)
  166. _exit_mock.assert_called_with(0)
  167. # Restore
  168. kill_mock.reset_mock()
  169. _exit_mock.reset_mock()
  170. # Testing exit when failed to remove pid file
  171. exists_mock.return_value = True
  172. main.stop_agent()
  173. kill_mock.assert_any_call(int(pid), signal.SIGTERM)
  174. kill_mock.assert_any_call(int(pid), signal.SIGKILL)
  175. _exit_mock.assert_called_with(1)
  176. # Restore
  177. ProcessHelper.pidfile = oldpid
  178. os.remove(tmpoutfile)
  179. @patch("os.rmdir")
  180. @patch("os.path.join")
  181. @patch('__builtin__.open')
  182. @patch.object(ConfigParser, "ConfigParser")
  183. @patch("os._exit")
  184. @patch("os.walk")
  185. @patch("os.remove")
  186. def test_reset(self, os_remove_mock, os_walk_mock, os_exit_mock, config_parser_mock, open_mock, os_path_join_mock, os_rmdir_mock):
  187. # Agent config update
  188. config_mock = MagicMock()
  189. os_walk_mock.return_value = [('/', ('',), ('file1.txt', 'file2.txt'))]
  190. config_parser_mock.return_value= config_mock
  191. config_mock.get('server', 'hostname').return_value = "old_host"
  192. main.reset_agent(["test", "reset", "new_hostname"])
  193. self.assertEqual(config_mock.get.call_count, 3)
  194. self.assertEqual(config_mock.set.call_count, 1)
  195. self.assertEqual(os_remove_mock.call_count, 2)
  196. @patch("os.rmdir")
  197. @patch("os.path.join")
  198. @patch('__builtin__.open')
  199. @patch.object(ConfigParser, "ConfigParser")
  200. @patch("os._exit")
  201. @patch("os.walk")
  202. @patch("os.remove")
  203. def test_reset_invalid_path(self, os_remove_mock, os_walk_mock, os_exit_mock, config_parser_mock, open_mock, os_path_join_mock, os_rmdir_mock):
  204. # Agent config file cannot be accessed
  205. config_mock = MagicMock()
  206. os_walk_mock.return_value = [('/', ('',), ('file1.txt', 'file2.txt'))]
  207. config_parser_mock.return_value= config_mock
  208. config_mock.get('server', 'hostname').return_value = "old_host"
  209. open_mock.side_effect = Exception("Invalid Path!")
  210. try:
  211. main.reset_agent(["test", "reset", "new_hostname"])
  212. self.fail("Should have thrown exception!")
  213. except:
  214. self.assertTrue(True)
  215. @patch.object(socket, "gethostbyname")
  216. @patch.object(main, "setup_logging")
  217. @patch.object(main, "bind_signal_handlers")
  218. @patch.object(main, "stop_agent")
  219. @patch.object(AmbariConfig, "getConfigFile")
  220. @patch.object(main, "perform_prestart_checks")
  221. @patch.object(main, "daemonize")
  222. @patch.object(main, "update_log_level")
  223. @patch.object(NetUtil.NetUtil, "try_to_connect")
  224. @patch.object(Controller, "__init__")
  225. @patch.object(Controller, "start")
  226. @patch.object(Controller, "join")
  227. @patch("optparse.OptionParser.parse_args")
  228. @patch.object(DataCleaner,"start")
  229. @patch.object(DataCleaner,"__init__")
  230. @patch.object(PingPortListener,"start")
  231. @patch.object(PingPortListener,"__init__")
  232. def test_main(self, ping_port_init_mock, ping_port_start_mock, data_clean_init_mock,data_clean_start_mock,
  233. parse_args_mock, join_mock, start_mock, Controller_init_mock, try_to_connect_mock,
  234. update_log_level_mock, daemonize_mock, perform_prestart_checks_mock,
  235. ambari_config_mock,
  236. stop_mock, bind_signal_handlers_mock,
  237. setup_logging_mock, socket_mock):
  238. data_clean_init_mock.return_value = None
  239. Controller_init_mock.return_value = None
  240. ping_port_init_mock.return_value = None
  241. options = MagicMock()
  242. parse_args_mock.return_value = (options, MagicMock)
  243. try_to_connect_mock.return_value = (0, True)
  244. # use default unix config
  245. ambari_config_mock.return_value = os.path.abspath("../../../conf/unix/ambari-agent.ini")
  246. #testing call without command-line arguments
  247. main.main()
  248. self.assertTrue(setup_logging_mock.called)
  249. self.assertTrue(bind_signal_handlers_mock.called)
  250. self.assertTrue(stop_mock.called)
  251. #self.assertTrue(resolve_ambari_config_mock.called)
  252. self.assertTrue(perform_prestart_checks_mock.called)
  253. self.assertTrue(daemonize_mock.called)
  254. self.assertTrue(update_log_level_mock.called)
  255. try_to_connect_mock.assert_called_once_with(ANY, -1, ANY)
  256. self.assertTrue(start_mock.called)
  257. self.assertTrue(data_clean_init_mock.called)
  258. self.assertTrue(data_clean_start_mock.called)
  259. self.assertTrue(ping_port_init_mock.called)
  260. self.assertTrue(ping_port_start_mock.called)
  261. perform_prestart_checks_mock.reset_mock()
  262. # Testing call with --expected-hostname parameter
  263. options.expected_hostname = "test.hst"
  264. main.main()
  265. perform_prestart_checks_mock.assert_called_once_with(options.expected_hostname)