feat: annuleren taak toegevoegd

This commit is contained in:
kodi
2026-03-15 13:06:48 +01:00
parent 7d910479f9
commit a52493459a
32 changed files with 835 additions and 61 deletions
@@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio
import sys
import tempfile
import threading
import time
import unittest
from pathlib import Path
@@ -22,6 +23,18 @@ from backend.app.services.task_service import TaskService
from backend.app.tasks_runner import TaskRunner
class BlockingDeleteFilesystemAdapter(FilesystemAdapter):
def __init__(self) -> None:
super().__init__()
self.entered = threading.Event()
self.release = threading.Event()
def delete_file(self, path: Path) -> None:
self.entered.set()
self.release.wait(timeout=2.0)
super().delete_file(path)
class FileOpsApiGoldenTest(unittest.TestCase):
def setUp(self) -> None:
self.temp_dir = tempfile.TemporaryDirectory()
@@ -84,11 +97,21 @@ class FileOpsApiGoldenTest(unittest.TestCase):
while time.time() < deadline:
response = self._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._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_mkdir_success(self) -> None:
response = self._post(
"/api/files/mkdir",
@@ -272,6 +295,54 @@ class FileOpsApiGoldenTest(unittest.TestCase):
self.assertEqual(detail["status"], "completed")
self.assertFalse(target.exists())
def test_delete_file_cancelled_after_current_delete_finishes(self) -> None:
blocking_fs = BlockingDeleteFilesystemAdapter()
path_guard = PathGuard({"storage1": str(self.root)})
service = FileOpsService(path_guard=path_guard, filesystem=blocking_fs)
delete_service = DeleteTaskService(
path_guard=path_guard,
repository=self.repo,
runner=TaskRunner(repository=self.repo, filesystem=blocking_fs),
)
task_service = TaskService(repository=self.repo)
async def _override_file_ops_service() -> FileOpsService:
return service
async def _override_delete_task_service() -> DeleteTaskService:
return delete_service
async def _override_task_service() -> TaskService:
return task_service
app.dependency_overrides[get_file_ops_service] = _override_file_ops_service
app.dependency_overrides[get_delete_task_service] = _override_delete_task_service
app.dependency_overrides[get_task_service] = _override_task_service
target = self.scope / "delete_later.txt"
target.write_text("z", encoding="utf-8")
response = self._post(
"/api/files/delete",
{"path": "storage1/scope/delete_later.txt"},
)
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.scope / "delete_later.txt"))
cancel_response = self._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"], 1)
self.assertFalse(target.exists())
def test_delete_empty_directory_success(self) -> None:
target = self.scope / "empty_dir"
target.mkdir()