TestResourceFilesKeeper.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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. import os
  17. os.environ["ROOT"] = ""
  18. import time
  19. import subprocess
  20. import os
  21. import logging
  22. import tempfile
  23. import pprint
  24. from xml.dom import minidom
  25. from unittest import TestCase
  26. from subprocess import Popen
  27. from mock.mock import MagicMock, call
  28. from mock.mock import patch
  29. from mock.mock import create_autospec
  30. from only_for_platform import get_platform, not_for_platform, only_for_platform, os_distro_value, PLATFORM_WINDOWS
  31. from ambari_server.resourceFilesKeeper import ResourceFilesKeeper, KeeperException
  32. class TestResourceFilesKeeper(TestCase):
  33. TEST_RESOURCES_DIR = ".." + os.sep + "resources"
  34. TEST_STACKS_DIR = ".." + os.sep + "resources" + os.sep + "stacks"
  35. # Stack that is not expected to change
  36. DUMMY_UNCHANGEABLE_STACK = ".." + os.sep + "resources" + os.sep + "TestAmbaryServer.samples" + os.sep + \
  37. "dummy_stack" + os.sep + "HIVE"
  38. DUMMY_ACTIVE_STACK = ".." + os.sep + "resources" + os.sep + "TestAmbaryServer.samples" + os.sep + \
  39. "active_stack"
  40. DUMMY_INACTIVE_STACK = ".." + os.sep + "resources" + os.sep + "TestAmbaryServer.samples" + os.sep + \
  41. "inactive_stack"
  42. DUMMY_UNCHANGEABLE_PACKAGE=os.path.join(DUMMY_UNCHANGEABLE_STACK,
  43. ResourceFilesKeeper.PACKAGE_DIR)
  44. if get_platform() != PLATFORM_WINDOWS:
  45. DUMMY_UNCHANGEABLE_PACKAGE_HASH="11c9ed5f7987b41ce5d7adaedd6dd08c9cc9b418"
  46. else:
  47. DUMMY_UNCHANGEABLE_PACKAGE_HASH="2e438f4f9862420ed8930a56b8809b8aca359e87"
  48. DUMMY_HASH="dummy_hash"
  49. YA_HASH="yet_another_hash"
  50. SOME_PATH="some-path"
  51. DUMMY_UNCHANGEABLE_COMMON_SERVICES=".." + os.sep + "resources" + os.sep + "TestAmbaryServer.samples" + os.sep + \
  52. "dummy_common_services" + os.sep + "HIVE" + os.sep + "0.11.0.2.0.5.0"
  53. DUMMY_UNCHANGEABLE_COMMON_SERVICES_PACKAGE=os.path.join(DUMMY_UNCHANGEABLE_COMMON_SERVICES,
  54. ResourceFilesKeeper.PACKAGE_DIR)
  55. if get_platform() != PLATFORM_WINDOWS:
  56. UPDATE_DIRECTORY_ARCHIVE_CALL_LIST = \
  57. "[call('../resources/TestAmbaryServer.samples/" \
  58. "dummy_stack/HIVE/package'),\n " \
  59. "call('../resources/TestAmbaryServer.samples/" \
  60. "dummy_stack/HIVE/package'),\n " \
  61. "call('../resources/TestAmbaryServer.samples/" \
  62. "dummy_stack/HIVE/package'),\n " \
  63. "call('../resources/TestAmbaryServer.samples/" \
  64. "dummy_common_services/HIVE/0.11.0.2.0.5.0/package'),\n " \
  65. "call('../resources/TestAmbaryServer.samples/" \
  66. "dummy_common_services/HIVE/0.11.0.2.0.5.0/package'),\n " \
  67. "call('../resources/custom_actions'),\n " \
  68. "call('../resources/host_scripts')]"
  69. else:
  70. UPDATE_DIRECTORY_ARCHIVE_CALL_LIST = \
  71. "[call('..\\\\resources\\\\TestAmbaryServer.samples\\\\dummy_stack\\\\HIVE\\\\package'),\n " \
  72. "call('..\\\\resources\\\\TestAmbaryServer.samples\\\\dummy_stack\\\\HIVE\\\\package'),\n " \
  73. "call('..\\\\resources\\\\TestAmbaryServer.samples\\\\dummy_stack\\\\HIVE\\\\package'),\n " \
  74. "call('..\\\\resources\\\\TestAmbaryServer.samples\\\\dummy_common_services\\\\HIVE\\\\0.11.0.2.0.5.0\\\\package'),\n " \
  75. "call('..\\\\resources\\\\TestAmbaryServer.samples\\\\dummy_common_services\\\\HIVE\\\\0.11.0.2.0.5.0\\\\package'),\n " \
  76. "call('..\\\\resources\\\\custom_actions'),\n " \
  77. "call('..\\\\resources\\\\host_scripts')]"
  78. def setUp(self):
  79. logging.basicConfig(level=logging.ERROR)
  80. @patch.object(ResourceFilesKeeper, "update_directory_archieves")
  81. def test_perform_housekeeping(self, update_directory_archieves_mock):
  82. resource_files_keeper = ResourceFilesKeeper(os.sep + "dummy-resources", os.sep + "dummy-path")
  83. resource_files_keeper.perform_housekeeping()
  84. update_directory_archieves_mock.assertCalled()
  85. pass
  86. @patch.object(ResourceFilesKeeper, "update_directory_archive")
  87. @patch.object(ResourceFilesKeeper, "list_common_services")
  88. @patch.object(ResourceFilesKeeper, "list_stacks")
  89. @patch("os.path.abspath")
  90. def test_update_directory_archieves(self, abspath_mock,
  91. list_active_stacks_mock,
  92. list_common_services_mock,
  93. update_directory_archive_mock):
  94. list_active_stacks_mock.return_value = [self.DUMMY_UNCHANGEABLE_STACK,
  95. self.DUMMY_UNCHANGEABLE_STACK,
  96. self.DUMMY_UNCHANGEABLE_STACK]
  97. list_common_services_mock.return_value = [self.DUMMY_UNCHANGEABLE_COMMON_SERVICES,
  98. self.DUMMY_UNCHANGEABLE_COMMON_SERVICES]
  99. abspath_mock.side_effect = lambda s : s
  100. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.TEST_STACKS_DIR)
  101. resource_files_keeper.update_directory_archieves()
  102. self.assertEquals(pprint.pformat(
  103. update_directory_archive_mock.call_args_list),
  104. self.UPDATE_DIRECTORY_ARCHIVE_CALL_LIST)
  105. pass
  106. @patch("glob.glob")
  107. @patch("os.path.exists")
  108. def test_list_stacks(self, exists_mock, glob_mock):
  109. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.SOME_PATH)
  110. # Test normal execution flow
  111. glob_mock.return_value = ["stack1", "stack2", "stack3"]
  112. exists_mock.side_effect = [True, False, True]
  113. res = resource_files_keeper.list_stacks(self.SOME_PATH)
  114. self.assertEquals(pprint.pformat(res), "['stack1', 'stack3']")
  115. # Test exception handling
  116. glob_mock.side_effect = self.keeper_exc_side_effect
  117. try:
  118. resource_files_keeper.list_stacks(self.SOME_PATH)
  119. self.fail('KeeperException not thrown')
  120. except KeeperException:
  121. pass # Expected
  122. except Exception, e:
  123. self.fail('Unexpected exception thrown:' + str(e))
  124. @patch("glob.glob")
  125. @patch("os.path.exists")
  126. def test_list_common_services(self, exists_mock, glob_mock):
  127. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.SOME_PATH)
  128. # Test normal execution flow
  129. glob_mock.return_value = ["common_service1", "common_service2", "common_service3"]
  130. exists_mock.side_effect = [True, False, True]
  131. res = resource_files_keeper.list_common_services(self.SOME_PATH)
  132. self.assertEquals(pprint.pformat(res), "['common_service1', 'common_service3']")
  133. # Test exception handling
  134. glob_mock.side_effect = self.keeper_exc_side_effect
  135. try:
  136. resource_files_keeper.list_common_services(self.SOME_PATH)
  137. self.fail('KeeperException not thrown')
  138. except KeeperException:
  139. pass # Expected
  140. except Exception, e:
  141. self.fail('Unexpected exception thrown:' + str(e))
  142. @patch("os.listdir")
  143. @patch.object(ResourceFilesKeeper, "count_hash_sum")
  144. @patch.object(ResourceFilesKeeper, "read_hash_sum")
  145. @patch.object(ResourceFilesKeeper, "zip_directory")
  146. @patch.object(ResourceFilesKeeper, "write_hash_sum")
  147. def test_update_directory_archive(self, write_hash_sum_mock,
  148. zip_directory_mock, read_hash_sum_mock,
  149. count_hash_sum_mock,
  150. os_listdir_mock):
  151. os_listdir_mock.return_value = ['file1', 'dir1']
  152. # Test situation when there is no saved directory hash
  153. read_hash_sum_mock.return_value = None
  154. count_hash_sum_mock.return_value = self.YA_HASH
  155. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.SOME_PATH)
  156. resource_files_keeper.update_directory_archive(self.SOME_PATH)
  157. self.assertTrue(read_hash_sum_mock.called)
  158. self.assertTrue(count_hash_sum_mock.called)
  159. self.assertTrue(zip_directory_mock.called)
  160. self.assertTrue(write_hash_sum_mock.called)
  161. read_hash_sum_mock.reset_mock()
  162. count_hash_sum_mock.reset_mock()
  163. zip_directory_mock.reset_mock()
  164. write_hash_sum_mock.reset_mock()
  165. # Test situation when saved directory hash == current hash
  166. read_hash_sum_mock.return_value = self.DUMMY_HASH
  167. count_hash_sum_mock.return_value = self.YA_HASH
  168. resource_files_keeper.update_directory_archive(self.SOME_PATH)
  169. self.assertTrue(read_hash_sum_mock.called)
  170. self.assertTrue(count_hash_sum_mock.called)
  171. self.assertTrue(zip_directory_mock.called)
  172. self.assertTrue(write_hash_sum_mock.called)
  173. read_hash_sum_mock.reset_mock()
  174. count_hash_sum_mock.reset_mock()
  175. zip_directory_mock.reset_mock()
  176. write_hash_sum_mock.reset_mock()
  177. # Test situation when saved directory hash == current hash
  178. read_hash_sum_mock.return_value = self.DUMMY_HASH
  179. count_hash_sum_mock.return_value = self.DUMMY_HASH
  180. resource_files_keeper.update_directory_archive(self.SOME_PATH)
  181. self.assertTrue(read_hash_sum_mock.called)
  182. self.assertTrue(count_hash_sum_mock.called)
  183. self.assertFalse(zip_directory_mock.called)
  184. self.assertFalse(write_hash_sum_mock.called)
  185. read_hash_sum_mock.reset_mock()
  186. count_hash_sum_mock.reset_mock()
  187. zip_directory_mock.reset_mock()
  188. write_hash_sum_mock.reset_mock()
  189. # Check that no saved hash file is created when zipping failed
  190. zip_directory_mock.side_effect = self.keeper_exc_side_effect
  191. read_hash_sum_mock.return_value = self.DUMMY_HASH
  192. count_hash_sum_mock.return_value = self.YA_HASH
  193. try:
  194. resource_files_keeper.update_directory_archive(self.SOME_PATH)
  195. self.fail('KeeperException not thrown')
  196. except KeeperException:
  197. pass # Expected
  198. except Exception, e:
  199. self.fail('Unexpected exception thrown:' + str(e))
  200. self.assertTrue(read_hash_sum_mock.called)
  201. self.assertTrue(count_hash_sum_mock.called)
  202. self.assertTrue(zip_directory_mock.called)
  203. self.assertFalse(write_hash_sum_mock.called)
  204. read_hash_sum_mock.reset_mock()
  205. count_hash_sum_mock.reset_mock()
  206. zip_directory_mock.reset_mock()
  207. write_hash_sum_mock.reset_mock()
  208. # Test nozip option
  209. read_hash_sum_mock.return_value = None
  210. count_hash_sum_mock.return_value = self.YA_HASH
  211. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.SOME_PATH, nozip=True)
  212. resource_files_keeper.update_directory_archive(self.SOME_PATH)
  213. self.assertTrue(read_hash_sum_mock.called)
  214. self.assertTrue(count_hash_sum_mock.called)
  215. self.assertFalse(zip_directory_mock.called)
  216. self.assertTrue(write_hash_sum_mock.called)
  217. # Test empty directory
  218. read_hash_sum_mock.reset_mock()
  219. count_hash_sum_mock.reset_mock()
  220. zip_directory_mock.reset_mock()
  221. write_hash_sum_mock.reset_mock()
  222. # If the input directory is empty, then write_hash_sum() should not be called
  223. os_listdir_mock.return_value = [] # Empty dir
  224. zip_directory_mock.side_effect = None
  225. read_hash_sum_mock.return_value = None # hash read from .hash file
  226. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.SOME_PATH)
  227. resource_files_keeper.update_directory_archive(self.SOME_PATH)
  228. self.assertTrue(read_hash_sum_mock.called)
  229. self.assertTrue(count_hash_sum_mock.called)
  230. self.assertTrue(zip_directory_mock.called)
  231. self.assertFalse(write_hash_sum_mock.called)
  232. pass
  233. def test_count_hash_sum(self):
  234. # Test normal flow
  235. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.DUMMY_UNCHANGEABLE_PACKAGE)
  236. test_dir = os.path.join(self.DUMMY_UNCHANGEABLE_PACKAGE)
  237. hash_sum = resource_files_keeper.count_hash_sum(test_dir)
  238. self.assertEquals(hash_sum, self.DUMMY_UNCHANGEABLE_PACKAGE_HASH)
  239. # Test exception handling
  240. with patch("__builtin__.open") as open_mock:
  241. open_mock.side_effect = self.exc_side_effect
  242. try:
  243. resource_files_keeper.count_hash_sum(test_dir)
  244. self.fail('KeeperException not thrown')
  245. except KeeperException:
  246. pass # Expected
  247. except Exception, e:
  248. self.fail('Unexpected exception thrown:' + str(e))
  249. def test_read_hash_sum(self):
  250. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.DUMMY_UNCHANGEABLE_PACKAGE)
  251. hash_sum = resource_files_keeper.read_hash_sum(self.DUMMY_UNCHANGEABLE_PACKAGE)
  252. self.assertEquals(hash_sum, "dummy_hash")
  253. # Test exception handling
  254. # If file exists, should rethrow exception
  255. with patch("os.path.isfile") as isfile_mock:
  256. isfile_mock.return_value = True
  257. with patch("__builtin__.open") as open_mock:
  258. open_mock.side_effect = self.exc_side_effect
  259. try:
  260. resource_files_keeper.read_hash_sum("path-to-directory")
  261. self.fail('KeeperException not thrown')
  262. except KeeperException:
  263. pass # Expected
  264. except Exception, e:
  265. self.fail('Unexpected exception thrown:' + str(e))
  266. # Test exception handling
  267. # If file does not exist, should ignore exception
  268. with patch("os.path.isfile") as isfile_mock:
  269. isfile_mock.return_value = False
  270. with patch("__builtin__.open") as open_mock:
  271. open_mock.side_effect = self.exc_side_effect
  272. res = resource_files_keeper.read_hash_sum("path-to-directory")
  273. self.assertEqual(res, None)
  274. pass
  275. def test_write_hash_sum(self):
  276. NEW_HASH = "new_hash"
  277. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.DUMMY_UNCHANGEABLE_PACKAGE)
  278. resource_files_keeper.write_hash_sum(
  279. self.DUMMY_UNCHANGEABLE_PACKAGE, NEW_HASH)
  280. hash_sum = resource_files_keeper.read_hash_sum(self.DUMMY_UNCHANGEABLE_PACKAGE)
  281. self.assertEquals(hash_sum, NEW_HASH)
  282. # Revert to previous value
  283. resource_files_keeper.write_hash_sum(
  284. self.DUMMY_UNCHANGEABLE_PACKAGE, self.DUMMY_HASH)
  285. hash_sum = resource_files_keeper.read_hash_sum(self.DUMMY_UNCHANGEABLE_PACKAGE)
  286. self.assertEquals(hash_sum, self.DUMMY_HASH)
  287. # Test exception handling
  288. with patch("__builtin__.open") as open_mock:
  289. open_mock.side_effect = self.exc_side_effect
  290. try:
  291. resource_files_keeper.write_hash_sum("path-to-directory", self.DUMMY_HASH)
  292. self.fail('KeeperException not thrown')
  293. except KeeperException:
  294. pass # Expected
  295. except Exception, e:
  296. self.fail('Unexpected exception thrown:' + str(e))
  297. def test_zip_directory(self):
  298. # Test normal flow
  299. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.DUMMY_UNCHANGEABLE_PACKAGE)
  300. resource_files_keeper.zip_directory(self.DUMMY_UNCHANGEABLE_PACKAGE)
  301. arc_file = os.path.join(self.DUMMY_UNCHANGEABLE_PACKAGE,
  302. ResourceFilesKeeper.ARCHIVE_NAME)
  303. # Arc file should not be empty
  304. arc_size=os.path.getsize(arc_file)
  305. self.assertTrue(40000 < arc_size < 50000)
  306. # After creating zip, count hash sum of dir (should not change)
  307. hash_val = resource_files_keeper.count_hash_sum(self.DUMMY_UNCHANGEABLE_PACKAGE)
  308. self.assertEquals(hash_val, self.DUMMY_UNCHANGEABLE_PACKAGE_HASH)
  309. # Remove arc file
  310. os.unlink(arc_file)
  311. # Test exception handling
  312. with patch("os.path.join") as join_mock:
  313. join_mock.side_effect = self.exc_side_effect
  314. try:
  315. resource_files_keeper.zip_directory("path-to-directory")
  316. self.fail('KeeperException not thrown')
  317. except KeeperException:
  318. pass # Expected
  319. except Exception, e:
  320. self.fail('Unexpected exception thrown:' + str(e))
  321. # Test skip zipping of an empty directory
  322. with patch("os.listdir") as os_listdir_mock:
  323. os_listdir_mock.return_value = False # Empty dir
  324. try:
  325. skip_empty_directory = True
  326. resource_files_keeper.zip_directory("empty-to-directory", skip_empty_directory)
  327. self.assertTrue(os_listdir_mock.called)
  328. except Exception, e:
  329. self.fail('Unexpected exception thrown: ' + str(e))
  330. pass
  331. def test_is_ignored(self):
  332. resource_files_keeper = ResourceFilesKeeper(self.TEST_RESOURCES_DIR, self.DUMMY_UNCHANGEABLE_PACKAGE)
  333. self.assertTrue(resource_files_keeper.is_ignored(".hash"))
  334. self.assertTrue(resource_files_keeper.is_ignored("archive.zip"))
  335. self.assertTrue(resource_files_keeper.is_ignored("dummy.pyc"))
  336. self.assertFalse(resource_files_keeper.is_ignored("dummy.py"))
  337. self.assertFalse(resource_files_keeper.is_ignored("1.sh"))
  338. pass
  339. def exc_side_effect(self, *a):
  340. raise Exception("horrible_exc")
  341. def keeper_exc_side_effect(self, *a):
  342. raise KeeperException("horrible_keeper_exc")