Files
abdullahceylan-ac-comfyui-q…/test_serialization_service.py

343 lines
13 KiB
Python

"""
Unit tests for the serialization service.
"""
import json
import pytest
from datetime import datetime, timezone
from unittest.mock import patch
from models import QueueItem, QueueStatus
from serialization_service import (
QueueDataSerializer,
SerializationError,
ValidationError,
)
class TestQueueDataSerializer:
"""Test cases for QueueDataSerializer."""
def setup_method(self):
"""Set up test fixtures."""
self.serializer = QueueDataSerializer()
# Create test queue items
self.test_items = [
QueueItem(
id="test-id-1",
workflow_name="Test Workflow 1",
workflow_data={"nodes": [{"id": 1, "type": "input"}]},
status=QueueStatus.COMPLETED,
created_at=datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc),
updated_at=datetime(2024, 1, 1, 12, 30, 0, tzinfo=timezone.utc),
started_at=datetime(2024, 1, 1, 12, 5, 0, tzinfo=timezone.utc),
completed_at=datetime(2024, 1, 1, 12, 25, 0, tzinfo=timezone.utc),
result_data={"output": "success"}
),
QueueItem(
id="test-id-2",
workflow_name="Test Workflow 2",
workflow_data={"nodes": [{"id": 2, "type": "process"}]},
status=QueueStatus.FAILED,
created_at=datetime(2024, 1, 2, 10, 0, 0, tzinfo=timezone.utc),
updated_at=datetime(2024, 1, 2, 10, 15, 0, tzinfo=timezone.utc),
started_at=datetime(2024, 1, 2, 10, 5, 0, tzinfo=timezone.utc),
error_message="Test error"
)
]
def test_serialize_queue_items_success(self):
"""Test successful serialization of queue items."""
with patch('serialization_service.datetime') as mock_datetime:
mock_datetime.now.return_value = datetime(2024, 1, 15, 14, 30, 0, tzinfo=timezone.utc)
mock_datetime.timezone = timezone
result = self.serializer.serialize_queue_items(self.test_items)
assert result["version"] == "1.0.0"
assert result["timestamp"] == "2024-01-15T14:30:00+00:00"
assert result["count"] == 2
assert len(result["items"]) == 2
# Check first item
item1 = result["items"][0]
assert item1["id"] == "test-id-1"
assert item1["workflow_name"] == "Test Workflow 1"
assert item1["status"] == "completed"
assert item1["result_data"] == {"output": "success"}
# Check second item
item2 = result["items"][1]
assert item2["id"] == "test-id-2"
assert item2["workflow_name"] == "Test Workflow 2"
assert item2["status"] == "failed"
assert item2["error_message"] == "Test error"
def test_serialize_empty_list(self):
"""Test serialization of empty queue items list."""
result = self.serializer.serialize_queue_items([])
assert result["version"] == "1.0.0"
assert result["count"] == 0
assert result["items"] == []
def test_serialize_queue_items_error(self):
"""Test serialization error handling."""
# Create an item that will cause serialization to fail
bad_item = QueueItem()
bad_item.workflow_data = {"circular": None}
bad_item.workflow_data["circular"] = bad_item.workflow_data # Circular reference
with pytest.raises(SerializationError):
self.serializer.serialize_queue_items([bad_item])
def test_deserialize_queue_items_success(self):
"""Test successful deserialization of queue items."""
data = {
"version": "1.0.0",
"timestamp": "2024-01-15T14:30:00+00:00",
"count": 2,
"items": [
{
"id": "test-id-1",
"workflow_name": "Test Workflow 1",
"workflow_data": {"nodes": [{"id": 1, "type": "input"}]},
"status": "completed",
"created_at": "2024-01-01T12:00:00+00:00",
"updated_at": "2024-01-01T12:30:00+00:00",
"started_at": "2024-01-01T12:05:00+00:00",
"completed_at": "2024-01-01T12:25:00+00:00",
"error_message": None,
"result_data": {"output": "success"}
},
{
"id": "test-id-2",
"workflow_name": "Test Workflow 2",
"workflow_data": {"nodes": [{"id": 2, "type": "process"}]},
"status": "failed",
"created_at": "2024-01-02T10:00:00+00:00",
"updated_at": "2024-01-02T10:15:00+00:00",
"started_at": "2024-01-02T10:05:00+00:00",
"completed_at": None,
"error_message": "Test error",
"result_data": None
}
]
}
items = self.serializer.deserialize_queue_items(data)
assert len(items) == 2
# Check first item
item1 = items[0]
assert item1.id == "test-id-1"
assert item1.workflow_name == "Test Workflow 1"
assert item1.status == QueueStatus.COMPLETED
assert item1.result_data == {"output": "success"}
# Check second item
item2 = items[1]
assert item2.id == "test-id-2"
assert item2.workflow_name == "Test Workflow 2"
assert item2.status == QueueStatus.FAILED
assert item2.error_message == "Test error"
def test_deserialize_empty_items(self):
"""Test deserialization of empty items list."""
data = {
"version": "1.0.0",
"timestamp": "2024-01-15T14:30:00+00:00",
"count": 0,
"items": []
}
items = self.serializer.deserialize_queue_items(data)
assert len(items) == 0
def test_serialize_to_json_success(self):
"""Test successful JSON serialization."""
json_str = self.serializer.serialize_to_json(self.test_items)
# Verify it's valid JSON
data = json.loads(json_str)
assert data["version"] == "1.0.0"
assert data["count"] == 2
assert len(data["items"]) == 2
def test_serialize_to_json_with_indent(self):
"""Test JSON serialization with custom indentation."""
json_str = self.serializer.serialize_to_json(self.test_items, indent=4)
# Check that indentation is applied
assert " " in json_str # 4-space indentation
# Verify it's still valid JSON
data = json.loads(json_str)
assert data["version"] == "1.0.0"
def test_deserialize_from_json_success(self):
"""Test successful JSON deserialization."""
json_str = '''
{
"version": "1.0.0",
"timestamp": "2024-01-15T14:30:00+00:00",
"count": 1,
"items": [
{
"id": "test-id",
"workflow_name": "Test Workflow",
"workflow_data": {"test": "data"},
"status": "pending",
"created_at": "2024-01-01T12:00:00+00:00",
"updated_at": "2024-01-01T12:00:00+00:00",
"started_at": null,
"completed_at": null,
"error_message": null,
"result_data": null
}
]
}
'''
items = self.serializer.deserialize_from_json(json_str)
assert len(items) == 1
assert items[0].id == "test-id"
assert items[0].workflow_name == "Test Workflow"
assert items[0].status == QueueStatus.PENDING
def test_deserialize_from_json_invalid_json(self):
"""Test JSON deserialization with invalid JSON."""
invalid_json = '{"invalid": json}'
with pytest.raises(SerializationError, match="Failed to decode JSON"):
self.serializer.deserialize_from_json(invalid_json)
def test_validate_queue_data_missing_version(self):
"""Test validation with missing version."""
data = {"items": []}
with pytest.raises(ValidationError, match="missing version information"):
self.serializer._validate_queue_data(data)
def test_validate_queue_data_unsupported_version(self):
"""Test validation with unsupported version."""
data = {"version": "2.0.0", "items": []}
with pytest.raises(ValidationError, match="Unsupported data format version"):
self.serializer._validate_queue_data(data)
def test_validate_queue_data_missing_items(self):
"""Test validation with missing items field."""
data = {"version": "1.0.0"}
with pytest.raises(ValidationError, match="missing 'items' field"):
self.serializer._validate_queue_data(data)
def test_validate_queue_data_items_not_list(self):
"""Test validation with items field not being a list."""
data = {"version": "1.0.0", "items": "not a list"}
with pytest.raises(ValidationError, match="'items' field must be a list"):
self.serializer._validate_queue_data(data)
def test_validate_queue_data_count_mismatch(self):
"""Test validation with count mismatch."""
data = {
"version": "1.0.0",
"items": [{"test": "item"}],
"count": 5
}
with pytest.raises(ValidationError, match="Item count mismatch"):
self.serializer._validate_queue_data(data)
def test_validate_item_data_not_dict(self):
"""Test item validation with non-dictionary data."""
with pytest.raises(ValidationError, match="must be a dictionary"):
self.serializer._validate_item_data("not a dict")
def test_validate_item_data_missing_required_field(self):
"""Test item validation with missing required field."""
item_data = {
"id": "test-id",
"workflow_name": "Test",
"workflow_data": {}
# Missing 'status' field
}
with pytest.raises(ValidationError, match="missing required field: status"):
self.serializer._validate_item_data(item_data)
def test_validate_item_data_invalid_status(self):
"""Test item validation with invalid status."""
item_data = {
"id": "test-id",
"workflow_name": "Test",
"workflow_data": {},
"status": "invalid_status"
}
with pytest.raises(ValidationError, match="Invalid status"):
self.serializer._validate_item_data(item_data)
def test_validate_item_data_workflow_data_not_dict(self):
"""Test item validation with workflow_data not being a dictionary."""
item_data = {
"id": "test-id",
"workflow_name": "Test",
"workflow_data": "not a dict",
"status": "pending"
}
with pytest.raises(ValidationError, match="'workflow_data' must be a dictionary"):
self.serializer._validate_item_data(item_data)
def test_validate_item_data_invalid_datetime(self):
"""Test item validation with invalid datetime format."""
item_data = {
"id": "test-id",
"workflow_name": "Test",
"workflow_data": {},
"status": "pending",
"created_at": "invalid-datetime"
}
with pytest.raises(ValidationError, match="Invalid datetime format"):
self.serializer._validate_item_data(item_data)
def test_get_supported_versions(self):
"""Test getting supported versions."""
versions = self.serializer.get_supported_versions()
assert "1.0.0" in versions
assert isinstance(versions, list)
def test_get_current_version(self):
"""Test getting current version."""
version = self.serializer.get_current_version()
assert version == "1.0.0"
def test_roundtrip_serialization(self):
"""Test complete roundtrip serialization and deserialization."""
# Serialize to JSON
json_str = self.serializer.serialize_to_json(self.test_items)
# Deserialize back to objects
deserialized_items = self.serializer.deserialize_from_json(json_str)
# Verify the data matches
assert len(deserialized_items) == len(self.test_items)
for original, deserialized in zip(self.test_items, deserialized_items):
assert original.id == deserialized.id
assert original.workflow_name == deserialized.workflow_name
assert original.workflow_data == deserialized.workflow_data
assert original.status == deserialized.status
assert original.created_at == deserialized.created_at
assert original.updated_at == deserialized.updated_at
assert original.started_at == deserialized.started_at
assert original.completed_at == deserialized.completed_at
assert original.error_message == deserialized.error_message
assert original.result_data == deserialized.result_data