775 lines
27 KiB
Python
775 lines
27 KiB
Python
"""Tests for FirestoreService."""
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
import pytest
|
|
from inline_snapshot import snapshot
|
|
|
|
from capa_de_integracion.models import ConversationEntry, ConversationSession
|
|
from capa_de_integracion.models.notification import Notification
|
|
from capa_de_integracion.services.firestore_service import FirestoreService
|
|
|
|
|
|
@pytest.mark.vcr
|
|
class TestSessionManagement:
|
|
"""Tests for conversation session management."""
|
|
|
|
async def test_create_session(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test creating a new conversation session."""
|
|
session = await clean_firestore.create_session(
|
|
session_id="test-session-1",
|
|
user_id="user-123",
|
|
telefono="+1234567890",
|
|
pantalla_contexto="home_screen",
|
|
last_message="Hello",
|
|
)
|
|
|
|
assert session.session_id == "test-session-1"
|
|
assert session.user_id == "user-123"
|
|
assert session.telefono == "+1234567890"
|
|
assert session.pantalla_contexto == "home_screen"
|
|
assert session.last_message == "Hello"
|
|
assert isinstance(session.last_modified, datetime)
|
|
|
|
async def test_get_session_existing(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test retrieving an existing session."""
|
|
# Create a session first
|
|
created_session = await clean_firestore.create_session(
|
|
session_id="test-session-2",
|
|
user_id="user-456",
|
|
telefono="+9876543210",
|
|
)
|
|
|
|
# Retrieve it
|
|
retrieved_session = await clean_firestore.get_session("test-session-2")
|
|
|
|
assert retrieved_session is not None
|
|
assert retrieved_session.session_id == created_session.session_id
|
|
assert retrieved_session.user_id == created_session.user_id
|
|
assert retrieved_session.telefono == created_session.telefono
|
|
|
|
async def test_get_session_not_found(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test retrieving a non-existent session returns None."""
|
|
session = await clean_firestore.get_session("nonexistent-session")
|
|
assert session is None
|
|
|
|
@pytest.mark.skip(reason="Requires composite index in Firestore emulator. See firestore.indexes.json")
|
|
async def test_get_session_by_phone_existing(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test retrieving session by phone number.
|
|
|
|
Note: This test requires a composite index (telefono + lastModified)
|
|
which must be configured in the Firestore emulator. To enable this test,
|
|
restart the emulator with: firebase emulators:start --only firestore --import=./
|
|
"""
|
|
phone = "+1111111111"
|
|
|
|
# Create multiple sessions for same phone
|
|
await clean_firestore.create_session(
|
|
session_id="session-1",
|
|
user_id="user-1",
|
|
telefono=phone,
|
|
)
|
|
|
|
# Wait a bit to ensure different timestamps
|
|
import asyncio
|
|
await asyncio.sleep(0.1)
|
|
|
|
session_2 = await clean_firestore.create_session(
|
|
session_id="session-2",
|
|
user_id="user-1",
|
|
telefono=phone,
|
|
)
|
|
|
|
# Should retrieve the most recent one
|
|
retrieved = await clean_firestore.get_session_by_phone(phone)
|
|
|
|
assert retrieved is not None
|
|
assert retrieved.session_id == session_2.session_id
|
|
|
|
async def test_get_session_by_phone_not_found(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test retrieving session by phone when none exists."""
|
|
session = await clean_firestore.get_session_by_phone("+9999999999")
|
|
assert session is None
|
|
|
|
async def test_get_session_by_phone_found(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test retrieving session by phone when it exists (mocked)."""
|
|
from unittest.mock import MagicMock
|
|
|
|
phone = "+1111111111"
|
|
expected_session = ConversationSession.create(
|
|
session_id="session-1",
|
|
user_id="user-1",
|
|
telefono=phone,
|
|
)
|
|
|
|
# Mock the query to return a session
|
|
mock_doc = MagicMock()
|
|
mock_doc.to_dict.return_value = expected_session.model_dump()
|
|
|
|
async def mock_stream():
|
|
yield mock_doc
|
|
|
|
mock_query = MagicMock()
|
|
mock_query.stream.return_value = mock_stream()
|
|
|
|
mock_collection = MagicMock()
|
|
mock_where = MagicMock()
|
|
mock_order = MagicMock()
|
|
mock_collection.where.return_value = mock_where
|
|
mock_where.order_by.return_value = mock_order
|
|
mock_order.limit.return_value = mock_query
|
|
|
|
original_collection = clean_firestore.db.collection
|
|
clean_firestore.db.collection = MagicMock(return_value=mock_collection)
|
|
|
|
try:
|
|
result = await clean_firestore.get_session_by_phone(phone)
|
|
assert result is not None
|
|
assert result.session_id == "session-1"
|
|
assert result.telefono == phone
|
|
finally:
|
|
clean_firestore.db.collection = original_collection
|
|
|
|
async def test_save_session(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test saving an updated session."""
|
|
# Create initial session
|
|
session = await clean_firestore.create_session(
|
|
session_id="test-session-3",
|
|
user_id="user-789",
|
|
telefono="+5555555555",
|
|
)
|
|
|
|
# Update session
|
|
session.last_message = "Updated message"
|
|
session.pantalla_contexto = "new_screen"
|
|
|
|
# Save updated session
|
|
success = await clean_firestore.save_session(session)
|
|
assert success is True
|
|
|
|
# Retrieve and verify
|
|
retrieved = await clean_firestore.get_session("test-session-3")
|
|
assert retrieved is not None
|
|
assert retrieved.last_message == "Updated message"
|
|
assert retrieved.pantalla_contexto == "new_screen"
|
|
|
|
async def test_update_pantalla_contexto(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test updating pantalla_contexto field."""
|
|
# Create session
|
|
await clean_firestore.create_session(
|
|
session_id="test-session-4",
|
|
user_id="user-101",
|
|
telefono="+2222222222",
|
|
pantalla_contexto="initial_screen",
|
|
)
|
|
|
|
# Update pantalla_contexto
|
|
success = await clean_firestore.update_pantalla_contexto(
|
|
"test-session-4",
|
|
"updated_screen",
|
|
)
|
|
assert success is True
|
|
|
|
# Verify update
|
|
session = await clean_firestore.get_session("test-session-4")
|
|
assert session is not None
|
|
assert session.pantalla_contexto == "updated_screen"
|
|
|
|
async def test_update_pantalla_contexto_nonexistent_session(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test updating pantalla_contexto for non-existent session."""
|
|
success = await clean_firestore.update_pantalla_contexto(
|
|
"nonexistent-session",
|
|
"some_screen",
|
|
)
|
|
assert success is False
|
|
|
|
async def test_delete_session(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test deleting a session."""
|
|
# Create session
|
|
await clean_firestore.create_session(
|
|
session_id="test-session-5",
|
|
user_id="user-202",
|
|
telefono="+3333333333",
|
|
)
|
|
|
|
# Delete session
|
|
success = await clean_firestore.delete_session("test-session-5")
|
|
assert success is True
|
|
|
|
# Verify deletion
|
|
session = await clean_firestore.get_session("test-session-5")
|
|
assert session is None
|
|
|
|
|
|
@pytest.mark.vcr
|
|
class TestEntryManagement:
|
|
"""Tests for conversation entry management."""
|
|
|
|
async def test_save_and_get_entries(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test saving and retrieving conversation entries."""
|
|
# Create session
|
|
await clean_firestore.create_session(
|
|
session_id="test-session-6",
|
|
user_id="user-303",
|
|
telefono="+4444444444",
|
|
)
|
|
|
|
# Create entries
|
|
entry1 = ConversationEntry(
|
|
timestamp=datetime.now(UTC),
|
|
entity="user",
|
|
type="CONVERSACION",
|
|
text="First message",
|
|
)
|
|
entry2 = ConversationEntry(
|
|
timestamp=datetime.now(UTC),
|
|
entity="assistant",
|
|
type="CONVERSACION",
|
|
text="First response",
|
|
)
|
|
|
|
# Save entries
|
|
success1 = await clean_firestore.save_entry("test-session-6", entry1)
|
|
success2 = await clean_firestore.save_entry("test-session-6", entry2)
|
|
|
|
assert success1 is True
|
|
assert success2 is True
|
|
|
|
# Retrieve entries
|
|
entries = await clean_firestore.get_entries("test-session-6")
|
|
|
|
assert len(entries) == 2
|
|
assert entries[0].entity == "user"
|
|
assert entries[0].text == "First message"
|
|
assert entries[1].entity == "assistant"
|
|
assert entries[1].text == "First response"
|
|
|
|
async def test_get_entries_with_limit(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test retrieving entries with limit."""
|
|
# Create session
|
|
await clean_firestore.create_session(
|
|
session_id="test-session-7",
|
|
user_id="user-404",
|
|
telefono="+5555555555",
|
|
)
|
|
|
|
# Create multiple entries
|
|
for i in range(5):
|
|
entry = ConversationEntry(
|
|
timestamp=datetime.now(UTC),
|
|
entity="user" if i % 2 == 0 else "assistant",
|
|
type="CONVERSACION",
|
|
text=f"Message {i}",
|
|
)
|
|
await clean_firestore.save_entry("test-session-7", entry)
|
|
|
|
# Retrieve with limit
|
|
entries = await clean_firestore.get_entries("test-session-7", limit=3)
|
|
|
|
assert len(entries) == 3
|
|
# Should get the most recent 3 in chronological order
|
|
assert entries[-1].text == "Message 4"
|
|
|
|
async def test_get_entries_empty_session(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test retrieving entries from session with no entries."""
|
|
# Create session without entries
|
|
await clean_firestore.create_session(
|
|
session_id="test-session-8",
|
|
user_id="user-505",
|
|
telefono="+6666666666",
|
|
)
|
|
|
|
entries = await clean_firestore.get_entries("test-session-8")
|
|
assert entries == []
|
|
|
|
async def test_delete_session_with_entries(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test deleting session also deletes all entries."""
|
|
# Create session with entries
|
|
await clean_firestore.create_session(
|
|
session_id="test-session-9",
|
|
user_id="user-606",
|
|
telefono="+7777777777",
|
|
)
|
|
|
|
entry = ConversationEntry(
|
|
timestamp=datetime.now(UTC),
|
|
entity="user",
|
|
type="CONVERSACION",
|
|
text="Test message",
|
|
)
|
|
await clean_firestore.save_entry("test-session-9", entry)
|
|
|
|
# Delete session
|
|
success = await clean_firestore.delete_session("test-session-9")
|
|
assert success is True
|
|
|
|
# Verify entries are also deleted
|
|
entries = await clean_firestore.get_entries("test-session-9")
|
|
assert entries == []
|
|
|
|
|
|
@pytest.mark.vcr
|
|
class TestNotificationManagement:
|
|
"""Tests for notification management."""
|
|
|
|
async def test_save_new_notification(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test saving a new notification creates new session."""
|
|
notification = Notification.create(
|
|
id_notificacion="notif-1",
|
|
telefono="+8888888888",
|
|
texto="Test notification",
|
|
)
|
|
|
|
await clean_firestore.save_or_append_notification(notification)
|
|
|
|
# Verify notification was saved
|
|
doc_ref = clean_firestore._notification_ref("+8888888888")
|
|
doc = await doc_ref.get()
|
|
|
|
assert doc.exists
|
|
data = doc.to_dict()
|
|
assert data is not None
|
|
assert data["telefono"] == "+8888888888"
|
|
assert data["session_id"] == "+8888888888"
|
|
assert len(data["notificaciones"]) == 1
|
|
assert data["notificaciones"][0]["texto"] == "Test notification"
|
|
|
|
async def test_append_to_existing_notification_session(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test appending notification to existing session."""
|
|
phone = "+9999999999"
|
|
|
|
# Create first notification
|
|
notification1 = Notification.create(
|
|
id_notificacion="notif-2",
|
|
telefono=phone,
|
|
texto="First notification",
|
|
)
|
|
await clean_firestore.save_or_append_notification(notification1)
|
|
|
|
# Append second notification
|
|
notification2 = Notification.create(
|
|
id_notificacion="notif-3",
|
|
telefono=phone,
|
|
texto="Second notification",
|
|
)
|
|
await clean_firestore.save_or_append_notification(notification2)
|
|
|
|
# Verify both notifications exist
|
|
doc_ref = clean_firestore._notification_ref(phone)
|
|
doc = await doc_ref.get()
|
|
data = doc.to_dict()
|
|
|
|
assert data is not None
|
|
assert len(data["notificaciones"]) == 2
|
|
assert data["notificaciones"][0]["texto"] == "First notification"
|
|
assert data["notificaciones"][1]["texto"] == "Second notification"
|
|
|
|
async def test_save_notification_without_phone_raises_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test saving notification without phone number raises ValueError."""
|
|
notification = Notification.create(
|
|
id_notificacion="notif-4",
|
|
telefono="",
|
|
texto="Test",
|
|
)
|
|
|
|
with pytest.raises(ValueError, match="Phone number is required"):
|
|
await clean_firestore.save_or_append_notification(notification)
|
|
|
|
async def test_update_notification_status(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test updating status of all notifications in session."""
|
|
phone = "+1010101010"
|
|
|
|
# Create notifications
|
|
notification1 = Notification.create(
|
|
id_notificacion="notif-5",
|
|
telefono=phone,
|
|
texto="Notification 1",
|
|
status="pending",
|
|
)
|
|
notification2 = Notification.create(
|
|
id_notificacion="notif-6",
|
|
telefono=phone,
|
|
texto="Notification 2",
|
|
status="pending",
|
|
)
|
|
|
|
await clean_firestore.save_or_append_notification(notification1)
|
|
await clean_firestore.save_or_append_notification(notification2)
|
|
|
|
# Update status
|
|
await clean_firestore.update_notification_status(phone, "sent")
|
|
|
|
# Verify status update
|
|
doc_ref = clean_firestore._notification_ref(phone)
|
|
doc = await doc_ref.get()
|
|
data = doc.to_dict()
|
|
|
|
assert data is not None
|
|
assert all(notif["status"] == "sent" for notif in data["notificaciones"])
|
|
|
|
async def test_update_notification_status_nonexistent_session(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test updating status for non-existent session logs warning."""
|
|
# Should not raise exception, just log warning
|
|
await clean_firestore.update_notification_status("+0000000000", "sent")
|
|
|
|
async def test_delete_notification(self, clean_firestore: FirestoreService) -> None:
|
|
"""Test deleting notification session."""
|
|
phone = "+1212121212"
|
|
|
|
# Create notification
|
|
notification = Notification.create(
|
|
id_notificacion="notif-7",
|
|
telefono=phone,
|
|
texto="Test",
|
|
)
|
|
await clean_firestore.save_or_append_notification(notification)
|
|
|
|
# Delete notification session
|
|
success = await clean_firestore.delete_notification(phone)
|
|
assert success is True
|
|
|
|
# Verify deletion
|
|
doc_ref = clean_firestore._notification_ref(phone)
|
|
doc = await doc_ref.get()
|
|
assert not doc.exists
|
|
|
|
|
|
@pytest.mark.vcr
|
|
class TestEdgeCases:
|
|
"""Tests for edge cases and error handling."""
|
|
|
|
async def test_concurrent_session_updates(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test concurrent updates to same session."""
|
|
import asyncio
|
|
|
|
# Create session
|
|
session = await clean_firestore.create_session(
|
|
session_id="test-concurrent",
|
|
user_id="user-999",
|
|
telefono="+1313131313",
|
|
)
|
|
|
|
# Update session fields concurrently
|
|
session.last_message = "Message 1"
|
|
task1 = clean_firestore.save_session(session)
|
|
|
|
session.last_message = "Message 2"
|
|
task2 = clean_firestore.save_session(session)
|
|
|
|
results = await asyncio.gather(task1, task2)
|
|
assert all(results)
|
|
|
|
# Verify final state
|
|
final_session = await clean_firestore.get_session("test-concurrent")
|
|
assert final_session is not None
|
|
# Last write wins
|
|
assert final_session.last_message in ["Message 1", "Message 2"]
|
|
|
|
async def test_special_characters_in_data(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test handling special characters in session data."""
|
|
session = await clean_firestore.create_session(
|
|
session_id="test-special-chars",
|
|
user_id="user-special",
|
|
telefono="+1414141414",
|
|
pantalla_contexto="screen/with/slashes",
|
|
last_message="Message with emoji 🎉 and special chars: <>&\"'",
|
|
)
|
|
|
|
# Retrieve and verify
|
|
retrieved = await clean_firestore.get_session("test-special-chars")
|
|
assert retrieved is not None
|
|
assert retrieved.pantalla_contexto == "screen/with/slashes"
|
|
assert "🎉" in retrieved.last_message
|
|
assert "<>&\"'" in retrieved.last_message
|
|
|
|
|
|
@pytest.mark.vcr
|
|
class TestErrorHandling:
|
|
"""Tests for error handling in Firestore operations."""
|
|
|
|
async def test_get_session_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test get_session handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
mock_doc_ref.get.side_effect = Exception("Database error")
|
|
|
|
original_session_ref = clean_firestore._session_ref
|
|
clean_firestore._session_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.get_session("error-session")
|
|
assert result is None
|
|
finally:
|
|
clean_firestore._session_ref = original_session_ref
|
|
|
|
async def test_get_session_by_phone_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test get_session_by_phone handles database errors gracefully."""
|
|
from unittest.mock import MagicMock
|
|
|
|
mock_collection = MagicMock()
|
|
mock_collection.where.side_effect = Exception("Database error")
|
|
|
|
original_collection = clean_firestore.db.collection
|
|
clean_firestore.db.collection = MagicMock(return_value=mock_collection)
|
|
|
|
try:
|
|
result = await clean_firestore.get_session_by_phone("+0000000000")
|
|
assert result is None
|
|
finally:
|
|
clean_firestore.db.collection = original_collection
|
|
|
|
async def test_save_session_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test save_session handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
session = ConversationSession.create(
|
|
session_id="error-session",
|
|
user_id="user-error",
|
|
telefono="+0000000000",
|
|
)
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
mock_doc_ref.set.side_effect = Exception("Database error")
|
|
|
|
original_session_ref = clean_firestore._session_ref
|
|
clean_firestore._session_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.save_session(session)
|
|
assert result is False
|
|
finally:
|
|
clean_firestore._session_ref = original_session_ref
|
|
|
|
async def test_save_entry_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test save_entry handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
entry = ConversationEntry(
|
|
timestamp=datetime.now(UTC),
|
|
entity="user",
|
|
type="CONVERSACION",
|
|
text="Test",
|
|
)
|
|
|
|
mock_entry_doc = AsyncMock()
|
|
mock_entry_doc.set.side_effect = Exception("Database error")
|
|
|
|
mock_collection = MagicMock()
|
|
mock_collection.document.return_value = mock_entry_doc
|
|
|
|
mock_doc_ref = MagicMock()
|
|
mock_doc_ref.collection.return_value = mock_collection
|
|
|
|
original_session_ref = clean_firestore._session_ref
|
|
clean_firestore._session_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.save_entry("error-session", entry)
|
|
assert result is False
|
|
finally:
|
|
clean_firestore._session_ref = original_session_ref
|
|
|
|
async def test_get_entries_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test get_entries handles database errors gracefully."""
|
|
from unittest.mock import MagicMock
|
|
|
|
mock_collection = MagicMock()
|
|
mock_collection.order_by.side_effect = Exception("Database error")
|
|
|
|
mock_doc_ref = MagicMock()
|
|
mock_doc_ref.collection.return_value = mock_collection
|
|
|
|
original_session_ref = clean_firestore._session_ref
|
|
clean_firestore._session_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.get_entries("error-session")
|
|
assert result == []
|
|
finally:
|
|
clean_firestore._session_ref = original_session_ref
|
|
|
|
async def test_delete_session_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test delete_session handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
mock_collection = MagicMock()
|
|
|
|
async def mock_stream():
|
|
mock_entry = MagicMock()
|
|
mock_entry.reference = AsyncMock()
|
|
yield mock_entry
|
|
|
|
mock_collection.stream.return_value = mock_stream()
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
mock_doc_ref.collection.return_value = mock_collection
|
|
mock_doc_ref.delete.side_effect = Exception("Database error")
|
|
|
|
original_session_ref = clean_firestore._session_ref
|
|
clean_firestore._session_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.delete_session("error-session")
|
|
assert result is False
|
|
finally:
|
|
clean_firestore._session_ref = original_session_ref
|
|
|
|
async def test_update_pantalla_contexto_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test update_pantalla_contexto handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
mock_doc = MagicMock()
|
|
mock_doc.exists = True
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
|
|
async def mock_get():
|
|
return mock_doc
|
|
|
|
mock_doc_ref.get = mock_get
|
|
mock_doc_ref.update.side_effect = Exception("Database error")
|
|
|
|
original_session_ref = clean_firestore._session_ref
|
|
clean_firestore._session_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.update_pantalla_contexto("error-session", "screen")
|
|
assert result is False
|
|
finally:
|
|
clean_firestore._session_ref = original_session_ref
|
|
|
|
async def test_save_or_append_notification_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test save_or_append_notification handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
notification = Notification.create(
|
|
id_notificacion="notif-error",
|
|
telefono="+0000000000",
|
|
texto="Test",
|
|
)
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
mock_doc_ref.get.side_effect = Exception("Database error")
|
|
|
|
original_notification_ref = clean_firestore._notification_ref
|
|
clean_firestore._notification_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
with pytest.raises(Exception):
|
|
await clean_firestore.save_or_append_notification(notification)
|
|
finally:
|
|
clean_firestore._notification_ref = original_notification_ref
|
|
|
|
async def test_update_notification_status_with_empty_data(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test update_notification_status handles empty session data."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
mock_doc = MagicMock()
|
|
mock_doc.exists = True
|
|
mock_doc.to_dict.return_value = None
|
|
|
|
async def mock_get():
|
|
return mock_doc
|
|
|
|
mock_doc_ref.get = mock_get
|
|
|
|
original_notification_ref = clean_firestore._notification_ref
|
|
clean_firestore._notification_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
# Should not raise, just log warning
|
|
await clean_firestore.update_notification_status("+0000000000", "sent")
|
|
finally:
|
|
clean_firestore._notification_ref = original_notification_ref
|
|
|
|
async def test_update_notification_status_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test update_notification_status handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
mock_doc = MagicMock()
|
|
mock_doc.exists = True
|
|
mock_doc.to_dict.return_value = {"notificaciones": [{"status": "pending"}]}
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
|
|
async def mock_get():
|
|
return mock_doc
|
|
|
|
mock_doc_ref.get = mock_get
|
|
mock_doc_ref.update.side_effect = Exception("Database error")
|
|
|
|
original_notification_ref = clean_firestore._notification_ref
|
|
clean_firestore._notification_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
with pytest.raises(Exception):
|
|
await clean_firestore.update_notification_status("+0000000000", "sent")
|
|
finally:
|
|
clean_firestore._notification_ref = original_notification_ref
|
|
|
|
async def test_delete_notification_with_db_error(
|
|
self, clean_firestore: FirestoreService,
|
|
) -> None:
|
|
"""Test delete_notification handles database errors gracefully."""
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
mock_doc_ref = AsyncMock()
|
|
mock_doc_ref.delete.side_effect = Exception("Database error")
|
|
|
|
original_notification_ref = clean_firestore._notification_ref
|
|
clean_firestore._notification_ref = MagicMock(return_value=mock_doc_ref)
|
|
|
|
try:
|
|
result = await clean_firestore.delete_notification("+0000000000")
|
|
assert result is False
|
|
finally:
|
|
clean_firestore._notification_ref = original_notification_ref
|