test_ansiblegate.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #
  2. # Author: Bo Maryniuk <bo@suse.de>
  3. import os
  4. import sys
  5. import pytest
  6. import salt.modules.ansiblegate as ansible
  7. import salt.utils.path
  8. import salt.utils.platform
  9. from salt.exceptions import LoaderError
  10. from tests.support.mock import MagicMock, MockTimedProc, patch
  11. pytestmark = pytest.mark.skipif(
  12. salt.utils.platform.is_windows(), reason="Not supported on Windows"
  13. )
  14. @pytest.fixture
  15. def resolver():
  16. _resolver = ansible.AnsibleModuleResolver({})
  17. _resolver._modules_map = {
  18. "one.two.three": os.sep + os.path.join("one", "two", "three.py"),
  19. "four.five.six": os.sep + os.path.join("four", "five", "six.py"),
  20. "three.six.one": os.sep + os.path.join("three", "six", "one.py"),
  21. }
  22. return _resolver
  23. @pytest.fixture(autouse=True)
  24. def setup_loader():
  25. setup_loader_modules = {ansible: {}}
  26. with pytest.helpers.loader_mock(setup_loader_modules) as loader_mock:
  27. yield loader_mock
  28. def test_ansible_module_help(resolver):
  29. """
  30. Test help extraction from the module
  31. :return:
  32. """
  33. class Module:
  34. """
  35. An ansible module mock.
  36. """
  37. __name__ = "foo"
  38. DOCUMENTATION = """
  39. ---
  40. one:
  41. text here
  42. ---
  43. two:
  44. text here
  45. description:
  46. describe the second part
  47. """
  48. with patch.object(ansible, "_resolver", resolver), patch.object(
  49. ansible._resolver, "load_module", MagicMock(return_value=Module())
  50. ):
  51. ret = ansible.help("dummy")
  52. assert sorted(
  53. ret.get('Available sections on module "{}"'.format(Module().__name__))
  54. ) == ["one", "two"]
  55. assert ret.get("Description") == "describe the second part"
  56. def test_module_resolver_modlist(resolver):
  57. """
  58. Test Ansible resolver modules list.
  59. :return:
  60. """
  61. assert resolver.get_modules_list() == [
  62. "four.five.six",
  63. "one.two.three",
  64. "three.six.one",
  65. ]
  66. for ptr in ["five", "fi", "ve"]:
  67. assert resolver.get_modules_list(ptr) == ["four.five.six"]
  68. for ptr in ["si", "ix", "six"]:
  69. assert resolver.get_modules_list(ptr) == ["four.five.six", "three.six.one"]
  70. assert resolver.get_modules_list("one") == ["one.two.three", "three.six.one"]
  71. assert resolver.get_modules_list("one.two") == ["one.two.three"]
  72. assert resolver.get_modules_list("four") == ["four.five.six"]
  73. def test_resolver_module_loader_failure(resolver):
  74. """
  75. Test Ansible module loader.
  76. :return:
  77. """
  78. mod = "four.five.six"
  79. with pytest.raises(ImportError) as import_error:
  80. resolver.load_module(mod)
  81. mod = "i.even.do.not.exist.at.all"
  82. with pytest.raises(LoaderError) as loader_error:
  83. resolver.load_module(mod)
  84. def test_resolver_module_loader(resolver):
  85. """
  86. Test Ansible module loader.
  87. :return:
  88. """
  89. with patch("salt.modules.ansiblegate.importlib", MagicMock()), patch(
  90. "salt.modules.ansiblegate.importlib.import_module", lambda x: x
  91. ):
  92. assert resolver.load_module("four.five.six") == "ansible.modules.four.five.six"
  93. def test_resolver_module_loader_import_failure(resolver):
  94. """
  95. Test Ansible module loader failure.
  96. :return:
  97. """
  98. with patch("salt.modules.ansiblegate.importlib", MagicMock()), patch(
  99. "salt.modules.ansiblegate.importlib.import_module", lambda x: x
  100. ):
  101. with pytest.raises(LoaderError) as loader_error:
  102. resolver.load_module("something.strange")
  103. def test_virtual_function(resolver):
  104. """
  105. Test Ansible module __virtual__ when ansible is not installed on the minion.
  106. :return:
  107. """
  108. with patch("salt.modules.ansiblegate.ansible", None):
  109. assert ansible.__virtual__() == "ansible"
  110. def test_ansible_module_call(resolver):
  111. """
  112. Test Ansible module call from ansible gate module
  113. :return:
  114. """
  115. class Module:
  116. """
  117. An ansible module mock.
  118. """
  119. __name__ = "one.two.three"
  120. __file__ = "foofile"
  121. def main(): # pylint: disable=no-method-argument
  122. pass
  123. ANSIBLE_MODULE_ARGS = '{"ANSIBLE_MODULE_ARGS": ["arg_1", {"kwarg1": "foobar"}]}'
  124. proc = MagicMock(
  125. side_effect=[
  126. MockTimedProc(stdout=ANSIBLE_MODULE_ARGS.encode(), stderr=None),
  127. MockTimedProc(stdout=b'{"completed": true}', stderr=None),
  128. ]
  129. )
  130. with patch.object(ansible, "_resolver", resolver), patch.object(
  131. ansible._resolver, "load_module", MagicMock(return_value=Module())
  132. ):
  133. _ansible_module_caller = ansible.AnsibleModuleCaller(ansible._resolver)
  134. with patch("salt.utils.timed_subprocess.TimedProc", proc):
  135. ret = _ansible_module_caller.call("one.two.three", "arg_1", kwarg1="foobar")
  136. proc.assert_any_call(
  137. [sys.executable, "foofile"],
  138. stdin=ANSIBLE_MODULE_ARGS,
  139. stdout=-1,
  140. timeout=1200,
  141. )
  142. try:
  143. proc.assert_any_call(
  144. [
  145. "echo",
  146. '{"ANSIBLE_MODULE_ARGS": {"kwarg1": "foobar", "_raw_params": "arg_1"}}',
  147. ],
  148. stdout=-1,
  149. timeout=1200,
  150. )
  151. except AssertionError:
  152. proc.assert_any_call(
  153. [
  154. "echo",
  155. '{"ANSIBLE_MODULE_ARGS": {"_raw_params": "arg_1", "kwarg1": "foobar"}}',
  156. ],
  157. stdout=-1,
  158. timeout=1200,
  159. )
  160. assert ret == {"completed": True, "timeout": 1200}
  161. def test_ansible_playbooks_return_retcode(resolver):
  162. """
  163. Test ansible.playbooks execution module function include retcode in the return.
  164. :return:
  165. """
  166. ref_out = {"retcode": 0, "stdout": '{"foo": "bar"}'}
  167. cmd_run_all = MagicMock(return_value=ref_out)
  168. with patch.dict(ansible.__salt__, {"cmd.run_all": cmd_run_all}), patch(
  169. "salt.utils.path.which", MagicMock(return_value=True)
  170. ):
  171. ret = ansible.playbooks("fake-playbook.yml")
  172. assert "retcode" in ret