test_roots.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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 copy
  8. import os
  9. import tempfile
  10. import pytest
  11. import salt.fileclient
  12. # Import Salt libs
  13. import salt.fileserver.roots as roots
  14. import salt.utils.files
  15. import salt.utils.hashutils
  16. import salt.utils.platform
  17. # Import Salt Testing libs
  18. from tests.support.mixins import (
  19. AdaptedConfigurationTestCaseMixin,
  20. LoaderModuleMockMixin,
  21. )
  22. from tests.support.mock import patch
  23. from tests.support.runtests import RUNTIME_VARS
  24. from tests.support.unit import TestCase
  25. try:
  26. import win32file
  27. except ImportError:
  28. pass
  29. UNICODE_FILENAME = "питон.txt"
  30. UNICODE_DIRNAME = UNICODE_ENVNAME = "соль"
  31. class RootsTest(TestCase, AdaptedConfigurationTestCaseMixin, LoaderModuleMockMixin):
  32. def setup_loader_modules(self):
  33. self.opts = self.get_temp_config("master")
  34. empty_dir = os.path.join(RUNTIME_VARS.TMP_STATE_TREE, "empty_dir")
  35. if not os.path.isdir(empty_dir):
  36. os.makedirs(empty_dir)
  37. return {roots: {"__opts__": self.opts}}
  38. @classmethod
  39. def setUpClass(cls):
  40. """
  41. Create special file_roots for symlink test on Windows
  42. """
  43. if salt.utils.platform.is_windows():
  44. root_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  45. source_sym = os.path.join(root_dir, "source_sym")
  46. with salt.utils.files.fopen(source_sym, "w") as fp_:
  47. fp_.write("hello world!\n")
  48. cwd = os.getcwd()
  49. try:
  50. os.chdir(root_dir)
  51. win32file.CreateSymbolicLink("dest_sym", "source_sym", 0)
  52. finally:
  53. os.chdir(cwd)
  54. cls.test_symlink_list_file_roots = {"base": [root_dir]}
  55. else:
  56. dest_sym = os.path.join(RUNTIME_VARS.BASE_FILES, "dest_sym")
  57. if not os.path.islink(dest_sym):
  58. # Fix broken symlink by recreating it
  59. if os.path.exists(dest_sym):
  60. os.remove(dest_sym)
  61. os.symlink("source_sym", dest_sym)
  62. cls.test_symlink_list_file_roots = None
  63. cls.tmp_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  64. full_path_to_file = os.path.join(RUNTIME_VARS.BASE_FILES, "testfile")
  65. with salt.utils.files.fopen(full_path_to_file, "rb") as s_fp:
  66. with salt.utils.files.fopen(
  67. os.path.join(cls.tmp_dir, "testfile"), "wb"
  68. ) as d_fp:
  69. for line in s_fp:
  70. d_fp.write(line)
  71. @classmethod
  72. def tearDownClass(cls):
  73. """
  74. Remove special file_roots for symlink test
  75. """
  76. if salt.utils.platform.is_windows():
  77. try:
  78. salt.utils.files.rm_rf(cls.test_symlink_list_file_roots["base"][0])
  79. except OSError:
  80. pass
  81. salt.utils.files.rm_rf(cls.tmp_dir)
  82. def tearDown(self):
  83. del self.opts
  84. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  85. def test_file_list(self):
  86. ret = roots.file_list({"saltenv": "base"})
  87. self.assertIn("testfile", ret)
  88. self.assertIn(UNICODE_FILENAME, ret)
  89. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  90. def test_find_file(self):
  91. ret = roots.find_file("testfile")
  92. self.assertEqual("testfile", ret["rel"])
  93. full_path_to_file = os.path.join(RUNTIME_VARS.BASE_FILES, "testfile")
  94. self.assertEqual(full_path_to_file, ret["path"])
  95. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  96. def test_serve_file(self):
  97. with patch.dict(roots.__opts__, {"file_buffer_size": 262144}):
  98. load = {
  99. "saltenv": "base",
  100. "path": os.path.join(self.tmp_dir, "testfile"),
  101. "loc": 0,
  102. }
  103. fnd = {"path": os.path.join(self.tmp_dir, "testfile"), "rel": "testfile"}
  104. ret = roots.serve_file(load, fnd)
  105. with salt.utils.files.fopen(
  106. os.path.join(RUNTIME_VARS.BASE_FILES, "testfile"), "rb"
  107. ) as fp_:
  108. data = fp_.read()
  109. self.assertDictEqual(ret, {"data": data, "dest": "testfile"})
  110. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  111. def test_envs(self):
  112. opts = {"file_roots": copy.copy(self.opts["file_roots"])}
  113. opts["file_roots"][UNICODE_ENVNAME] = opts["file_roots"]["base"]
  114. with patch.dict(roots.__opts__, opts):
  115. ret = roots.envs()
  116. self.assertIn("base", ret)
  117. self.assertIn(UNICODE_ENVNAME, ret)
  118. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  119. def test_file_hash(self):
  120. load = {
  121. "saltenv": "base",
  122. "path": os.path.join(self.tmp_dir, "testfile"),
  123. }
  124. fnd = {"path": os.path.join(self.tmp_dir, "testfile"), "rel": "testfile"}
  125. ret = roots.file_hash(load, fnd)
  126. # Hashes are different in Windows. May be how git translates line
  127. # endings
  128. with salt.utils.files.fopen(
  129. os.path.join(RUNTIME_VARS.BASE_FILES, "testfile"), "rb"
  130. ) as fp_:
  131. hsum = salt.utils.hashutils.sha256_digest(fp_.read())
  132. self.assertDictEqual(ret, {"hsum": hsum, "hash_type": "sha256"})
  133. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  134. def test_file_list_emptydirs(self):
  135. ret = roots.file_list_emptydirs({"saltenv": "base"})
  136. self.assertIn("empty_dir", ret)
  137. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  138. def test_file_list_with_slash(self):
  139. opts = {"file_roots": copy.copy(self.opts["file_roots"])}
  140. opts["file_roots"]["foo/bar"] = opts["file_roots"]["base"]
  141. load = {
  142. "saltenv": "foo/bar",
  143. }
  144. with patch.dict(roots.__opts__, opts):
  145. ret = roots.file_list(load)
  146. self.assertIn("testfile", ret)
  147. self.assertIn(UNICODE_FILENAME, ret)
  148. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  149. def test_dir_list(self):
  150. ret = roots.dir_list({"saltenv": "base"})
  151. self.assertIn("empty_dir", ret)
  152. self.assertIn(UNICODE_DIRNAME, ret)
  153. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  154. def test_symlink_list(self):
  155. orig_file_roots = self.opts["file_roots"]
  156. try:
  157. if self.test_symlink_list_file_roots:
  158. self.opts["file_roots"] = self.test_symlink_list_file_roots
  159. ret = roots.symlink_list({"saltenv": "base"})
  160. self.assertDictEqual(ret, {"dest_sym": "source_sym"})
  161. finally:
  162. if self.test_symlink_list_file_roots:
  163. self.opts["file_roots"] = orig_file_roots
  164. @pytest.mark.slow_test(seconds=1) # Test takes >0.1 and <=1 seconds
  165. def test_dynamic_file_roots(self):
  166. dyn_root_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  167. top_sls = os.path.join(dyn_root_dir, "top.sls")
  168. with salt.utils.files.fopen(top_sls, "w") as fp_:
  169. fp_.write("{{saltenv}}:\n '*':\n - dynamo\n")
  170. dynamo_sls = os.path.join(dyn_root_dir, "dynamo.sls")
  171. with salt.utils.files.fopen(dynamo_sls, "w") as fp_:
  172. fp_.write("foo:\n test.nop\n")
  173. opts = {"file_roots": copy.copy(self.opts["file_roots"])}
  174. opts["file_roots"]["__env__"] = [dyn_root_dir]
  175. with patch.dict(roots.__opts__, opts):
  176. ret1 = roots.find_file("dynamo.sls", "dyn")
  177. ret2 = roots.file_list({"saltenv": "dyn"})
  178. self.assertEqual("dynamo.sls", ret1["rel"])
  179. self.assertIn("top.sls", ret2)
  180. self.assertIn("dynamo.sls", ret2)