diff --git a/src-ui/src/app/services/tasks.service.spec.ts b/src-ui/src/app/services/tasks.service.spec.ts index 09bd29441..d4c4e8950 100644 --- a/src-ui/src/app/services/tasks.service.spec.ts +++ b/src-ui/src/app/services/tasks.service.spec.ts @@ -129,6 +129,21 @@ describe('TasksService', () => { expect(tasksService.startedFileTasks).toHaveLength(1) }) + it('calls acknowledge_all api endpoint on dismissAll and reloads', () => { + tasksService.dismissAllTasks().subscribe() + const req = httpTestingController.expectOne( + `${environment.apiBaseUrl}tasks/acknowledge_all/` + ) + expect(req.request.method).toEqual('POST') + req.flush({}) + // reload is then called + httpTestingController + .expectOne( + `${environment.apiBaseUrl}tasks/?task_type=consume_file&acknowledged=false` + ) + .flush([]) + }) + it('supports running tasks', () => { tasksService.run(PaperlessTaskType.SanityCheck).subscribe((res) => { expect(res).toEqual({ diff --git a/src/documents/models.py b/src/documents/models.py index 63bac5cff..c77eef0d1 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -811,15 +811,15 @@ class PaperlessTask(ModelWithOwner): models.Index(fields=["owner", "acknowledged", "date_created"]), ] - def __str__(self) -> str: + def __str__(self) -> str: # pragma: no cover return f"{self.get_task_type_display()} [{self.task_id[:8]}]" @property - def is_complete(self) -> bool: + def is_complete(self) -> bool: # pragma: no cover return self.status in self.COMPLETE_STATUSES @property - def related_document_ids(self) -> list[int]: + def related_document_ids(self) -> list[int]: # pragma: no cover if not self.result_data: return [] if doc_id := self.result_data.get("document_id"): diff --git a/src/documents/tests/test_api_tasks.py b/src/documents/tests/test_api_tasks.py index cef09a5c2..369882493 100644 --- a/src/documents/tests/test_api_tasks.py +++ b/src/documents/tests/test_api_tasks.py @@ -481,6 +481,13 @@ class TestSummary: assert by_type["consume_file"]["failure_count"] == 1 assert by_type["train_classifier"]["total_count"] == 1 + def test_rejects_invalid_days_param(self, admin_client: APIClient) -> None: + """?days=invalid returns 400 with an error message.""" + response = admin_client.get(ENDPOINT + "summary/", {"days": "invalid"}) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert "days" in response.data + @pytest.mark.django_db() class TestActive: diff --git a/src/documents/tests/test_task_signals.py b/src/documents/tests/test_task_signals.py index dbaa16363..2724067f9 100644 --- a/src/documents/tests/test_task_signals.py +++ b/src/documents/tests/test_task_signals.py @@ -2,11 +2,14 @@ import uuid from unittest import mock import pytest +import pytest_mock from documents.data_models import ConsumableDocument from documents.data_models import DocumentMetadataOverrides from documents.data_models import DocumentSource from documents.models import PaperlessTask +from documents.signals.handlers import task_revoked_handler +from documents.tests.factories import PaperlessTaskFactory @pytest.fixture @@ -144,12 +147,7 @@ class TestBeforeTaskPublishHandler: @pytest.mark.django_db class TestTaskPrerunHandler: def test_marks_task_started(self): - task = PaperlessTask.objects.create( - task_id=str(uuid.uuid4()), - task_type=PaperlessTask.TaskType.CONSUME_FILE, - trigger_source=PaperlessTask.TriggerSource.MANUAL, - status=PaperlessTask.Status.PENDING, - ) + task = PaperlessTaskFactory(status=PaperlessTask.Status.PENDING) from documents.signals.handlers import task_prerun_handler task_prerun_handler(task_id=task.task_id) @@ -173,10 +171,8 @@ class TestTaskPostrunHandler: def _started_task(self) -> PaperlessTask: from django.utils import timezone - return PaperlessTask.objects.create( - task_id=str(uuid.uuid4()), + return PaperlessTaskFactory( task_type=PaperlessTask.TaskType.TRAIN_CLASSIFIER, - trigger_source=PaperlessTask.TriggerSource.MANUAL, status=PaperlessTask.Status.STARTED, date_started=timezone.now(), ) @@ -255,10 +251,8 @@ class TestTaskFailureHandler: def test_records_failure_with_exception(self): from django.utils import timezone - task = PaperlessTask.objects.create( - task_id=str(uuid.uuid4()), + task = PaperlessTaskFactory( task_type=PaperlessTask.TaskType.CONSUME_FILE, - trigger_source=PaperlessTask.TriggerSource.WEB_UI, status=PaperlessTask.Status.STARTED, date_started=timezone.now(), ) @@ -280,10 +274,8 @@ class TestTaskFailureHandler: from django.utils import timezone - task = PaperlessTask.objects.create( - task_id=str(uuid.uuid4()), + task = PaperlessTaskFactory( task_type=PaperlessTask.TaskType.CONSUME_FILE, - trigger_source=PaperlessTask.TriggerSource.WEB_UI, status=PaperlessTask.Status.STARTED, date_started=timezone.now(), ) @@ -307,3 +299,29 @@ class TestTaskFailureHandler: from documents.signals.handlers import task_failure_handler task_failure_handler(task_id=None, exception=ValueError("x"), traceback=None) + + +@pytest.mark.django_db +class TestTaskRevokedHandler: + def test_marks_task_revoked(self, mocker: pytest_mock.MockerFixture): + """task_revoked_handler moves a queued task to REVOKED and stamps date_done.""" + task = PaperlessTaskFactory(status=PaperlessTask.Status.PENDING) + request = mocker.MagicMock() + request.id = task.task_id + + task_revoked_handler(request=request) + task.refresh_from_db() + assert task.status == PaperlessTask.Status.REVOKED + assert task.date_done is not None + + def test_ignores_none_request(self): + """task_revoked_handler must not raise when request is None.""" + + task_revoked_handler(request=None) # must not raise + + def test_ignores_unknown_task_id(self, mocker: pytest_mock.MockerFixture): + """task_revoked_handler must not raise for a task_id not in the database.""" + request = mocker.MagicMock() + request.id = "nonexistent-id" + + task_revoked_handler(request=request) # must not raise