Skip to content

Commit 1a1f258

Browse files
author
Jens Kürten
committed
abort on error
1 parent cd36ebd commit 1a1f258

File tree

2 files changed

+89
-11
lines changed

2 files changed

+89
-11
lines changed

csfunctions/service/file_upload.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from csfunctions.service.base import BaseService
1010
from csfunctions.service.file_upload_schemas import (
11+
AbortFileUploadRequest,
1112
CompleteFileUploadRequest,
1213
CreateNewFileRequest,
1314
CreateNewFileResponse,
@@ -102,6 +103,19 @@ def _complete_upload(
102103
).model_dump(),
103104
)
104105

106+
def _abort_upload(
107+
self, file_object_id: str, lock_id: str, persno: str, presigned_write_urls: PresignedWriteUrls
108+
) -> None:
109+
self.request(
110+
endpoint=f"/file_upload/{file_object_id}/abort",
111+
method="POST",
112+
json=AbortFileUploadRequest(
113+
lock_id=lock_id,
114+
persno=persno,
115+
presigned_write_urls=presigned_write_urls,
116+
).model_dump(),
117+
)
118+
105119
def upload_file_content(
106120
self,
107121
file_object_id: str,
@@ -122,17 +136,27 @@ def upload_file_content(
122136
persno=persno,
123137
check_access=check_access,
124138
)
125-
presigned_with_etags, sha256 = self._upload_from_stream(presigned_urls=presigned, stream=stream)
126-
self._complete_upload(
127-
file_object_id=file_object_id,
128-
filesize=filesize,
129-
lock_id=lock_id,
130-
presigned_urls=presigned_with_etags,
131-
persno=persno,
132-
check_access=check_access,
133-
sha256=sha256,
134-
delete_derived_files=delete_derived_files,
135-
)
139+
try:
140+
presigned_with_etags, sha256 = self._upload_from_stream(presigned_urls=presigned, stream=stream)
141+
self._complete_upload(
142+
file_object_id=file_object_id,
143+
filesize=filesize,
144+
lock_id=lock_id,
145+
presigned_urls=presigned_with_etags,
146+
persno=persno,
147+
check_access=check_access,
148+
sha256=sha256,
149+
delete_derived_files=delete_derived_files,
150+
)
151+
except Exception as e:
152+
# if something goes wrong during upload we try to abort
153+
self._abort_upload(
154+
file_object_id=file_object_id,
155+
lock_id=lock_id,
156+
persno=persno,
157+
presigned_write_urls=presigned,
158+
)
159+
raise e
136160

137161
def upload_new_file(
138162
self,

tests/test_service.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,57 @@ def test_upload_file_content(self):
295295
self.assertEqual(kwargs["persno"], "tester")
296296
self.assertEqual(kwargs["sha256"], "deadbeef")
297297
self.assertEqual(kwargs["delete_derived_files"], False)
298+
299+
def test_abort_upload(self):
300+
presigned = PresignedWriteUrls(
301+
blob_id="blob123",
302+
urls=["https://upload.url/1"],
303+
chunksize=4,
304+
headers={"Authorization": "Bearer token"},
305+
)
306+
with patch.object(self.service, "request", return_value=None) as mock_request:
307+
self.service._abort_upload(
308+
file_object_id="file123",
309+
lock_id="lockid",
310+
persno="tester",
311+
presigned_write_urls=presigned,
312+
)
313+
mock_request.assert_called_once()
314+
args, kwargs = mock_request.call_args
315+
self.assertIn("endpoint", kwargs)
316+
self.assertTrue("abort" in kwargs["endpoint"])
317+
self.assertEqual(kwargs["method"], "POST")
318+
self.assertEqual(kwargs["json"]["lock_id"], "lockid")
319+
self.assertEqual(kwargs["json"]["persno"], "tester")
320+
self.assertEqual(kwargs["json"]["presigned_write_urls"], presigned.model_dump())
321+
322+
def test_upload_file_content_aborts_on_error(self):
323+
# Patch internal methods to simulate error and check abort
324+
with (
325+
patch.object(self.service, "_get_stream_size", return_value=4),
326+
patch.object(self.service, "_get_presigned_write_urls") as mock_presigned,
327+
patch.object(self.service, "_upload_from_stream", side_effect=Exception("upload error")),
328+
patch.object(self.service, "_abort_upload") as mock_abort,
329+
):
330+
mock_presigned.return_value = PresignedWriteUrls(
331+
blob_id="blob123",
332+
urls=["https://upload.url/1", "https://upload.url/2"],
333+
chunksize=2,
334+
headers={"Authorization": "Bearer token"},
335+
)
336+
stream = io.BytesIO(b"abcd")
337+
with self.assertRaises(Exception) as cm:
338+
self.service.upload_file_content(
339+
file_object_id="file123",
340+
stream=stream,
341+
persno="tester",
342+
check_access=True,
343+
filesize=None,
344+
delete_derived_files=False,
345+
)
346+
self.assertEqual(str(cm.exception), "upload error")
347+
mock_abort.assert_called_once()
348+
args, kwargs = mock_abort.call_args
349+
self.assertEqual(kwargs["file_object_id"], "file123")
350+
self.assertEqual(kwargs["persno"], "tester")
351+
self.assertEqual(kwargs["presigned_write_urls"], mock_presigned.return_value)

0 commit comments

Comments
 (0)