test_saltify.py 7.5 KB

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