Coverage for tests/test_http.py: 31%

Shortcuts on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

98 statements  

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.path 

13import unittest 

14 

15import lsst.resources 

16import responses 

17from lsst.resources import ResourcePath 

18from lsst.resources.tests import GenericTestCase 

19from lsst.resources.utils import makeTestTempDir, removeTestTempDir 

20 

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

22 

23 

24class GenericHttpTestCase(GenericTestCase, unittest.TestCase): 

25 scheme = "http" 

26 netloc = "server.example" 

27 

28 

29# Mock required environment variables during tests 

30@unittest.mock.patch.dict( 

31 os.environ, 

32 { 

33 "LSST_BUTLER_WEBDAV_AUTH": "TOKEN", 

34 "LSST_BUTLER_WEBDAV_TOKEN_FILE": os.path.join(TESTDIR, "data/webdav/token"), 

35 "LSST_BUTLER_WEBDAV_CA_BUNDLE": "/path/to/ca/certs", 

36 }, 

37) 

38class HttpReadWriteTestCase(unittest.TestCase): 

39 """Specialist test cases for WebDAV server. 

40 

41 The responses class requires that every possible request be explicitly 

42 mocked out. This currently makes it extremely inconvenient to subclass 

43 the generic read/write tests shared by other URI schemes. For now use 

44 explicit standalone tests. 

45 """ 

46 

47 def setUp(self): 

48 # Local test directory 

49 self.tmpdir = ResourcePath(makeTestTempDir(TESTDIR)) 

50 

51 serverRoot = "www.not-exists.orgx" 

52 existingFolderName = "existingFolder" 

53 existingFileName = "existingFile" 

54 notExistingFileName = "notExistingFile" 

55 

56 self.baseURL = ResourcePath(f"https://{serverRoot}", forceDirectory=True) 

57 self.existingFileResourcePath = ResourcePath( 

58 f"https://{serverRoot}/{existingFolderName}/{existingFileName}" 

59 ) 

60 self.notExistingFileResourcePath = ResourcePath( 

61 f"https://{serverRoot}/{existingFolderName}/{notExistingFileName}" 

62 ) 

63 self.existingFolderResourcePath = ResourcePath( 

64 f"https://{serverRoot}/{existingFolderName}", forceDirectory=True 

65 ) 

66 self.notExistingFolderResourcePath = ResourcePath( 

67 f"https://{serverRoot}/{notExistingFileName}", forceDirectory=True 

68 ) 

69 

70 # Need to declare the options 

71 responses.add(responses.OPTIONS, self.baseURL.geturl(), status=200, headers={"DAV": "1,2,3"}) 

72 

73 # Used by HttpResourcePath.exists() 

74 responses.add( 

75 responses.HEAD, 

76 self.existingFileResourcePath.geturl(), 

77 status=200, 

78 headers={"Content-Length": "1024"}, 

79 ) 

80 responses.add(responses.HEAD, self.notExistingFileResourcePath.geturl(), status=404) 

81 

82 # Used by HttpResourcePath.read() 

83 responses.add( 

84 responses.GET, self.existingFileResourcePath.geturl(), status=200, body=str.encode("It works!") 

85 ) 

86 responses.add(responses.GET, self.notExistingFileResourcePath.geturl(), status=404) 

87 

88 # Used by HttpResourcePath.write() 

89 responses.add(responses.PUT, self.existingFileResourcePath.geturl(), status=201) 

90 

91 # Used by HttpResourcePath.transfer_from() 

92 responses.add( 

93 responses.Response( 

94 url=self.existingFileResourcePath.geturl(), 

95 method="COPY", 

96 headers={"Destination": self.existingFileResourcePath.geturl()}, 

97 status=201, 

98 ) 

99 ) 

100 responses.add( 

101 responses.Response( 

102 url=self.existingFileResourcePath.geturl(), 

103 method="COPY", 

104 headers={"Destination": self.notExistingFileResourcePath.geturl()}, 

105 status=201, 

106 ) 

107 ) 

108 responses.add( 

109 responses.Response( 

110 url=self.existingFileResourcePath.geturl(), 

111 method="MOVE", 

112 headers={"Destination": self.notExistingFileResourcePath.geturl()}, 

113 status=201, 

114 ) 

115 ) 

116 

117 # Used by HttpResourcePath.remove() 

118 responses.add(responses.DELETE, self.existingFileResourcePath.geturl(), status=200) 

119 responses.add(responses.DELETE, self.notExistingFileResourcePath.geturl(), status=404) 

120 

121 # Used by HttpResourcePath.mkdir() 

122 responses.add( 

123 responses.HEAD, 

124 self.existingFolderResourcePath.geturl(), 

125 status=200, 

126 headers={"Content-Length": "1024"}, 

127 ) 

128 responses.add(responses.HEAD, self.baseURL.geturl(), status=200, headers={"Content-Length": "1024"}) 

129 responses.add(responses.HEAD, self.notExistingFolderResourcePath.geturl(), status=404) 

130 responses.add( 

131 responses.Response(url=self.notExistingFolderResourcePath.geturl(), method="MKCOL", status=201) 

132 ) 

133 responses.add( 

134 responses.Response(url=self.existingFolderResourcePath.geturl(), method="MKCOL", status=403) 

135 ) 

136 

137 def tearDown(self): 

138 if self.tmpdir: 

139 if self.tmpdir.isLocal: 

140 removeTestTempDir(self.tmpdir.ospath) 

141 

142 @responses.activate 

143 def test_exists(self): 

144 

145 self.assertTrue(self.existingFileResourcePath.exists()) 

146 self.assertFalse(self.notExistingFileResourcePath.exists()) 

147 

148 self.assertEqual(self.existingFileResourcePath.size(), 1024) 

149 with self.assertRaises(FileNotFoundError): 

150 self.notExistingFileResourcePath.size() 

151 

152 @responses.activate 

153 def test_remove(self): 

154 

155 self.assertIsNone(self.existingFileResourcePath.remove()) 

156 with self.assertRaises(FileNotFoundError): 

157 self.notExistingFileResourcePath.remove() 

158 

159 @responses.activate 

160 def test_mkdir(self): 

161 

162 # The mock means that we can't check this now exists 

163 self.notExistingFolderResourcePath.mkdir() 

164 

165 # This should do nothing 

166 self.existingFolderResourcePath.mkdir() 

167 

168 with self.assertRaises(ValueError): 

169 self.notExistingFileResourcePath.mkdir() 

170 

171 @responses.activate 

172 def test_read(self): 

173 

174 self.assertEqual(self.existingFileResourcePath.read().decode(), "It works!") 

175 self.assertNotEqual(self.existingFileResourcePath.read().decode(), "Nope.") 

176 with self.assertRaises(FileNotFoundError): 

177 self.notExistingFileResourcePath.read() 

178 

179 # Run this twice to ensure use of cache in code coverag. 

180 for _ in (1, 2): 

181 with self.existingFileResourcePath.as_local() as local_uri: 

182 self.assertTrue(local_uri.isLocal) 

183 content = local_uri.read().decode() 

184 self.assertEqual(content, "It works!") 

185 

186 # Check that the environment variable is being read. 

187 lsst.resources.http._TMPDIR = None 

188 with unittest.mock.patch.dict(os.environ, {"LSST_RESOURCES_TMPDIR": self.tmpdir.ospath}): 

189 with self.existingFileResourcePath.as_local() as local_uri: 

190 self.assertTrue(local_uri.isLocal) 

191 content = local_uri.read().decode() 

192 self.assertEqual(content, "It works!") 

193 self.assertIsNotNone(local_uri.relative_to(self.tmpdir)) 

194 

195 @responses.activate 

196 def test_write(self): 

197 

198 self.assertIsNone(self.existingFileResourcePath.write(data=str.encode("Some content."))) 

199 with self.assertRaises(FileExistsError): 

200 self.existingFileResourcePath.write(data=str.encode("Some content."), overwrite=False) 

201 

202 @responses.activate 

203 def test_transfer(self): 

204 

205 # Transferring to self should be no-op. 

206 self.existingFileResourcePath.transfer_from(src=self.existingFileResourcePath) 

207 

208 self.assertIsNone(self.notExistingFileResourcePath.transfer_from(src=self.existingFileResourcePath)) 

209 # Should test for existence. 

210 # self.assertTrue(self.notExistingFileResourcePath.exists()) 

211 

212 # Should delete and try again with move. 

213 # self.notExistingFileResourcePath.remove() 

214 self.assertIsNone( 

215 self.notExistingFileResourcePath.transfer_from(src=self.existingFileResourcePath, transfer="move") 

216 ) 

217 # Should then check that it was moved. 

218 # self.assertFalse(self.existingFileResourcePath.exists()) 

219 

220 # Existing file resource should have been removed so this should 

221 # trigger FileNotFoundError. 

222 # with self.assertRaises(FileNotFoundError): 

223 # self.notExistingFileResourcePath.transfer_from(src=self.existingFileResourcePath) 

224 with self.assertRaises(ValueError): 

225 self.notExistingFileResourcePath.transfer_from( 

226 src=self.existingFileResourcePath, transfer="unsupported" 

227 ) 

228 

229 def test_parent(self): 

230 

231 self.assertEqual( 

232 self.existingFolderResourcePath.geturl(), self.notExistingFileResourcePath.parent().geturl() 

233 ) 

234 self.assertEqual(self.baseURL.geturl(), self.baseURL.parent().geturl()) 

235 self.assertEqual( 

236 self.existingFileResourcePath.parent().geturl(), self.existingFileResourcePath.dirname().geturl() 

237 ) 

238 

239 

240if __name__ == "__main__": 240 ↛ 241line 240 didn't jump to line 241, because the condition on line 240 was never true

241 unittest.main()