1
0

test_roots.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. """
  2. :codeauthor: Mike Place <mp@saltstack.com>
  3. """
  4. import copy
  5. import os
  6. import pathlib
  7. import shutil
  8. import tempfile
  9. import salt.fileclient
  10. import salt.fileserver.roots as roots
  11. import salt.utils.files
  12. import salt.utils.hashutils
  13. import salt.utils.platform
  14. from tests.support.mixins import (
  15. AdaptedConfigurationTestCaseMixin,
  16. LoaderModuleMockMixin,
  17. )
  18. from tests.support.mock import patch
  19. from tests.support.runtests import RUNTIME_VARS
  20. from tests.support.unit import TestCase, skipIf
  21. UNICODE_FILENAME = "питон.txt"
  22. UNICODE_DIRNAME = UNICODE_ENVNAME = "соль"
  23. class RootsTest(TestCase, AdaptedConfigurationTestCaseMixin, LoaderModuleMockMixin):
  24. def setup_loader_modules(self):
  25. config_overrides = {"file_roots": {"base": [str(self.tmp_state_tree)]}}
  26. self.opts = self.get_temp_config("master", **config_overrides)
  27. return {roots: {"__opts__": self.opts}}
  28. @classmethod
  29. def setUpClass(cls):
  30. cls.tmp_dir = pathlib.Path(tempfile.mkdtemp(dir=RUNTIME_VARS.TMP))
  31. cls.tmp_state_tree = pathlib.Path(tempfile.mkdtemp(dir=RUNTIME_VARS.TMP))
  32. full_path_to_file = os.path.join(RUNTIME_VARS.BASE_FILES, "testfile")
  33. shutil.copyfile(full_path_to_file, str(cls.tmp_dir / "testfile"))
  34. shutil.copyfile(full_path_to_file, str(cls.tmp_state_tree / "testfile"))
  35. shutil.copyfile(
  36. os.path.join(RUNTIME_VARS.BASE_FILES, UNICODE_FILENAME),
  37. str(cls.tmp_state_tree / UNICODE_FILENAME),
  38. )
  39. shutil.copytree(
  40. os.path.join(RUNTIME_VARS.BASE_FILES, UNICODE_DIRNAME),
  41. str(cls.tmp_state_tree / UNICODE_DIRNAME),
  42. )
  43. @classmethod
  44. def tearDownClass(cls):
  45. salt.utils.files.rm_rf(str(cls.tmp_dir))
  46. salt.utils.files.rm_rf(str(cls.tmp_state_tree))
  47. def tearDown(self):
  48. del self.opts
  49. def test_file_list(self):
  50. ret = roots.file_list({"saltenv": "base"})
  51. self.assertIn("testfile", ret)
  52. self.assertIn(UNICODE_FILENAME, ret)
  53. def test_find_file(self):
  54. ret = roots.find_file("testfile")
  55. self.assertEqual("testfile", ret["rel"])
  56. full_path_to_file = str(self.tmp_state_tree / "testfile")
  57. self.assertEqual(full_path_to_file, ret["path"])
  58. def test_serve_file(self):
  59. with patch.dict(roots.__opts__, {"file_buffer_size": 262144}):
  60. load = {
  61. "saltenv": "base",
  62. "path": str(self.tmp_dir / "testfile"),
  63. "loc": 0,
  64. }
  65. fnd = {"path": str(self.tmp_dir / "testfile"), "rel": "testfile"}
  66. ret = roots.serve_file(load, fnd)
  67. with salt.utils.files.fopen(
  68. os.path.join(RUNTIME_VARS.BASE_FILES, "testfile"), "rb"
  69. ) as fp_:
  70. data = fp_.read()
  71. self.assertDictEqual(ret, {"data": data, "dest": "testfile"})
  72. def test_envs(self):
  73. opts = {"file_roots": copy.copy(self.opts["file_roots"])}
  74. opts["file_roots"][UNICODE_ENVNAME] = opts["file_roots"]["base"]
  75. with patch.dict(roots.__opts__, opts):
  76. ret = roots.envs()
  77. self.assertIn("base", ret)
  78. self.assertIn(UNICODE_ENVNAME, ret)
  79. def test_file_hash(self):
  80. load = {
  81. "saltenv": "base",
  82. "path": str(self.tmp_dir / "testfile"),
  83. }
  84. fnd = {"path": str(self.tmp_dir / "testfile"), "rel": "testfile"}
  85. ret = roots.file_hash(load, fnd)
  86. # Hashes are different in Windows. May be how git translates line
  87. # endings
  88. with salt.utils.files.fopen(
  89. os.path.join(RUNTIME_VARS.BASE_FILES, "testfile"), "rb"
  90. ) as fp_:
  91. hsum = salt.utils.hashutils.sha256_digest(fp_.read())
  92. self.assertDictEqual(ret, {"hsum": hsum, "hash_type": "sha256"})
  93. def test_file_list_emptydirs(self):
  94. empty_dir = self.tmp_state_tree / "empty_dir"
  95. if not empty_dir.is_dir():
  96. empty_dir.mkdir()
  97. self.addCleanup(salt.utils.files.rm_rf, str(empty_dir))
  98. ret = roots.file_list_emptydirs({"saltenv": "base"})
  99. self.assertIn("empty_dir", ret)
  100. def test_file_list_with_slash(self):
  101. opts = {"file_roots": copy.copy(self.opts["file_roots"])}
  102. opts["file_roots"]["foo/bar"] = opts["file_roots"]["base"]
  103. load = {
  104. "saltenv": "foo/bar",
  105. }
  106. with patch.dict(roots.__opts__, opts):
  107. ret = roots.file_list(load)
  108. self.assertIn("testfile", ret)
  109. self.assertIn(UNICODE_FILENAME, ret)
  110. def test_dir_list(self):
  111. empty_dir = self.tmp_state_tree / "empty_dir"
  112. if not empty_dir.is_dir():
  113. empty_dir.mkdir()
  114. self.addCleanup(salt.utils.files.rm_rf, str(empty_dir))
  115. ret = roots.dir_list({"saltenv": "base"})
  116. self.assertIn("empty_dir", ret)
  117. self.assertIn(UNICODE_DIRNAME, ret)
  118. def test_symlink_list(self):
  119. source_sym = self.tmp_state_tree / "source_sym"
  120. source_sym.write_text("")
  121. dest_sym = self.tmp_state_tree / "dest_sym"
  122. dest_sym.symlink_to(str(source_sym))
  123. self.addCleanup(dest_sym.unlink)
  124. self.addCleanup(source_sym.unlink)
  125. ret = roots.symlink_list({"saltenv": "base"})
  126. self.assertDictEqual(ret, {"dest_sym": str(source_sym)})
  127. def test_dynamic_file_roots(self):
  128. dyn_root_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  129. top_sls = os.path.join(dyn_root_dir, "top.sls")
  130. with salt.utils.files.fopen(top_sls, "w") as fp_:
  131. fp_.write("{{saltenv}}:\n '*':\n - dynamo\n")
  132. dynamo_sls = os.path.join(dyn_root_dir, "dynamo.sls")
  133. with salt.utils.files.fopen(dynamo_sls, "w") as fp_:
  134. fp_.write("foo:\n test.nop\n")
  135. opts = {"file_roots": copy.copy(self.opts["file_roots"])}
  136. opts["file_roots"]["__env__"] = [dyn_root_dir]
  137. with patch.dict(roots.__opts__, opts):
  138. ret1 = roots.find_file("dynamo.sls", "dyn")
  139. ret2 = roots.file_list({"saltenv": "dyn"})
  140. self.assertEqual("dynamo.sls", ret1["rel"])
  141. self.assertIn("top.sls", ret2)
  142. self.assertIn("dynamo.sls", ret2)
  143. @skipIf(
  144. salt.utils.platform.is_windows(),
  145. "Windows does not support this master function",
  146. )
  147. def test_update_no_change(self):
  148. # process all changes that have happen
  149. # changes will always take place the first time during testing
  150. ret = roots.update()
  151. self.assertTrue(ret["changed"])
  152. # check if no changes took place
  153. ret = roots.update()
  154. self.assertFalse(ret["changed"])
  155. self.assertEqual(ret["files"]["changed"], [])
  156. self.assertEqual(ret["files"]["removed"], [])
  157. self.assertEqual(ret["files"]["added"], [])