test_files.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. # -*- coding: utf-8 -*-
  2. """
  3. Unit Tests for functions located in salt/utils/files.py
  4. """
  5. # Import python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import copy
  8. import os
  9. # Import Salt libs
  10. import salt.utils.files
  11. from salt.ext import six
  12. # Import Salt Testing libs
  13. from tests.support.helpers import with_tempdir
  14. from tests.support.mock import patch
  15. from tests.support.unit import TestCase, skipIf
  16. class FilesTestCase(TestCase):
  17. """
  18. Test case for files util.
  19. """
  20. def test_safe_rm(self):
  21. with patch("os.remove") as os_remove_mock:
  22. salt.utils.files.safe_rm("dummy_tgt")
  23. self.assertTrue(os_remove_mock.called)
  24. @skipIf(
  25. os.path.exists("/tmp/no_way_this_is_a_file_nope.sh"),
  26. "Test file exists! Skipping safe_rm_exceptions test!",
  27. )
  28. def test_safe_rm_exceptions(self):
  29. error = False
  30. try:
  31. salt.utils.files.safe_rm("/tmp/no_way_this_is_a_file_nope.sh")
  32. except (IOError, OSError):
  33. error = True
  34. self.assertFalse(
  35. error, "salt.utils.files.safe_rm raised exception when it should not have"
  36. )
  37. @with_tempdir()
  38. def test_safe_walk_symlink_recursion(self, tmp):
  39. if os.stat(tmp).st_ino == 0:
  40. self.skipTest("inodes not supported in {0}".format(tmp))
  41. os.mkdir(os.path.join(tmp, "fax"))
  42. os.makedirs(os.path.join(tmp, "foo", "bar"))
  43. os.symlink(os.path.join("..", ".."), os.path.join(tmp, "foo", "bar", "baz"))
  44. os.symlink("foo", os.path.join(tmp, "root"))
  45. expected = [
  46. (os.path.join(tmp, "root"), ["bar"], []),
  47. (os.path.join(tmp, "root", "bar"), ["baz"], []),
  48. (os.path.join(tmp, "root", "bar", "baz"), ["fax", "foo", "root"], []),
  49. (os.path.join(tmp, "root", "bar", "baz", "fax"), [], []),
  50. ]
  51. paths = []
  52. for root, dirs, names in salt.utils.files.safe_walk(os.path.join(tmp, "root")):
  53. paths.append((root, sorted(dirs), names))
  54. if paths != expected:
  55. raise AssertionError(
  56. "\n".join(
  57. ["got:"]
  58. + [repr(p) for p in paths]
  59. + ["", "expected:"]
  60. + [repr(p) for p in expected]
  61. )
  62. )
  63. @skipIf(not six.PY3, "This test only applies to Python 3")
  64. def test_fopen_with_disallowed_fds(self):
  65. """
  66. This is safe to have as a unit test since we aren't going to actually
  67. try to read or write. We want to ensure that we are raising a
  68. TypeError. Python 3's open() builtin will treat the booleans as file
  69. descriptor numbers and try to open stdin/stdout. We also want to test
  70. fd 2 which is stderr.
  71. """
  72. for invalid_fn in (False, True, 0, 1, 2):
  73. try:
  74. with salt.utils.files.fopen(invalid_fn):
  75. pass
  76. except TypeError:
  77. # This is expected. We aren't using an assertRaises here
  78. # because we want to ensure that if we did somehow open the
  79. # filehandle, that it doesn't remain open.
  80. pass
  81. else:
  82. # We probably won't even get this far if we actually opened
  83. # stdin/stdout as a file descriptor. It is likely to cause the
  84. # integration suite to die since, news flash, closing
  85. # stdin/stdout/stderr is usually not a wise thing to do in the
  86. # middle of a program's execution.
  87. self.fail(
  88. "fopen() should have been prevented from opening a file "
  89. "using {0} as the filename".format(invalid_fn)
  90. )
  91. def _create_temp_structure(self, temp_directory, structure):
  92. for folder, files in six.iteritems(structure):
  93. current_directory = os.path.join(temp_directory, folder)
  94. os.makedirs(current_directory)
  95. for name, content in six.iteritems(files):
  96. path = os.path.join(temp_directory, folder, name)
  97. with salt.utils.files.fopen(path, "w+") as fh:
  98. fh.write(content)
  99. def _validate_folder_structure_and_contents(
  100. self, target_directory, desired_structure
  101. ):
  102. for folder, files in six.iteritems(desired_structure):
  103. for name, content in six.iteritems(files):
  104. path = os.path.join(target_directory, folder, name)
  105. with salt.utils.files.fopen(path) as fh:
  106. assert fh.read().strip() == content
  107. @with_tempdir()
  108. @with_tempdir()
  109. def test_recursive_copy(self, src, dest):
  110. src_structure = {
  111. "foo": {"foofile.txt": "fooSTRUCTURE"},
  112. "bar": {"barfile.txt": "barSTRUCTURE"},
  113. }
  114. dest_structure = {
  115. "foo": {"foo.txt": "fooTARGET_STRUCTURE"},
  116. "baz": {"baz.txt": "bazTARGET_STRUCTURE"},
  117. }
  118. # Create the file structures in both src and dest dirs
  119. self._create_temp_structure(src, src_structure)
  120. self._create_temp_structure(dest, dest_structure)
  121. # Perform the recursive copy
  122. salt.utils.files.recursive_copy(src, dest)
  123. # Confirm results match expected results
  124. desired_structure = copy.copy(dest_structure)
  125. desired_structure.update(src_structure)
  126. self._validate_folder_structure_and_contents(dest, desired_structure)