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
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
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.
12import os.path
13import unittest
15import lsst.resources
16import responses
17from lsst.resources import ResourcePath
18from lsst.resources.tests import GenericTestCase
19from lsst.resources.utils import makeTestTempDir, removeTestTempDir
21TESTDIR = os.path.abspath(os.path.dirname(__file__))
24class GenericHttpTestCase(GenericTestCase, unittest.TestCase):
25 scheme = "http"
26 netloc = "server.example"
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.
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 """
47 def setUp(self):
48 # Local test directory
49 self.tmpdir = ResourcePath(makeTestTempDir(TESTDIR))
51 serverRoot = "www.not-exists.orgx"
52 existingFolderName = "existingFolder"
53 existingFileName = "existingFile"
54 notExistingFileName = "notExistingFile"
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 )
70 # Need to declare the options
71 responses.add(responses.OPTIONS, self.baseURL.geturl(), status=200, headers={"DAV": "1,2,3"})
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)
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)
88 # Used by HttpResourcePath.write()
89 responses.add(responses.PUT, self.existingFileResourcePath.geturl(), status=201)
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 )
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)
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 )
137 def tearDown(self):
138 if self.tmpdir:
139 if self.tmpdir.isLocal:
140 removeTestTempDir(self.tmpdir.ospath)
142 @responses.activate
143 def test_exists(self):
145 self.assertTrue(self.existingFileResourcePath.exists())
146 self.assertFalse(self.notExistingFileResourcePath.exists())
148 self.assertEqual(self.existingFileResourcePath.size(), 1024)
149 with self.assertRaises(FileNotFoundError):
150 self.notExistingFileResourcePath.size()
152 @responses.activate
153 def test_remove(self):
155 self.assertIsNone(self.existingFileResourcePath.remove())
156 with self.assertRaises(FileNotFoundError):
157 self.notExistingFileResourcePath.remove()
159 @responses.activate
160 def test_mkdir(self):
162 # The mock means that we can't check this now exists
163 self.notExistingFolderResourcePath.mkdir()
165 # This should do nothing
166 self.existingFolderResourcePath.mkdir()
168 with self.assertRaises(ValueError):
169 self.notExistingFileResourcePath.mkdir()
171 @responses.activate
172 def test_read(self):
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()
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!")
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))
195 @responses.activate
196 def test_write(self):
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)
202 @responses.activate
203 def test_transfer(self):
205 # Transferring to self should be no-op.
206 self.existingFileResourcePath.transfer_from(src=self.existingFileResourcePath)
208 self.assertIsNone(self.notExistingFileResourcePath.transfer_from(src=self.existingFileResourcePath))
209 # Should test for existence.
210 # self.assertTrue(self.notExistingFileResourcePath.exists())
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())
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 )
229 def test_parent(self):
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 )
240if __name__ == "__main__": 240 ↛ 241line 240 didn't jump to line 241, because the condition on line 240 was never true
241 unittest.main()