Coverage for tests/test_file.py: 22%

94 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-25 09:29 +0000

1# This file is part of lsst-resources. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12import os 

13import pathlib 

14import unittest 

15import unittest.mock 

16import urllib.parse 

17 

18from lsst.resources import ResourcePath, ResourcePathExpression 

19from lsst.resources.tests import GenericReadWriteTestCase, GenericTestCase 

20 

21TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

22 

23 

24class SimpleTestCase(unittest.TestCase): 

25 """Basic tests for file URIs.""" 

26 

27 def test_instance(self): 

28 for example in ( 

29 "xxx", 

30 ResourcePath("xxx"), 

31 pathlib.Path("xxx"), 

32 urllib.parse.urlparse("file:///xxx"), 

33 ): 

34 self.assertIsInstance(example, ResourcePathExpression) 

35 

36 for example in ({1, 2, 3}, 42, self): 

37 self.assertNotIsInstance(example, ResourcePathExpression) 

38 

39 

40class FileTestCase(GenericTestCase, unittest.TestCase): 

41 """File-specific generic test cases.""" 

42 

43 scheme = "file" 

44 netloc = "localhost" 

45 

46 def test_env_var(self): 

47 """Test that environment variables are expanded.""" 

48 with unittest.mock.patch.dict(os.environ, {"MY_TEST_DIR": "/a/b/c"}): 

49 uri = ResourcePath("${MY_TEST_DIR}/d.txt") 

50 self.assertEqual(uri.path, "/a/b/c/d.txt") 

51 self.assertEqual(uri.scheme, "file") 

52 

53 # This will not expand 

54 uri = ResourcePath("${MY_TEST_DIR}/d.txt", forceAbsolute=False) 

55 self.assertEqual(uri.path, "${MY_TEST_DIR}/d.txt") 

56 self.assertFalse(uri.scheme) 

57 

58 def test_ospath(self): 

59 """File URIs have ospath property.""" 

60 file = ResourcePath(self._make_uri("a/test.txt")) 

61 self.assertEqual(file.ospath, "/a/test.txt") 

62 self.assertEqual(file.ospath, file.path) 

63 

64 # A Schemeless URI can take unquoted files but will be quoted 

65 # when it becomes a file URI. 

66 something = "/a#/???.txt" 

67 file = ResourcePath(something, forceAbsolute=True) 

68 self.assertEqual(file.scheme, "file") 

69 self.assertEqual(file.ospath, something, "From URI: {file}") 

70 self.assertNotIn("???", file.path) 

71 

72 def test_path_lib(self): 

73 """File URIs can be created from pathlib""" 

74 file = ResourcePath(self._make_uri("a/test.txt")) 

75 

76 path_file = pathlib.Path(file.ospath) 

77 from_path = ResourcePath(path_file) 

78 self.assertEqual(from_path.ospath, file.ospath) 

79 

80 def test_schemeless_root(self): 

81 root = ResourcePath(self._make_uri("/root")) 

82 via_root = ResourcePath("b.txt", root=root) 

83 self.assertEqual(via_root.ospath, "/root/b.txt") 

84 

85 

86class FileReadWriteTestCase(GenericReadWriteTestCase, unittest.TestCase): 

87 """File tests involving reading and writing of data.""" 

88 

89 scheme = "file" 

90 netloc = "localhost" 

91 testdir = TESTDIR 

92 transfer_modes = ("move", "copy", "link", "hardlink", "symlink", "relsymlink") 

93 

94 def test_transfer_identical(self): 

95 """Test overwrite of identical files. 

96 

97 Only relevant for local files. 

98 """ 

99 dir1 = self.tmpdir.join("dir1", forceDirectory=True) 

100 dir1.mkdir() 

101 self.assertTrue(dir1.exists()) 

102 dir2 = self.tmpdir.join("dir2", forceDirectory=True) 

103 # A symlink can't include a trailing slash. 

104 dir2_ospath = dir2.ospath 

105 if dir2_ospath.endswith("/"): 

106 dir2_ospath = dir2_ospath[:-1] 

107 os.symlink(dir1.ospath, dir2_ospath) 

108 

109 # Write a test file. 

110 src_file = dir1.join("test.txt") 

111 content = "0123456" 

112 src_file.write(content.encode()) 

113 

114 # Construct URI to destination that should be identical. 

115 dest_file = dir2.join("test.txt") 

116 self.assertTrue(dest_file.exists()) 

117 self.assertNotEqual(src_file, dest_file) 

118 

119 # Transfer it over itself. 

120 dest_file.transfer_from(src_file, transfer="symlink", overwrite=True) 

121 new_content = dest_file.read().decode() 

122 self.assertEqual(content, new_content) 

123 

124 def test_local_temporary(self): 

125 """Create temporary local file if no prefix specified.""" 

126 with ResourcePath.temporary_uri(suffix=".json") as tmp: 

127 self.assertEqual(tmp.getExtension(), ".json", f"uri: {tmp}") 

128 self.assertTrue(tmp.isabs(), f"uri: {tmp}") 

129 self.assertFalse(tmp.exists(), f"uri: {tmp}") 

130 tmp.write(b"abcd") 

131 self.assertTrue(tmp.exists(), f"uri: {tmp}") 

132 self.assertTrue(tmp.isTemporary) 

133 self.assertTrue(tmp.isLocal) 

134 

135 # If we now ask for a local form of this temporary file 

136 # it should still be temporary and it should not be deleted 

137 # on exit. 

138 with tmp.as_local() as loc: 

139 self.assertEqual(tmp, loc) 

140 self.assertTrue(loc.isTemporary) 

141 self.assertTrue(tmp.exists()) 

142 self.assertFalse(tmp.exists(), f"uri: {tmp}") 

143 

144 def test_transfers_from_local(self): 

145 """Extra tests for local transfers.""" 

146 target = self.tmpdir.join("a/target.txt") 

147 with ResourcePath.temporary_uri() as tmp: 

148 tmp.write(b"") 

149 self.assertTrue(tmp.isTemporary) 

150 

151 # Symlink transfers for temporary resources should 

152 # trigger a debug message. 

153 for transfer in ("symlink", "relsymlink"): 

154 with self.assertLogs("lsst.resources", level="DEBUG") as cm: 

155 target.transfer_from(tmp, transfer) 

156 target.remove() 

157 self.assertIn("Using a symlink for a temporary", "".join(cm.output)) 

158 

159 # Force the target directory to be created. 

160 target.transfer_from(tmp, "move") 

161 self.assertFalse(tmp.exists()) 

162 

163 # Temporary file now gone so transfer should not work. 

164 with self.assertRaises(FileNotFoundError): 

165 target.transfer_from(tmp, "move", overwrite=True) 

166 

167 

168if __name__ == "__main__": 

169 unittest.main()