Create API layer for web interface
This commit is contained in:
@@ -0,0 +1,350 @@
|
||||
"""
|
||||
Tests for queue management API endpoints.
|
||||
"""
|
||||
|
||||
import json
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from api_routes import QueueManagerAPI
|
||||
from models import QueueItem, QueueState, QueueStatus
|
||||
from queue_service import QueueService, QueueServiceError
|
||||
|
||||
|
||||
class TestQueueManagementEndpoints:
|
||||
"""Test cases for queue management API endpoints."""
|
||||
|
||||
@pytest.fixture
|
||||
def mock_queue_service(self):
|
||||
"""Create a mock queue service for testing."""
|
||||
service = Mock(spec=QueueService)
|
||||
service.get_queue_state.return_value = QueueState.RUNNING
|
||||
return service
|
||||
|
||||
@pytest.fixture
|
||||
def api(self, mock_queue_service):
|
||||
"""Create a QueueManagerAPI instance for testing."""
|
||||
return QueueManagerAPI(queue_service=mock_queue_service)
|
||||
|
||||
@pytest.fixture
|
||||
def client(self, api):
|
||||
"""Create a test client for the Flask app."""
|
||||
api.app.config['TESTING'] = True
|
||||
return api.app.test_client()
|
||||
|
||||
@pytest.fixture
|
||||
def sample_queue_item(self):
|
||||
"""Create a sample queue item for testing."""
|
||||
return QueueItem(
|
||||
id="test-item-1",
|
||||
workflow_name="Test Workflow",
|
||||
workflow_data={"nodes": {"1": {"class_type": "TestNode"}}},
|
||||
status=QueueStatus.PENDING
|
||||
)
|
||||
|
||||
def test_get_queue_items_all(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test getting all queue items."""
|
||||
mock_queue_service.get_queue_items.return_value = [sample_queue_item]
|
||||
|
||||
response = client.get('/api/queue/items')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['count'] == 1
|
||||
assert len(data['items']) == 1
|
||||
assert data['items'][0]['id'] == 'test-item-1'
|
||||
assert 'timestamp' in data
|
||||
|
||||
mock_queue_service.get_queue_items.assert_called_once_with(None)
|
||||
|
||||
def test_get_queue_items_with_status_filter(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test getting queue items with status filter."""
|
||||
mock_queue_service.get_queue_items.return_value = [sample_queue_item]
|
||||
|
||||
response = client.get('/api/queue/items?status=pending')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['count'] == 1
|
||||
|
||||
mock_queue_service.get_queue_items.assert_called_once_with(QueueStatus.PENDING)
|
||||
|
||||
def test_get_queue_items_invalid_status(self, client, mock_queue_service):
|
||||
"""Test getting queue items with invalid status filter."""
|
||||
response = client.get('/api/queue/items?status=invalid_status')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
|
||||
def test_add_queue_item_success(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test adding a new queue item successfully."""
|
||||
mock_queue_service.add_workflow.return_value = "test-item-1"
|
||||
mock_queue_service.get_queue_item.return_value = sample_queue_item
|
||||
|
||||
request_data = {
|
||||
'workflow_name': 'Test Workflow',
|
||||
'workflow_data': {'nodes': {'1': {'class_type': 'TestNode'}}}
|
||||
}
|
||||
|
||||
response = client.post('/api/queue/items',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 201
|
||||
data = json.loads(response.data)
|
||||
assert data['item']['id'] == 'test-item-1'
|
||||
assert data['message'] == 'Workflow added to queue successfully'
|
||||
assert 'timestamp' in data
|
||||
|
||||
mock_queue_service.add_workflow.assert_called_once_with(
|
||||
request_data['workflow_data'],
|
||||
request_data['workflow_name']
|
||||
)
|
||||
|
||||
def test_add_queue_item_missing_workflow_data(self, client, mock_queue_service):
|
||||
"""Test adding a queue item without workflow data."""
|
||||
request_data = {'workflow_name': 'Test Workflow'}
|
||||
|
||||
response = client.post('/api/queue/items',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
assert 'workflow_data' in data['message']
|
||||
|
||||
def test_add_queue_item_invalid_json(self, client, mock_queue_service):
|
||||
"""Test adding a queue item with invalid JSON."""
|
||||
response = client.post('/api/queue/items',
|
||||
data='invalid json',
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_get_queue_item_success(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test getting a specific queue item successfully."""
|
||||
mock_queue_service.get_queue_item.return_value = sample_queue_item
|
||||
|
||||
response = client.get('/api/queue/items/test-item-1')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['item']['id'] == 'test-item-1'
|
||||
assert 'timestamp' in data
|
||||
|
||||
mock_queue_service.get_queue_item.assert_called_once_with('test-item-1')
|
||||
|
||||
def test_get_queue_item_not_found(self, client, mock_queue_service):
|
||||
"""Test getting a non-existent queue item."""
|
||||
mock_queue_service.get_queue_item.return_value = None
|
||||
|
||||
response = client.get('/api/queue/items/nonexistent')
|
||||
|
||||
assert response.status_code == 404
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Not found'
|
||||
|
||||
def test_update_queue_item_status(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test updating a queue item's status."""
|
||||
mock_queue_service.update_item_status.return_value = True
|
||||
updated_item = QueueItem(
|
||||
id="test-item-1",
|
||||
workflow_name="Test Workflow",
|
||||
workflow_data={"nodes": {"1": {"class_type": "TestNode"}}},
|
||||
status=QueueStatus.RUNNING
|
||||
)
|
||||
mock_queue_service.get_queue_item.return_value = updated_item
|
||||
|
||||
request_data = {
|
||||
'status': 'running'
|
||||
}
|
||||
|
||||
response = client.put('/api/queue/items/test-item-1',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['item']['status'] == 'running'
|
||||
assert data['message'] == 'Queue item updated successfully'
|
||||
|
||||
mock_queue_service.update_item_status.assert_called_once_with(
|
||||
'test-item-1', QueueStatus.RUNNING, None, None
|
||||
)
|
||||
|
||||
def test_update_queue_item_with_error(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test updating a queue item with error message."""
|
||||
mock_queue_service.update_item_status.return_value = True
|
||||
failed_item = QueueItem(
|
||||
id="test-item-1",
|
||||
workflow_name="Test Workflow",
|
||||
workflow_data={"nodes": {"1": {"class_type": "TestNode"}}},
|
||||
status=QueueStatus.FAILED,
|
||||
error_message="Test error"
|
||||
)
|
||||
mock_queue_service.get_queue_item.return_value = failed_item
|
||||
|
||||
request_data = {
|
||||
'status': 'failed',
|
||||
'error_message': 'Test error'
|
||||
}
|
||||
|
||||
response = client.put('/api/queue/items/test-item-1',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['item']['status'] == 'failed'
|
||||
assert data['item']['error_message'] == 'Test error'
|
||||
|
||||
def test_update_queue_item_invalid_status(self, client, mock_queue_service):
|
||||
"""Test updating a queue item with invalid status."""
|
||||
request_data = {
|
||||
'status': 'invalid_status'
|
||||
}
|
||||
|
||||
response = client.put('/api/queue/items/test-item-1',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
|
||||
def test_delete_queue_item_success(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test deleting a queue item successfully."""
|
||||
mock_queue_service.get_queue_item.return_value = sample_queue_item
|
||||
mock_queue_service.delete_items.return_value = True
|
||||
|
||||
response = client.delete('/api/queue/items/test-item-1')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert 'deleted successfully' in data['message']
|
||||
assert 'timestamp' in data
|
||||
|
||||
mock_queue_service.delete_items.assert_called_once_with(['test-item-1'])
|
||||
|
||||
def test_delete_queue_item_not_found(self, client, mock_queue_service):
|
||||
"""Test deleting a non-existent queue item."""
|
||||
mock_queue_service.get_queue_item.return_value = None
|
||||
|
||||
response = client.delete('/api/queue/items/nonexistent')
|
||||
|
||||
assert response.status_code == 404
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Not found'
|
||||
|
||||
def test_bulk_delete_items_success(self, client, mock_queue_service):
|
||||
"""Test bulk deleting queue items successfully."""
|
||||
mock_queue_service.delete_items.return_value = True
|
||||
|
||||
request_data = {
|
||||
'item_ids': ['item-1', 'item-2', 'item-3']
|
||||
}
|
||||
|
||||
response = client.delete('/api/queue/items/bulk',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['deleted_count'] == 3
|
||||
assert 'Successfully deleted' in data['message']
|
||||
|
||||
mock_queue_service.delete_items.assert_called_once_with(['item-1', 'item-2', 'item-3'])
|
||||
|
||||
def test_bulk_delete_items_empty_list(self, client, mock_queue_service):
|
||||
"""Test bulk deleting with empty item list."""
|
||||
request_data = {
|
||||
'item_ids': []
|
||||
}
|
||||
|
||||
response = client.delete('/api/queue/items/bulk',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
assert 'cannot be empty' in data['message']
|
||||
|
||||
def test_bulk_delete_items_missing_field(self, client, mock_queue_service):
|
||||
"""Test bulk deleting without item_ids field."""
|
||||
request_data = {}
|
||||
|
||||
response = client.delete('/api/queue/items/bulk',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
assert 'item_ids' in data['message']
|
||||
|
||||
def test_filter_queue_items_success(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test filtering queue items successfully."""
|
||||
mock_queue_service.filter_items.return_value = [sample_queue_item]
|
||||
|
||||
request_data = {
|
||||
'status': ['pending'],
|
||||
'workflow_name': 'Test'
|
||||
}
|
||||
|
||||
response = client.post('/api/queue/items/filter',
|
||||
data=json.dumps(request_data),
|
||||
content_type='application/json')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['count'] == 1
|
||||
assert len(data['items']) == 1
|
||||
assert 'filter' in data
|
||||
assert 'timestamp' in data
|
||||
|
||||
def test_search_queue_items_success(self, client, mock_queue_service, sample_queue_item):
|
||||
"""Test searching queue items successfully."""
|
||||
mock_queue_service.search_items.return_value = [sample_queue_item]
|
||||
|
||||
response = client.get('/api/queue/search?q=test')
|
||||
|
||||
assert response.status_code == 200
|
||||
data = json.loads(response.data)
|
||||
assert data['count'] == 1
|
||||
assert data['query'] == 'test'
|
||||
assert len(data['items']) == 1
|
||||
assert 'timestamp' in data
|
||||
|
||||
mock_queue_service.search_items.assert_called_once_with('test')
|
||||
|
||||
def test_search_queue_items_missing_query(self, client, mock_queue_service):
|
||||
"""Test searching queue items without query parameter."""
|
||||
response = client.get('/api/queue/search')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
assert 'query parameter' in data['message']
|
||||
|
||||
def test_search_queue_items_empty_query(self, client, mock_queue_service):
|
||||
"""Test searching queue items with empty query."""
|
||||
response = client.get('/api/queue/search?q=')
|
||||
|
||||
assert response.status_code == 400
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Bad request'
|
||||
|
||||
def test_queue_service_error_handling(self, client, mock_queue_service):
|
||||
"""Test handling of QueueServiceError."""
|
||||
mock_queue_service.get_queue_items.side_effect = QueueServiceError("Database error")
|
||||
|
||||
response = client.get('/api/queue/items')
|
||||
|
||||
assert response.status_code == 500
|
||||
data = json.loads(response.data)
|
||||
assert data['error'] == 'Queue service error'
|
||||
assert data['message'] == 'Database error'
|
||||
Reference in New Issue
Block a user