test_output.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. # -*- coding: utf-8 -*-
  2. """
  3. :codeauthor: Nicole Thomas <nicole@saltstack.com>
  4. """
  5. # Import Salt Libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import os
  8. import traceback
  9. import pytest
  10. # Import Salt libs
  11. import salt.config
  12. import salt.utils.yaml
  13. from salt.ext import six
  14. from salt.output import display_output
  15. # Import Salt Testing Libs
  16. from tests.support.case import ShellCase
  17. from tests.support.mixins import RUNTIME_VARS
  18. class OutputReturnTest(ShellCase):
  19. """
  20. Integration tests to ensure outputters return their expected format.
  21. Tests against situations where the loader might not be returning the
  22. right outputter even though it was explicitly requested.
  23. """
  24. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  25. def test_output_json(self):
  26. """
  27. Tests the return of json-formatted data
  28. """
  29. ret = self.run_call("test.ping --out=json")
  30. self.assertIn("{", ret)
  31. self.assertIn('"local": true', "".join(ret))
  32. self.assertIn("}", "".join(ret))
  33. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  34. def test_output_nested(self):
  35. """
  36. Tests the return of nested-formatted data
  37. """
  38. expected = ["local:", " True"]
  39. ret = self.run_call("test.ping --out=nested")
  40. self.assertEqual(ret, expected)
  41. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  42. def test_output_quiet(self):
  43. """
  44. Tests the return of an out=quiet query
  45. """
  46. expected = []
  47. ret = self.run_call("test.ping --out=quiet")
  48. self.assertEqual(ret, expected)
  49. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  50. def test_output_pprint(self):
  51. """
  52. Tests the return of pprint-formatted data
  53. """
  54. expected = ["{u'local': True}"] if six.PY2 else ["{'local': True}"]
  55. ret = self.run_call("test.ping --out=pprint")
  56. self.assertEqual(ret, expected)
  57. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  58. def test_output_raw(self):
  59. """
  60. Tests the return of raw-formatted data
  61. """
  62. expected = ["{u'local': True}"] if six.PY2 else ["{'local': True}"]
  63. ret = self.run_call("test.ping --out=raw")
  64. self.assertEqual(ret, expected)
  65. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  66. def test_output_txt(self):
  67. """
  68. Tests the return of txt-formatted data
  69. """
  70. expected = ["local: True"]
  71. ret = self.run_call("test.ping --out=txt")
  72. self.assertEqual(ret, expected)
  73. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  74. def test_output_yaml(self):
  75. """
  76. Tests the return of yaml-formatted data
  77. """
  78. expected = ["local: true"]
  79. ret = self.run_call("test.ping --out=yaml")
  80. self.assertEqual(ret, expected)
  81. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  82. def test_output_yaml_namespaced_dict_wrapper(self):
  83. """
  84. Tests the ability to dump a NamespacedDictWrapper instance, as used in
  85. magic dunders like __grains__ and __pillar__
  86. See https://github.com/saltstack/salt/issues/49269
  87. """
  88. dumped_yaml = "\n".join(self.run_call("grains.items --out=yaml"))
  89. loaded_yaml = salt.utils.yaml.safe_load(dumped_yaml)
  90. # We just want to check that the dumped YAML loades as a dict with a
  91. # single top-level key, we don't care about the real contents.
  92. assert isinstance(loaded_yaml, dict)
  93. assert list(loaded_yaml) == ["local"]
  94. @pytest.mark.slow_test(seconds=0.5) # Test takes >0.1 and <=0.5 seconds
  95. def test_output_unicodebad(self):
  96. """
  97. Tests outputter reliability with utf8
  98. """
  99. opts = salt.config.minion_config(
  100. os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "minion")
  101. )
  102. opts["output_file"] = os.path.join(RUNTIME_VARS.TMP, "outputtest")
  103. data = {"foo": {"result": False, "aaa": "azerzaeréééé", "comment": "ééééàààà"}}
  104. try:
  105. # this should not raises UnicodeEncodeError
  106. display_output(data, opts=opts)
  107. except Exception: # pylint: disable=broad-except
  108. # display trace in error message for debugging on jenkins
  109. trace = traceback.format_exc()
  110. sentinel = object()
  111. old_max_diff = getattr(self, "maxDiff", sentinel)
  112. try:
  113. self.maxDiff = None
  114. self.assertEqual(trace, "")
  115. finally:
  116. if old_max_diff is sentinel:
  117. delattr(self, "maxDiff")
  118. else:
  119. self.maxDiff = old_max_diff
  120. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  121. def test_output_highstate(self):
  122. """
  123. Regression tests for the highstate outputter. Calls a basic state with various
  124. flags. Each comparison should be identical when successful.
  125. """
  126. # Test basic highstate output. No frills.
  127. expected = [
  128. "minion:",
  129. " ID: simple-ping",
  130. " Function: module.run",
  131. " Name: test.ping",
  132. " Result: True",
  133. " Comment: Module function test.ping executed",
  134. " Changes: ",
  135. " ret:",
  136. " True",
  137. "Summary for minion",
  138. "Succeeded: 1 (changed=1)",
  139. "Failed: 0",
  140. "Total states run: 1",
  141. ]
  142. state_run = self.run_salt('"minion" state.sls simple-ping')
  143. for expected_item in expected:
  144. self.assertIn(expected_item, state_run)
  145. # Test highstate output while also passing --out=highstate.
  146. # This is a regression test for Issue #29796
  147. state_run = self.run_salt('"minion" state.sls simple-ping --out=highstate')
  148. for expected_item in expected:
  149. self.assertIn(expected_item, state_run)
  150. # Test highstate output when passing --static and running a state function.
  151. # See Issue #44556.
  152. state_run = self.run_salt('"minion" state.sls simple-ping --static')
  153. for expected_item in expected:
  154. self.assertIn(expected_item, state_run)
  155. # Test highstate output when passing --static and --out=highstate.
  156. # See Issue #44556.
  157. state_run = self.run_salt(
  158. '"minion" state.sls simple-ping --static --out=highstate'
  159. )
  160. for expected_item in expected:
  161. self.assertIn(expected_item, state_run)
  162. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  163. def test_output_highstate_falls_back_nested(self):
  164. """
  165. Tests outputter when passing --out=highstate with a non-state call. This should
  166. fall back to "nested" output.
  167. """
  168. expected = ["minion:", " True"]
  169. ret = self.run_salt('"minion" test.ping --out=highstate')
  170. self.assertEqual(ret, expected)
  171. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  172. def test_static_simple(self):
  173. """
  174. Tests passing the --static option with a basic test.ping command. This
  175. should be the "nested" output.
  176. """
  177. expected = ["minion:", " True"]
  178. ret = self.run_salt('"minion" test.ping --static')
  179. self.assertEqual(ret, expected)