@@ -63,7 +63,7 @@ async def test_get_url_path_with_home(mock_provider):
6363async def test_do_filestatus_success (mock_provider , fake_request ):
6464 mock_response = AsyncMock ()
6565 mock_response .status_code = 200
66- mock_response .raise_for_status = AsyncMock ()
66+ mock_response .raise_for_status = MagicMock ()
6767
6868 mock_response .json = MagicMock (
6969 return_value = {
@@ -86,6 +86,23 @@ async def test_do_filestatus_success(mock_provider, fake_request):
8686 assert file_status ["type" ] == "FILE"
8787
8888
89+ @pytest .mark .asyncio
90+ async def test_do_filestatus_missing_filestatus (mock_provider , fake_request ):
91+ mock_response = AsyncMock ()
92+ mock_response .status_code = 200
93+ mock_response .raise_for_status = MagicMock ()
94+ mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
95+
96+ mock_provider .client .get .return_value = mock_response
97+
98+ status , data = await mock_provider ._do_filestatus (
99+ fake_request , DAVPath ("/test.txt" )
100+ )
101+
102+ assert status == 200
103+ assert data == {}
104+
105+
89106@pytest .mark .asyncio
90107async def test_do_get_file (mock_provider , fake_request ):
91108 fake_status = {
@@ -102,7 +119,13 @@ async def test_do_get_file(mock_provider, fake_request):
102119 ),
103120 )
104121 )
105- mock_provider ._dav_response_data_generator = AsyncMock (return_value = AsyncMock ())
122+
123+ async def fake_generator ():
124+ yield b"data"
125+
126+ mock_provider ._dav_response_data_generator = MagicMock (
127+ return_value = fake_generator ()
128+ )
106129
107130 fake_request .ranges = [DAVRequestRange (DAVRangeType .RANGE , 0 , 100 , 200 )]
108131 status , basic_data , generator , _ = await mock_provider ._do_get (fake_request )
@@ -112,11 +135,44 @@ async def test_do_get_file(mock_provider, fake_request):
112135 assert generator is not None
113136
114137
138+ @pytest .mark .asyncio
139+ async def test_do_get_file_non_range (mock_provider , fake_request ):
140+ fake_status = {
141+ "type" : "FILE" ,
142+ "length" : 100 ,
143+ "modificationTime" : 1234567890 ,
144+ }
145+
146+ mock_provider ._get_dav_property_d0 = AsyncMock (
147+ return_value = (
148+ 200 ,
149+ await mock_provider ._create_dav_property_obj (
150+ fake_request , DAVPath ("/testfile.txt" ), fake_status
151+ ),
152+ )
153+ )
154+
155+ async def fake_generator ():
156+ yield b"data"
157+
158+ mock_provider ._dav_response_data_generator = MagicMock (
159+ return_value = fake_generator ()
160+ )
161+
162+ fake_request .ranges = None
163+ status , basic_data , generator , _ = await mock_provider ._do_get (fake_request )
164+
165+ assert status == 200
166+ assert basic_data .content_length == 100
167+ assert generator is not None
168+
169+
115170@pytest .mark .asyncio
116171async def test_do_delete_success (mock_provider , fake_request ):
117172 mock_provider ._precheck_source = AsyncMock (return_value = (True , True , False ))
118173 mock_provider .client .delete .return_value = AsyncMock (
119- status_code = 204 , raise_for_status = AsyncMock ()
174+ status_code = 204 ,
175+ raise_for_status = MagicMock (),
120176 )
121177
122178 result = await mock_provider ._do_delete (fake_request )
@@ -130,6 +186,23 @@ async def test_do_delete_not_found(mock_provider, fake_request):
130186 assert result == 404
131187
132188
189+ @pytest .mark .asyncio
190+ async def test_do_delete_http_error (mock_provider , fake_request ):
191+ mock_provider ._precheck_source = AsyncMock (return_value = (True , True , False ))
192+
193+ mock_response = AsyncMock ()
194+ mock_response .raise_for_status = MagicMock (
195+ side_effect = httpx .HTTPStatusError (
196+ "error" , request = MagicMock (), response = MagicMock (status_code = 500 )
197+ )
198+ )
199+
200+ mock_provider .client .delete .return_value = mock_response
201+
202+ response = await mock_provider ._do_delete (fake_request )
203+ assert response == 424
204+
205+
133206def test_get_url ():
134207 root = WebHDFSProvider (
135208 config = Config (),
@@ -175,17 +248,20 @@ def test_get_url():
175248async def test_do_filestatus_failure (mock_provider , fake_request ):
176249 mock_response = AsyncMock ()
177250 mock_response .status_code = 404
178- mock_response .raise_for_status .side_effect = httpx .HTTPStatusError (
179- message = "Error" , request = MagicMock (), response = MagicMock (status_code = 404 )
251+ mock_response .raise_for_status = MagicMock (
252+ side_effect = httpx .HTTPStatusError (
253+ message = "Error" ,
254+ request = MagicMock (),
255+ response = MagicMock (status_code = 404 ),
256+ )
180257 )
181258 mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
182259
183260 mock_provider .client .get .return_value = mock_response
184261
185262 url_path = DAVPath ("/notfound.txt" )
186-
187- response = await mock_provider ._do_filestatus (fake_request , url_path )
188- assert response == (404 , {})
263+ with pytest .raises (httpx .HTTPStatusError ):
264+ await mock_provider ._do_filestatus (fake_request , url_path )
189265
190266
191267@pytest .mark .asyncio
@@ -214,6 +290,30 @@ async def test_do_get_collection(mock_provider, fake_request):
214290 assert response_content_range is None
215291
216292
293+ @pytest .mark .asyncio
294+ async def test_do_get_invalid_range (mock_provider , fake_request ):
295+ fake_status = {
296+ "type" : "FILE" ,
297+ "length" : 100 ,
298+ "modificationTime" : 0 ,
299+ }
300+
301+ mock_provider ._get_dav_property_d0 = AsyncMock (
302+ return_value = (
303+ 200 ,
304+ await mock_provider ._create_dav_property_obj (
305+ fake_request , DAVPath ("/file.txt" ), fake_status
306+ ),
307+ )
308+ )
309+
310+ fake_request .ranges = [DAVRequestRange (DAVRangeType .RANGE , 200 , 300 , 100 )]
311+
312+ status , _ , _ , _ = await mock_provider ._do_get (fake_request )
313+
314+ assert status in (200 , 416 )
315+
316+
217317@pytest .mark .asyncio
218318async def test_dav_response_data_generator (mock_provider , fake_request ):
219319 async def fake_aiter_bytes ():
@@ -244,26 +344,60 @@ async def fake_aiter_bytes():
244344 assert result == [(b"chunk1" , True ), (b"chunk2" , False )]
245345
246346
347+ @pytest .mark .asyncio
348+ async def test_dav_response_generator_empty (mock_provider , fake_request ):
349+ async def fake_aiter ():
350+ if False :
351+ yield b""
352+
353+ fake_response = MagicMock ()
354+ fake_response .aiter_bytes = fake_aiter
355+ fake_response .raise_for_status = MagicMock ()
356+
357+ class AsyncContextManager :
358+ async def __aenter__ (self ):
359+ return fake_response
360+
361+ async def __aexit__ (self , exc_type , exc_val , exc_tb ):
362+ return None
363+
364+ mock_provider .client .stream = MagicMock (return_value = AsyncContextManager ())
365+
366+ gen = mock_provider ._dav_response_data_generator (
367+ fake_request , DAVPath ("/file.txt" ), None , None
368+ )
369+
370+ result = [chunk async for chunk , more in gen ]
371+ assert result == [None ]
372+
373+
247374@pytest .mark .asyncio
248375async def test_do_put (mock_provider , fake_request ):
249- mock_response = MagicMock ()
250- mock_response .status_code = 200
251- mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
252- mock_response .raise_for_status = AsyncMock ()
376+ mock_provider ._precheck_source = AsyncMock (return_value = (True , False , False ))
253377
254- mock_provider .client .get .return_value = mock_response
378+ first_put = AsyncMock ()
379+ first_put .status_code = 307
380+ first_put .headers = {
381+ "location" : "http://fake-hdfs:9870/webhdfs/v1/file_put_location"
382+ }
383+ first_put .raise_for_status = MagicMock ()
255384
256- response = await mock_provider ._do_put (fake_request )
385+ second_put = AsyncMock ()
386+ second_put .status_code = 201
387+ second_put .raise_for_status = MagicMock ()
257388
258- assert response == 204
389+ mock_provider .client .put = AsyncMock (side_effect = [first_put , second_put ])
390+
391+ response = await mock_provider ._do_put (fake_request )
392+ assert response == 201
259393
260394
261395@pytest .mark .asyncio
262396async def test_do_copy (mock_provider , fake_request ):
263397 mock_response = MagicMock ()
264398 mock_response .status_code = 200
265399 mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
266- mock_response .raise_for_status = AsyncMock ()
400+ mock_response .raise_for_status = MagicMock ()
267401
268402 mock_provider .client .get .return_value = mock_response
269403
@@ -276,7 +410,7 @@ async def test_do_mkcol(mock_provider, fake_request):
276410 mock_response = MagicMock ()
277411 mock_response .status_code = 200
278412 mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
279- mock_response .raise_for_status = AsyncMock ()
413+ mock_response .raise_for_status = MagicMock ()
280414
281415 mock_provider .client .get .return_value = mock_response
282416
@@ -290,7 +424,7 @@ async def test_do_propfind(mock_provider, fake_request):
290424 mock_response = MagicMock ()
291425 mock_response .status_code = 200
292426 mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
293- mock_response .raise_for_status = AsyncMock ()
427+ mock_response .raise_for_status = MagicMock ()
294428
295429 mock_provider .client .get .return_value = mock_response
296430
@@ -340,12 +474,29 @@ async def test_do_propfind(mock_provider, fake_request):
340474 assert resp_val .extra_not_found == exp_val .extra_not_found
341475
342476
477+ @pytest .mark .asyncio
478+ async def test_do_propfind_with_extra_keys (mock_provider , fake_request ):
479+ fake_request .propfind_only_fetch_basic = False
480+ fake_request .propfind_extra_keys = ["custom:key" ]
481+
482+ mock_response = AsyncMock ()
483+ mock_response .status_code = 200
484+ mock_response .raise_for_status = MagicMock ()
485+ mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
486+
487+ mock_provider .client .get .return_value = mock_response
488+
489+ result = await mock_provider ._do_propfind (fake_request )
490+
491+ assert isinstance (result , dict )
492+
493+
343494@pytest .mark .asyncio
344495async def test_do_head (mock_provider , fake_request ):
345496 mock_response = MagicMock ()
346497 mock_response .status_code = 200
347498 mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
348- mock_response .raise_for_status = AsyncMock ()
499+ mock_response .raise_for_status = MagicMock ()
349500
350501 mock_provider .client .get .return_value = mock_response
351502
@@ -359,7 +510,7 @@ async def test_do_precheck_destination(mock_provider, fake_request):
359510 mock_response = MagicMock ()
360511 mock_response .status_code = 200
361512 mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
362- mock_response .raise_for_status = AsyncMock ()
513+ mock_response .raise_for_status = MagicMock ()
363514
364515 mock_provider .client .get .return_value = mock_response
365516
@@ -370,13 +521,32 @@ async def test_do_precheck_destination(mock_provider, fake_request):
370521
371522@pytest .mark .asyncio
372523async def test_do_move (mock_provider , fake_request ):
373- mock_response = MagicMock ()
374- mock_response .status_code = 200
375- mock_response .json = MagicMock (return_value = {"FileStatus" : {}})
376- mock_response .raise_for_status = AsyncMock ()
524+ fake_request .overwrite = True
377525
378- mock_provider .client .get .return_value = mock_response
526+ mock_provider ._precheck_destination = AsyncMock (return_value = (True , False , True ))
527+
528+ mock_delete_response = MagicMock ()
529+ mock_delete_response .status_code = 204
530+ mock_delete_response .raise_for_status = MagicMock ()
531+
532+ mock_provider .client .delete = AsyncMock (return_value = mock_delete_response )
533+
534+ mock_put_response = MagicMock ()
535+ mock_put_response .status_code = 201
536+ mock_put_response .raise_for_status = MagicMock ()
537+
538+ mock_provider .client .put = AsyncMock (return_value = mock_put_response )
539+
540+ result = await mock_provider ._do_move (fake_request )
541+ assert result == 204
542+
543+
544+ @pytest .mark .asyncio
545+ async def test_do_move_destination_exists_no_overwrite (mock_provider , fake_request ):
546+ fake_request .overwrite = False
547+
548+ mock_provider ._precheck_destination = AsyncMock (return_value = (True , True , True ))
379549
380- response = await mock_provider ._do_move (fake_request )
550+ result = await mock_provider ._do_move (fake_request )
381551
382- assert response == 204
552+ assert result == 403
0 commit comments