feat: annuleren taak toegevoegd
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
@@ -29,6 +30,18 @@ class FailingFilesystemAdapter(FilesystemAdapter):
|
||||
raise OSError("forced copy failure")
|
||||
|
||||
|
||||
class BlockingCopyFilesystemAdapter(FilesystemAdapter):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.entered = threading.Event()
|
||||
self.release = threading.Event()
|
||||
|
||||
def copy_file(self, source: str, destination: str, on_progress: callable | None = None) -> None:
|
||||
self.entered.set()
|
||||
self.release.wait(timeout=2.0)
|
||||
return super().copy_file(source=source, destination=destination, on_progress=on_progress)
|
||||
|
||||
|
||||
class CopyApiGoldenTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
@@ -72,11 +85,21 @@ class CopyApiGoldenTest(unittest.TestCase):
|
||||
while time.time() < deadline:
|
||||
response = self._request("GET", f"/api/tasks/{task_id}")
|
||||
body = response.json()
|
||||
if body["status"] in {"completed", "failed"}:
|
||||
if body["status"] in {"completed", "failed", "cancelled"}:
|
||||
return body
|
||||
time.sleep(0.02)
|
||||
self.fail("task did not reach terminal state in time")
|
||||
|
||||
def _wait_for_status(self, task_id: str, statuses: set[str], timeout_s: float = 2.0) -> dict:
|
||||
deadline = time.time() + timeout_s
|
||||
while time.time() < deadline:
|
||||
response = self._request("GET", f"/api/tasks/{task_id}")
|
||||
body = response.json()
|
||||
if body["status"] in statuses:
|
||||
return body
|
||||
time.sleep(0.02)
|
||||
self.fail(f"task did not reach one of {sorted(statuses)} in time")
|
||||
|
||||
def test_copy_success_create_task_shape(self) -> None:
|
||||
src = self.root / "source.txt"
|
||||
src.write_text("hello", encoding="utf-8")
|
||||
@@ -189,6 +212,40 @@ class CopyApiGoldenTest(unittest.TestCase):
|
||||
self.assertEqual((self.root / "dest" / "file.txt").read_text(encoding="utf-8"), "F")
|
||||
self.assertEqual((self.root / "dest" / "docs" / "nested" / "note.txt").read_text(encoding="utf-8"), "N")
|
||||
|
||||
def test_copy_batch_cancelled_after_current_file_finishes(self) -> None:
|
||||
blocking_fs = BlockingCopyFilesystemAdapter()
|
||||
path_guard = PathGuard({"storage1": str(self.root), "storage2": str(self.root)})
|
||||
self._set_services(path_guard=path_guard, filesystem=blocking_fs)
|
||||
(self.root / "a.txt").write_text("A", encoding="utf-8")
|
||||
(self.root / "b.txt").write_text("B", encoding="utf-8")
|
||||
(self.root / "dest").mkdir()
|
||||
|
||||
response = self._request(
|
||||
"POST",
|
||||
"/api/files/copy",
|
||||
{
|
||||
"sources": ["storage1/a.txt", "storage1/b.txt"],
|
||||
"destination_base": "storage1/dest",
|
||||
},
|
||||
)
|
||||
|
||||
task_id = response.json()["task_id"]
|
||||
self.assertTrue(blocking_fs.entered.wait(timeout=2.0))
|
||||
running = self._wait_for_status(task_id, {"running"})
|
||||
self.assertEqual(running["current_item"], str(self.root / "a.txt"))
|
||||
|
||||
cancel_response = self._request("POST", f"/api/tasks/{task_id}/cancel")
|
||||
self.assertEqual(cancel_response.status_code, 200)
|
||||
self.assertEqual(cancel_response.json()["status"], "cancelling")
|
||||
|
||||
blocking_fs.release.set()
|
||||
detail = self._wait_task(task_id)
|
||||
self.assertEqual(detail["status"], "cancelled")
|
||||
self.assertEqual(detail["done_items"], 1)
|
||||
self.assertEqual(detail["total_items"], 2)
|
||||
self.assertTrue((self.root / "dest" / "a.txt").exists())
|
||||
self.assertFalse((self.root / "dest" / "b.txt").exists())
|
||||
|
||||
def test_copy_source_not_found(self) -> None:
|
||||
response = self._request(
|
||||
"POST",
|
||||
|
||||
Reference in New Issue
Block a user