1
0

test_yamlloader.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. # -*- coding: utf-8 -*-
  2. """
  3. Unit tests for salt.utils.yamlloader.SaltYamlSafeLoader
  4. """
  5. # Import python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import collections
  8. import textwrap
  9. import salt.utils.files
  10. # Import 3rd-party libs
  11. from salt.ext import six
  12. from salt.utils.yamlloader import SaltYamlSafeLoader
  13. from tests.support.mock import mock_open, patch
  14. # Import Salt Testing Libs
  15. from tests.support.unit import TestCase
  16. # Import Salt Libs
  17. from yaml.constructor import ConstructorError
  18. class YamlLoaderTestCase(TestCase):
  19. """
  20. TestCase for salt.utils.yamlloader module
  21. """
  22. @staticmethod
  23. def render_yaml(data):
  24. """
  25. Takes a YAML string, puts it into a mock file, passes that to the YAML
  26. SaltYamlSafeLoader and then returns the rendered/parsed YAML data
  27. """
  28. if six.PY2:
  29. # On Python 2, data read from a filehandle will not already be
  30. # unicode, so we need to encode it first to properly simulate
  31. # reading from a file. This is because unicode_literals is imported
  32. # and all of the data to be used in mock_open will be a unicode
  33. # type. Encoding will make it a str.
  34. data = salt.utils.data.encode(data)
  35. with patch("salt.utils.files.fopen", mock_open(read_data=data)) as mocked_file:
  36. with salt.utils.files.fopen(mocked_file) as mocked_stream:
  37. return SaltYamlSafeLoader(mocked_stream).get_data()
  38. @staticmethod
  39. def raise_error(value):
  40. raise TypeError("{0!r} is not a unicode string".format(value))
  41. def assert_unicode(self, value):
  42. """
  43. Make sure the entire data structure is unicode
  44. """
  45. if six.PY3:
  46. return
  47. if isinstance(value, six.string_types):
  48. if not isinstance(value, six.text_type):
  49. self.raise_error(value)
  50. elif isinstance(value, collections.Mapping):
  51. for k, v in six.iteritems(value):
  52. self.assert_unicode(k)
  53. self.assert_unicode(v)
  54. elif isinstance(value, collections.Iterable):
  55. for item in value:
  56. self.assert_unicode(item)
  57. def assert_matches(self, ret, expected):
  58. self.assertEqual(ret, expected)
  59. self.assert_unicode(ret)
  60. def test_yaml_basics(self):
  61. """
  62. Test parsing an ordinary path
  63. """
  64. self.assert_matches(
  65. self.render_yaml(
  66. textwrap.dedent(
  67. """\
  68. p1:
  69. - alpha
  70. - beta"""
  71. )
  72. ),
  73. {"p1": ["alpha", "beta"]},
  74. )
  75. def test_yaml_merge(self):
  76. """
  77. Test YAML anchors
  78. """
  79. # Simple merge test
  80. self.assert_matches(
  81. self.render_yaml(
  82. textwrap.dedent(
  83. """\
  84. p1: &p1
  85. v1: alpha
  86. p2:
  87. <<: *p1
  88. v2: beta"""
  89. )
  90. ),
  91. {"p1": {"v1": "alpha"}, "p2": {"v1": "alpha", "v2": "beta"}},
  92. )
  93. # Test that keys/nodes are overwritten
  94. self.assert_matches(
  95. self.render_yaml(
  96. textwrap.dedent(
  97. """\
  98. p1: &p1
  99. v1: alpha
  100. p2:
  101. <<: *p1
  102. v1: new_alpha"""
  103. )
  104. ),
  105. {"p1": {"v1": "alpha"}, "p2": {"v1": "new_alpha"}},
  106. )
  107. # Test merging of lists
  108. self.assert_matches(
  109. self.render_yaml(
  110. textwrap.dedent(
  111. """\
  112. p1: &p1
  113. v1: &v1
  114. - t1
  115. - t2
  116. p2:
  117. v2: *v1"""
  118. )
  119. ),
  120. {"p2": {"v2": ["t1", "t2"]}, "p1": {"v1": ["t1", "t2"]}},
  121. )
  122. def test_yaml_duplicates(self):
  123. """
  124. Test that duplicates still throw an error
  125. """
  126. with self.assertRaises(ConstructorError):
  127. self.render_yaml(
  128. textwrap.dedent(
  129. """\
  130. p1: alpha
  131. p1: beta"""
  132. )
  133. )
  134. with self.assertRaises(ConstructorError):
  135. self.render_yaml(
  136. textwrap.dedent(
  137. """\
  138. p1: &p1
  139. v1: alpha
  140. p2:
  141. <<: *p1
  142. v2: beta
  143. v2: betabeta"""
  144. )
  145. )
  146. def test_yaml_with_plain_scalars(self):
  147. """
  148. Test that plain (i.e. unqoted) string and non-string scalars are
  149. properly handled
  150. """
  151. self.assert_matches(
  152. self.render_yaml(
  153. textwrap.dedent(
  154. """\
  155. foo:
  156. b: {foo: bar, one: 1, list: [1, two, 3]}"""
  157. )
  158. ),
  159. {"foo": {"b": {"foo": "bar", "one": 1, "list": [1, "two", 3]}}},
  160. )