test_saltify.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: Alexander Schwartz <alexander.schwartz@gmx.net>
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. # Import Salt Testing Libs
  8. from tests.support.mixins import LoaderModuleMockMixin
  9. from tests.support.unit import skipIf, TestCase
  10. from tests.support.mock import MagicMock, NO_MOCK, NO_MOCK_REASON, patch, ANY
  11. # Import Salt Libs
  12. import salt.client
  13. from salt.cloud.clouds import saltify
  14. TEST_PROFILES = {
  15. 'testprofile1': NotImplemented,
  16. 'testprofile2': { # this profile is used in test_saltify_destroy()
  17. 'ssh_username': 'fred',
  18. 'remove_config_on_destroy': False, # expected for test
  19. 'shutdown_on_destroy': True # expected value for test
  20. },
  21. 'testprofile3': { # this profile is used in test_create_wake_on_lan()
  22. 'wake_on_lan_mac': 'aa-bb-cc-dd-ee-ff',
  23. 'wol_sender_node': 'friend1',
  24. 'wol_boot_wait': 0.01 # we want the wait to be very short
  25. }
  26. }
  27. TEST_PROFILE_NAMES = ['testprofile1', 'testprofile2', 'testprofile3']
  28. @skipIf(NO_MOCK, NO_MOCK_REASON)
  29. class SaltifyTestCase(TestCase, LoaderModuleMockMixin):
  30. '''
  31. Test cases for salt.cloud.clouds.saltify
  32. '''
  33. LOCAL_OPTS = {
  34. 'providers': {
  35. 'sfy1': {
  36. 'saltify': {
  37. 'driver': 'saltify',
  38. 'profiles': TEST_PROFILES
  39. }
  40. },
  41. },
  42. 'profiles': TEST_PROFILES,
  43. 'sock_dir': '/var/sockxxx',
  44. 'transport': 'tcp',
  45. }
  46. def setup_loader_modules(self):
  47. saltify_globals = {
  48. '__active_provider_name__': '',
  49. '__utils__': {
  50. 'cloud.bootstrap': MagicMock(),
  51. 'cloud.fire_event': MagicMock(),
  52. },
  53. '__opts__': self.LOCAL_OPTS,
  54. }
  55. return {saltify: saltify_globals}
  56. def test_create_no_deploy(self):
  57. '''
  58. Test if deployment fails. This is the most basic test as saltify doesn't contain much logic
  59. '''
  60. with patch('salt.cloud.clouds.saltify._verify', MagicMock(return_value=True)):
  61. vm = {'deploy': False,
  62. 'driver': 'saltify',
  63. 'name': 'dummy'
  64. }
  65. self.assertTrue(saltify.create(vm))
  66. def test_create_and_deploy(self):
  67. '''
  68. Test if deployment can be done.
  69. '''
  70. mock_cmd = MagicMock(return_value=True)
  71. with patch.dict(
  72. 'salt.cloud.clouds.saltify.__utils__',
  73. {'cloud.bootstrap': mock_cmd}):
  74. vm_ = {'deploy': True,
  75. 'driver': 'saltify',
  76. 'name': 'new2',
  77. 'profile': 'testprofile2',
  78. }
  79. result = saltify.create(vm_)
  80. mock_cmd.assert_called_once_with(vm_, ANY)
  81. self.assertTrue(result)
  82. def test_create_wake_on_lan(self):
  83. '''
  84. Test if wake on lan works
  85. '''
  86. mock_sleep = MagicMock()
  87. mock_cmd = MagicMock(return_value=True)
  88. mm_cmd = MagicMock(return_value={'friend1': True})
  89. lcl = salt.client.LocalClient()
  90. lcl.cmd = mm_cmd
  91. with patch('time.sleep', mock_sleep):
  92. with patch('salt.client.LocalClient', return_value=lcl):
  93. with patch.dict(
  94. 'salt.cloud.clouds.saltify.__utils__',
  95. {'cloud.bootstrap': mock_cmd}):
  96. vm_ = {'deploy': True,
  97. 'driver': 'saltify',
  98. 'name': 'new1',
  99. 'profile': 'testprofile3',
  100. }
  101. result = saltify.create(vm_)
  102. mock_cmd.assert_called_once_with(vm_, ANY)
  103. mm_cmd.assert_called_with('friend1', 'network.wol', ['aa-bb-cc-dd-ee-ff'])
  104. # The test suite might call time.sleep, look for any call
  105. # that has the expected wait time.
  106. mock_sleep.assert_any_call(0.01)
  107. self.assertTrue(result)
  108. def test_avail_locations(self):
  109. '''
  110. Test the avail_locations will always return {}
  111. '''
  112. self.assertEqual(saltify.avail_locations(), {})
  113. def test_avail_sizes(self):
  114. '''
  115. Test the avail_sizes will always return {}
  116. '''
  117. self.assertEqual(saltify.avail_sizes(), {})
  118. def test_avail_images(self):
  119. '''
  120. Test the avail_images will return profiles
  121. '''
  122. testlist = list(TEST_PROFILE_NAMES) # copy
  123. self.assertEqual(
  124. saltify.avail_images()['Profiles'].sort(),
  125. testlist.sort())
  126. def test_list_nodes(self):
  127. '''
  128. Test list_nodes will return required fields only
  129. '''
  130. testgrains = {
  131. 'nodeX1': {
  132. 'id': 'nodeX1',
  133. 'ipv4': [
  134. '127.0.0.1', '192.1.2.22', '172.16.17.18'],
  135. 'ipv6': [
  136. '::1', 'fdef:bad:add::f00', '3001:DB8::F00D'],
  137. 'salt-cloud': {
  138. 'driver': 'saltify',
  139. 'provider': 'saltyfy',
  140. 'profile': 'testprofile2'
  141. },
  142. 'extra_stuff': 'does not belong'
  143. }
  144. }
  145. expected_result = {
  146. 'nodeX1': {
  147. 'id': 'nodeX1',
  148. 'image': 'testprofile2',
  149. 'private_ips': [
  150. '172.16.17.18', 'fdef:bad:add::f00'],
  151. 'public_ips': [
  152. '192.1.2.22', '3001:DB8::F00D'],
  153. 'size': '',
  154. 'state': 'running'
  155. }
  156. }
  157. mm_cmd = MagicMock(return_value=testgrains)
  158. lcl = salt.client.LocalClient()
  159. lcl.cmd = mm_cmd
  160. with patch('salt.client.LocalClient', return_value=lcl):
  161. self.assertEqual(
  162. saltify.list_nodes(),
  163. expected_result)
  164. def test_saltify_reboot(self):
  165. mm_cmd = MagicMock(return_value=True)
  166. lcl = salt.client.LocalClient()
  167. lcl.cmd = mm_cmd
  168. with patch('salt.client.LocalClient', return_value=lcl):
  169. result = saltify.reboot('nodeS1', 'action')
  170. mm_cmd.assert_called_with('nodeS1', 'system.reboot')
  171. self.assertTrue(result)
  172. def test_saltify_destroy(self):
  173. # destroy calls local.cmd several times and expects
  174. # different results, so we will provide a list of
  175. # results. Each call will get the next value.
  176. # NOTE: this assumes that the call order never changes,
  177. # so to keep things simple, we will not use remove_config...
  178. result_list = [
  179. {'nodeS1': { # first call is grains.get
  180. 'driver': 'saltify',
  181. 'provider': 'saltify',
  182. 'profile': 'testprofile2'}
  183. },
  184. # Note:
  185. # testprofile2 has remove_config_on_destroy: False
  186. # and shutdown_on_destroy: True
  187. {'nodeS1': # last call shuts down the minion
  188. 'a system.shutdown worked message'},
  189. ]
  190. mm_cmd = MagicMock(side_effect=result_list)
  191. lcl = salt.client.LocalClient()
  192. lcl.cmd = mm_cmd
  193. with patch('salt.client.LocalClient', return_value=lcl):
  194. result = saltify.destroy('nodeS1', 'action')
  195. mm_cmd.assert_called_with('nodeS1', 'system.shutdown')
  196. self.assertTrue(result)