test_client.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. # -*- coding: utf-8 -*-
  2. """
  3. :codeauthor: Mike Place <mp@saltstack.com>
  4. """
  5. # Import python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import pytest
  8. import salt.utils.platform
  9. # Import Salt libs
  10. from salt import client
  11. from salt.exceptions import (
  12. EauthAuthenticationError,
  13. SaltClientError,
  14. SaltInvocationError,
  15. SaltReqTimeoutError,
  16. )
  17. # Import Salt Testing libs
  18. from tests.support.mixins import SaltClientTestCaseMixin
  19. from tests.support.mock import MagicMock, patch
  20. from tests.support.unit import TestCase, skipIf
  21. class LocalClientTestCase(TestCase, SaltClientTestCaseMixin):
  22. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  23. def test_job_result_return_success(self):
  24. """
  25. Should return the `expected_return`, since there is a job with the right jid.
  26. """
  27. minions = ()
  28. jid = "0815"
  29. raw_return = {"id": "fake-id", "jid": jid, "data": "", "return": "fake-return"}
  30. expected_return = {"fake-id": {"ret": "fake-return"}}
  31. local_client = client.LocalClient(mopts=self.get_temp_config("master"))
  32. local_client.event.get_event = MagicMock(return_value=raw_return)
  33. local_client.returners = MagicMock()
  34. ret = local_client.get_event_iter_returns(jid, minions)
  35. val = next(ret)
  36. self.assertEqual(val, expected_return)
  37. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  38. def test_job_result_return_failure(self):
  39. """
  40. We are _not_ getting a job return, because the jid is different. Instead we should
  41. get a StopIteration exception.
  42. """
  43. minions = ()
  44. jid = "0815"
  45. raw_return = {
  46. "id": "fake-id",
  47. "jid": "0816",
  48. "data": "",
  49. "return": "fake-return",
  50. }
  51. local_client = client.LocalClient(mopts=self.get_temp_config("master"))
  52. local_client.event.get_event = MagicMock()
  53. local_client.event.get_event.side_effect = [raw_return, None]
  54. local_client.returners = MagicMock()
  55. ret = local_client.get_event_iter_returns(jid, minions)
  56. with self.assertRaises(StopIteration):
  57. next(ret)
  58. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  59. def test_create_local_client(self):
  60. local_client = client.LocalClient(mopts=self.get_temp_config("master"))
  61. self.assertIsInstance(
  62. local_client,
  63. client.LocalClient,
  64. "LocalClient did not create a LocalClient instance",
  65. )
  66. def test_check_pub_data(self):
  67. just_minions = {"minions": ["m1", "m2"]}
  68. jid_no_minions = {"jid": "1234", "minions": []}
  69. valid_pub_data = {"minions": ["m1", "m2"], "jid": "1234"}
  70. self.assertRaises(EauthAuthenticationError, self.client._check_pub_data, "")
  71. self.assertDictEqual(
  72. {},
  73. self.client._check_pub_data(just_minions),
  74. "Did not handle lack of jid correctly",
  75. )
  76. self.assertDictEqual(
  77. {},
  78. self.client._check_pub_data({"jid": "0"}),
  79. "Passing JID of zero is not handled gracefully",
  80. )
  81. with patch.dict(self.client.opts, {}):
  82. self.client._check_pub_data(jid_no_minions)
  83. self.assertDictEqual(
  84. valid_pub_data, self.client._check_pub_data(valid_pub_data)
  85. )
  86. def test_cmd_subset(self):
  87. with patch(
  88. "salt.client.LocalClient.cmd",
  89. return_value={
  90. "minion1": ["first.func", "second.func"],
  91. "minion2": ["first.func", "second.func"],
  92. },
  93. ):
  94. with patch("salt.client.LocalClient.cmd_cli") as cmd_cli_mock:
  95. self.client.cmd_subset("*", "first.func", sub=1, cli=True)
  96. try:
  97. cmd_cli_mock.assert_called_with(
  98. ["minion2"],
  99. "first.func",
  100. (),
  101. progress=False,
  102. kwarg=None,
  103. tgt_type="list",
  104. full_return=False,
  105. ret="",
  106. )
  107. except AssertionError:
  108. cmd_cli_mock.assert_called_with(
  109. ["minion1"],
  110. "first.func",
  111. (),
  112. progress=False,
  113. kwarg=None,
  114. tgt_type="list",
  115. full_return=False,
  116. ret="",
  117. )
  118. self.client.cmd_subset("*", "first.func", sub=10, cli=True)
  119. try:
  120. cmd_cli_mock.assert_called_with(
  121. ["minion2", "minion1"],
  122. "first.func",
  123. (),
  124. progress=False,
  125. kwarg=None,
  126. tgt_type="list",
  127. full_return=False,
  128. ret="",
  129. )
  130. except AssertionError:
  131. cmd_cli_mock.assert_called_with(
  132. ["minion1", "minion2"],
  133. "first.func",
  134. (),
  135. progress=False,
  136. kwarg=None,
  137. tgt_type="list",
  138. full_return=False,
  139. ret="",
  140. )
  141. ret = self.client.cmd_subset(
  142. "*", "first.func", sub=1, cli=True, full_return=True
  143. )
  144. try:
  145. cmd_cli_mock.assert_called_with(
  146. ["minion2"],
  147. "first.func",
  148. (),
  149. progress=False,
  150. kwarg=None,
  151. tgt_type="list",
  152. full_return=True,
  153. ret="",
  154. )
  155. except AssertionError:
  156. cmd_cli_mock.assert_called_with(
  157. ["minion1"],
  158. "first.func",
  159. (),
  160. progress=False,
  161. kwarg=None,
  162. tgt_type="list",
  163. full_return=True,
  164. ret="",
  165. )
  166. @skipIf(salt.utils.platform.is_windows(), "Not supported on Windows")
  167. def test_pub(self):
  168. """
  169. Tests that the client cleanly returns when the publisher is not running
  170. Note: Requires ZeroMQ's IPC transport which is not supported on windows.
  171. """
  172. if self.get_config("minion")["transport"] != "zeromq":
  173. self.skipTest("This test only works with ZeroMQ")
  174. # Make sure we cleanly return if the publisher isn't running
  175. with patch("os.path.exists", return_value=False):
  176. self.assertRaises(
  177. SaltClientError, lambda: self.client.pub("*", "test.ping")
  178. )
  179. # Check nodegroups behavior
  180. with patch("os.path.exists", return_value=True):
  181. with patch.dict(
  182. self.client.opts,
  183. {
  184. "nodegroups": {
  185. "group1": "L@foo.domain.com,bar.domain.com,baz.domain.com or bl*.domain.com"
  186. }
  187. },
  188. ):
  189. # Do we raise an exception if the nodegroup can't be matched?
  190. self.assertRaises(
  191. SaltInvocationError,
  192. self.client.pub,
  193. "non_existent_group",
  194. "test.ping",
  195. tgt_type="nodegroup",
  196. )
  197. @skipIf(not salt.utils.platform.is_windows(), "Windows only test")
  198. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  199. def test_pub_win32(self):
  200. """
  201. Tests that the client raises a timeout error when using ZeroMQ's TCP
  202. transport and publisher is not running.
  203. Note: Requires ZeroMQ's TCP transport, this is only the default on Windows.
  204. """
  205. if self.get_config("minion")["transport"] != "zeromq":
  206. self.skipTest("This test only works with ZeroMQ")
  207. # Make sure we cleanly return if the publisher isn't running
  208. with patch("os.path.exists", return_value=False):
  209. self.assertRaises(
  210. SaltReqTimeoutError, lambda: self.client.pub("*", "test.ping")
  211. )
  212. # Check nodegroups behavior
  213. with patch("os.path.exists", return_value=True):
  214. with patch.dict(
  215. self.client.opts,
  216. {
  217. "nodegroups": {
  218. "group1": "L@foo.domain.com,bar.domain.com,baz.domain.com or bl*.domain.com"
  219. }
  220. },
  221. ):
  222. # Do we raise an exception if the nodegroup can't be matched?
  223. self.assertRaises(
  224. SaltInvocationError,
  225. self.client.pub,
  226. "non_existent_group",
  227. "test.ping",
  228. tgt_type="nodegroup",
  229. )