WIP
This commit is contained in:
217
tests/web/test_async_queue.py
Normal file
217
tests/web/test_async_queue.py
Normal file
@@ -0,0 +1,217 @@
|
||||
"""
|
||||
Tests for the AsyncTaskQueue class.
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from threading import Event
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from src.web.workers.async_queue import AsyncTask, AsyncTaskQueue
|
||||
|
||||
|
||||
class TestAsyncTask:
|
||||
"""Tests for AsyncTask dataclass."""
|
||||
|
||||
def test_create_task(self):
|
||||
"""Test creating an AsyncTask."""
|
||||
task = AsyncTask(
|
||||
request_id="test-id",
|
||||
api_key="test-key",
|
||||
file_path=Path("/tmp/test.pdf"),
|
||||
filename="test.pdf",
|
||||
)
|
||||
|
||||
assert task.request_id == "test-id"
|
||||
assert task.api_key == "test-key"
|
||||
assert task.filename == "test.pdf"
|
||||
assert task.priority == 0
|
||||
assert task.created_at is not None
|
||||
|
||||
|
||||
class TestAsyncTaskQueue:
|
||||
"""Tests for AsyncTaskQueue."""
|
||||
|
||||
def test_init(self):
|
||||
"""Test queue initialization."""
|
||||
queue = AsyncTaskQueue(max_size=50, worker_count=2)
|
||||
|
||||
assert queue._worker_count == 2
|
||||
assert queue._queue.maxsize == 50
|
||||
assert not queue._started
|
||||
|
||||
def test_submit_task(self, task_queue, sample_task):
|
||||
"""Test submitting a task to the queue."""
|
||||
success = task_queue.submit(sample_task)
|
||||
|
||||
assert success is True
|
||||
assert task_queue.get_queue_depth() == 1
|
||||
|
||||
def test_submit_when_full(self, sample_task):
|
||||
"""Test submitting to a full queue."""
|
||||
queue = AsyncTaskQueue(max_size=1, worker_count=1)
|
||||
|
||||
# Submit first task
|
||||
queue.submit(sample_task)
|
||||
|
||||
# Create second task
|
||||
task2 = AsyncTask(
|
||||
request_id="test-2",
|
||||
api_key="test-key",
|
||||
file_path=sample_task.file_path,
|
||||
filename="test2.pdf",
|
||||
)
|
||||
|
||||
# Queue should be full
|
||||
success = queue.submit(task2)
|
||||
assert success is False
|
||||
|
||||
def test_get_queue_depth(self, task_queue, sample_task):
|
||||
"""Test getting queue depth."""
|
||||
assert task_queue.get_queue_depth() == 0
|
||||
|
||||
task_queue.submit(sample_task)
|
||||
assert task_queue.get_queue_depth() == 1
|
||||
|
||||
def test_start_and_stop(self, task_queue):
|
||||
"""Test starting and stopping the queue."""
|
||||
handler = MagicMock()
|
||||
|
||||
task_queue.start(handler)
|
||||
assert task_queue._started is True
|
||||
assert task_queue.is_running is True
|
||||
assert len(task_queue._workers) == 1
|
||||
|
||||
task_queue.stop(timeout=5.0)
|
||||
assert task_queue._started is False
|
||||
assert task_queue.is_running is False
|
||||
assert len(task_queue._workers) == 0
|
||||
|
||||
def test_worker_processes_task(self, sample_task):
|
||||
"""Test that worker thread processes tasks."""
|
||||
queue = AsyncTaskQueue(max_size=10, worker_count=1)
|
||||
processed = Event()
|
||||
|
||||
def handler(task):
|
||||
processed.set()
|
||||
|
||||
queue.start(handler)
|
||||
queue.submit(sample_task)
|
||||
|
||||
# Wait for processing
|
||||
assert processed.wait(timeout=5.0)
|
||||
|
||||
queue.stop()
|
||||
|
||||
def test_worker_handles_errors(self, sample_task):
|
||||
"""Test that worker handles errors gracefully."""
|
||||
queue = AsyncTaskQueue(max_size=10, worker_count=1)
|
||||
error_handled = Event()
|
||||
|
||||
def failing_handler(task):
|
||||
error_handled.set()
|
||||
raise ValueError("Test error")
|
||||
|
||||
queue.start(failing_handler)
|
||||
queue.submit(sample_task)
|
||||
|
||||
# Should not crash
|
||||
assert error_handled.wait(timeout=5.0)
|
||||
time.sleep(0.5) # Give time for error handling
|
||||
|
||||
assert queue.is_running
|
||||
|
||||
queue.stop()
|
||||
|
||||
def test_processing_tracking(self, task_queue, sample_task):
|
||||
"""Test tracking of processing tasks."""
|
||||
processed = Event()
|
||||
|
||||
def slow_handler(task):
|
||||
processed.set()
|
||||
time.sleep(0.5)
|
||||
|
||||
task_queue.start(slow_handler)
|
||||
task_queue.submit(sample_task)
|
||||
|
||||
# Wait for processing to start
|
||||
assert processed.wait(timeout=5.0)
|
||||
|
||||
# Task should be in processing set
|
||||
assert task_queue.get_processing_count() == 1
|
||||
assert task_queue.is_processing(sample_task.request_id)
|
||||
|
||||
# Wait for completion
|
||||
time.sleep(1.0)
|
||||
|
||||
assert task_queue.get_processing_count() == 0
|
||||
assert not task_queue.is_processing(sample_task.request_id)
|
||||
|
||||
task_queue.stop()
|
||||
|
||||
def test_multiple_workers(self, sample_task):
|
||||
"""Test queue with multiple workers."""
|
||||
queue = AsyncTaskQueue(max_size=10, worker_count=3)
|
||||
processed_count = []
|
||||
|
||||
def handler(task):
|
||||
processed_count.append(task.request_id)
|
||||
time.sleep(0.1)
|
||||
|
||||
queue.start(handler)
|
||||
|
||||
# Submit multiple tasks
|
||||
for i in range(5):
|
||||
task = AsyncTask(
|
||||
request_id=f"task-{i}",
|
||||
api_key="test-key",
|
||||
file_path=sample_task.file_path,
|
||||
filename=f"test-{i}.pdf",
|
||||
)
|
||||
queue.submit(task)
|
||||
|
||||
# Wait for all tasks
|
||||
time.sleep(2.0)
|
||||
|
||||
assert len(processed_count) == 5
|
||||
|
||||
queue.stop()
|
||||
|
||||
def test_graceful_shutdown(self, sample_task):
|
||||
"""Test graceful shutdown waits for current task."""
|
||||
queue = AsyncTaskQueue(max_size=10, worker_count=1)
|
||||
started = Event()
|
||||
finished = Event()
|
||||
|
||||
def slow_handler(task):
|
||||
started.set()
|
||||
time.sleep(0.5)
|
||||
finished.set()
|
||||
|
||||
queue.start(slow_handler)
|
||||
queue.submit(sample_task)
|
||||
|
||||
# Wait for processing to start
|
||||
assert started.wait(timeout=5.0)
|
||||
|
||||
# Stop should wait for task to finish
|
||||
queue.stop(timeout=5.0)
|
||||
|
||||
assert finished.is_set()
|
||||
|
||||
def test_double_start(self, task_queue):
|
||||
"""Test that starting twice doesn't create duplicate workers."""
|
||||
handler = MagicMock()
|
||||
|
||||
task_queue.start(handler)
|
||||
assert len(task_queue._workers) == 1
|
||||
|
||||
# Starting again should not add more workers
|
||||
task_queue.start(handler)
|
||||
assert len(task_queue._workers) == 1
|
||||
|
||||
task_queue.stop()
|
||||
Reference in New Issue
Block a user