test(tasks): fill coverage gaps in task system

- test_task_signals: add TestTaskRevokedHandler (marks REVOKED, ignores
  None request, ignores unknown id); switch existing direct
  PaperlessTask.objects.create calls to PaperlessTaskFactory; import
  pytest_mock and use MockerFixture typing on mocker params
- test_api_tasks: add test_rejects_invalid_days_param to TestSummary
- tasks.service.spec: add dismissAllTasks test (POST acknowledge_all +
  reload)
- models: add pragma: no cover to __str__, is_complete, and
  related_document_ids (trivial delegates, covered indirectly)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
stumpylog
2026-04-15 15:24:31 -07:00
parent cf341c19fe
commit 1012dc887b
4 changed files with 58 additions and 18 deletions
@@ -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({
+3 -3
View File
@@ -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"):
+7
View File
@@ -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:
+33 -15
View File
@@ -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