freeleaps-service-hub/apps/notification/tests/unit_tests/test_services.py
YuehuCao def50f709f test: add unit tests for template_message and email_sender services
- Achieve 100% coverage for both services
2025-07-28 11:03:01 +08:00

818 lines
34 KiB
Python

import pytest
from unittest.mock import Mock, AsyncMock, patch
import re
from backend.services.template_message_service import TemplateMessageService
from backend.services.email_sender_service import EmailSenderService
from backend.models.models import MessageTemplateDoc, EmailSenderDoc
class TestTemplateMessageServiceUnit:
"""Unit tests for TemplateMessageService"""
def test_service_initialization(self):
"""Test service can be initialized."""
service = TemplateMessageService()
assert service is not None
@pytest.mark.asyncio
async def test_update_global_template_success(self):
"""Test successful global template update."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.tenant_id = None # Global template
mock_template.set = AsyncMock()
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
result = await service.update_global_template("template_id", {"subject": "New Subject"})
mock_template.set.assert_called_once_with({"subject": "New Subject"})
assert result == {"success": True}
@pytest.mark.asyncio
async def test_create_global_template(self):
"""Test creating global template."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.tenant_id = "some_tenant"
mock_template.create = AsyncMock(return_value=mock_template)
# Test global template creation
result = await service.create_global_template(mock_template)
# Verify tenant_id is set to None
assert mock_template.tenant_id is None
mock_template.create.assert_called_once()
assert result == mock_template
@pytest.mark.asyncio
async def test_update_global_template_not_found(self):
"""Test updating non-existent global template."""
service = TemplateMessageService()
# Mock MessageTemplateDoc.get returning None
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=None):
with pytest.raises(PermissionError, match="Not a global template"):
await service.update_global_template("template_id", {"subject": "New Subject"})
@pytest.mark.asyncio
async def test_update_global_template_not_global(self):
"""Test updating tenant template as global template."""
service = TemplateMessageService()
# Mock template (tenant template)
mock_template = Mock()
mock_template.tenant_id = "tenant_123" # Not global
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
with pytest.raises(PermissionError, match="Not a global template"):
await service.update_global_template("template_id", {"subject": "New Subject"})
@pytest.mark.asyncio
async def test_delete_global_template_success(self):
"""Test successful global template deletion."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.tenant_id = None # Global template
mock_template.delete = AsyncMock()
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
result = await service.delete_global_template("template_id")
mock_template.delete.assert_called_once()
assert result == {"success": True}
@pytest.mark.asyncio
async def test_delete_global_template_not_found(self):
"""Test deleting non-existent global template."""
service = TemplateMessageService()
# Mock MessageTemplateDoc.get returning None
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=None):
with pytest.raises(PermissionError, match="Not a global template"):
await service.delete_global_template("template_id")
@pytest.mark.asyncio
async def test_delete_global_template_not_global(self):
"""Test deleting tenant template as global template."""
service = TemplateMessageService()
# Mock template (tenant template)
mock_template = Mock()
mock_template.tenant_id = "tenant_123" # Not global
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
with pytest.raises(PermissionError, match="Not a global template"):
await service.delete_global_template("template_id")
@pytest.mark.asyncio
async def test_get_template(self):
"""Test getting template by template_id, tenant_id, and region."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
# Mock MessageTemplateDoc.find_one
with patch('backend.services.template_message_service.MessageTemplateDoc.find_one', new_callable=AsyncMock, return_value=mock_template):
result = await service.get_template("template_id", "tenant_123", 1)
assert result == mock_template
@pytest.mark.asyncio
async def test_list_global_templates(self):
"""Test listing global templates."""
service = TemplateMessageService()
# Mock templates list
mock_templates = [Mock(), Mock()]
mock_query = Mock()
mock_query.to_list = AsyncMock(return_value=mock_templates)
# Mock MessageTemplateDoc.find
with patch('backend.services.template_message_service.MessageTemplateDoc.find', return_value=mock_query):
result = await service.list_global_templates(1)
assert result == mock_templates
@pytest.mark.asyncio
async def test_list_tenant_templates(self):
"""Test listing tenant templates."""
service = TemplateMessageService()
# Mock templates list
mock_templates = [Mock(), Mock()]
mock_query = Mock()
mock_query.to_list = AsyncMock(return_value=mock_templates)
# Mock MessageTemplateDoc.find
with patch('backend.services.template_message_service.MessageTemplateDoc.find', return_value=mock_query):
result = await service.list_tenant_templates("tenant_123", 1)
assert result == mock_templates
@pytest.mark.asyncio
async def test_assign_template_to_tenant_already_assigned(self):
"""Test assigning template that tenant already has."""
service = TemplateMessageService()
# Mock global template
mock_global_template = Mock()
mock_global_template.template_id = "template_1"
mock_global_template.region = 1
mock_global_template.subject = "Test Subject"
mock_global_template.body = "Test Body"
# Mock existing tenant template
mock_existing_template = Mock()
# Create a mock that returns different values based on the query
async def mock_find_one(query):
if query.get("tenant_id") is None: # Global template query
return mock_global_template
else: # Tenant template query
return mock_existing_template # Template already exists
# Mock MessageTemplateDoc.find_one
with patch('backend.services.template_message_service.MessageTemplateDoc.find_one', side_effect=mock_find_one):
result = await service.assign_template_to_tenant(["template_1"], 1, "tenant_123")
assert len(result) == 1
assert result[0]["template_id"] == "template_1"
assert result[0]["success"] is False
assert "Template already assigned" in result[0]["msg"]
@pytest.mark.asyncio
async def test_assign_template_to_tenant_not_found(self):
"""Test assigning non-existent template to tenant."""
service = TemplateMessageService()
# Mock MessageTemplateDoc.find_one returning None for global template
with patch('backend.services.template_message_service.MessageTemplateDoc.find_one', new_callable=AsyncMock, return_value=None):
result = await service.assign_template_to_tenant(["non_existent_template"], 1, "tenant_123")
assert len(result) == 1
assert result[0]["template_id"] == "non_existent_template"
assert result[0]["success"] is False
assert "Template not found" in result[0]["msg"]
@pytest.mark.asyncio
async def test_assign_template_to_tenant_success_complex(self):
"""Test successful template assignment to tenant with complex mocking."""
service = TemplateMessageService()
# Mock global template
mock_global_template = Mock()
mock_global_template.template_id = "template_1"
mock_global_template.region = 1
mock_global_template.subject = "Test Subject"
mock_global_template.body = "Test Body"
# Mock new template
mock_new_template = Mock()
mock_new_template.id = "new_id"
mock_new_template.create = AsyncMock()
# Create a simple async mock function
async def mock_find_one(query):
if query.get("tenant_id") is None: # Global template query
return mock_global_template
else: # Tenant template query
return None # No existing template
# Mock the entire MessageTemplateDoc class
with patch('backend.services.template_message_service.MessageTemplateDoc') as mock_doc_class:
# Set up the find_one method
mock_doc_class.find_one = mock_find_one
# Set up the constructor
mock_doc_class.return_value = mock_new_template
result = await service.assign_template_to_tenant(["template_1"], 1, "tenant_123")
assert len(result) == 1
assert result[0]["template_id"] == "template_1"
assert result[0]["success"] is True
assert "template_db_id" in result[0]
@pytest.mark.asyncio
async def test_create_template_tenant_success(self):
"""Test creating tenant template."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.tenant_id = None
mock_template.create = AsyncMock(return_value=mock_template)
result = await service.create_template(mock_template, "tenant_123")
# Verify tenant_id is set
assert mock_template.tenant_id == "tenant_123"
mock_template.create.assert_called_once()
assert result == mock_template
@pytest.mark.asyncio
async def test_update_template_tenant_success(self):
"""Test successful template update."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.tenant_id = "tenant_123"
mock_template.set = AsyncMock()
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
result = await service.update_template("template_id", "tenant_123", {"subject": "New Subject"})
mock_template.set.assert_called_once_with({"subject": "New Subject"})
assert result == {"success": True}
@pytest.mark.asyncio
async def test_update_template_tenant_not_found(self):
"""Test updating non-existent template."""
service = TemplateMessageService()
# Mock MessageTemplateDoc.get returning None
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=None):
with pytest.raises(PermissionError, match="Forbidden"):
await service.update_template("template_id", "tenant_123", {"subject": "New Subject"})
@pytest.mark.asyncio
async def test_update_template_tenant_forbidden(self):
"""Test template update with wrong tenant."""
service = TemplateMessageService()
# Mock template with different tenant
mock_template = Mock()
mock_template.tenant_id = "tenant_456" # Different tenant
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
with pytest.raises(PermissionError, match="Forbidden"):
await service.update_template("template_id", "tenant_123", {"subject": "New Subject"})
@pytest.mark.asyncio
async def test_delete_template_tenant_success(self):
"""Test successful template deletion."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.tenant_id = "tenant_123"
mock_template.delete = AsyncMock()
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
result = await service.delete_template("template_id", "tenant_123")
mock_template.delete.assert_called_once()
assert result == {"success": True}
@pytest.mark.asyncio
async def test_delete_template_tenant_not_found(self):
"""Test deleting non-existent template."""
service = TemplateMessageService()
# Mock MessageTemplateDoc.get returning None
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=None):
with pytest.raises(PermissionError, match="Forbidden"):
await service.delete_template("template_id", "tenant_123")
@pytest.mark.asyncio
async def test_delete_template_tenant_forbidden(self):
"""Test deleting template with wrong tenant."""
service = TemplateMessageService()
# Mock template with different tenant
mock_template = Mock()
mock_template.tenant_id = "tenant_456" # Different tenant
# Mock MessageTemplateDoc.get
with patch('backend.services.template_message_service.MessageTemplateDoc.get', new_callable=AsyncMock, return_value=mock_template):
with pytest.raises(PermissionError, match="Forbidden"):
await service.delete_template("template_id", "tenant_123")
def test_template_rendering_logic(self):
"""Test template rendering logic without database."""
# Mock template data (simulating what would come from database)
mock_template = Mock()
mock_template.subject = "Hello {name}, your code is {code}"
mock_template.body = "Welcome {name}! Your verification code is {code}. Please use it within {expiry} minutes."
# Extract placeholders with regex
subject_placeholders = re.findall(r'\{(\w+)\}', mock_template.subject)
body_placeholders = re.findall(r'\{(\w+)\}', mock_template.body)
# Analyze count and type of placeholders
print(f"Subject placeholders: {subject_placeholders}") # ['name', 'code']
print(f"Body placeholders: {body_placeholders}") # ['name', 'code', 'expiry']
# Count placeholders
subject_count = len(subject_placeholders)
body_count = len(body_placeholders)
total_unique = len(set(subject_placeholders + body_placeholders))
print(f"Subject placeholder count: {subject_count}")
print(f"Body placeholder count: {body_count}")
print(f"Total unique placeholders: {total_unique}")
# Validate placeholder types
assert "name" in subject_placeholders
assert "code" in subject_placeholders
assert "name" in body_placeholders
assert "code" in body_placeholders
assert "expiry" in body_placeholders
# Get all required properties
required_properties = set(subject_placeholders + body_placeholders)
print(f"Required properties: {required_properties}") # {'name', 'code', 'expiry'}
# Test properties
properties = {
"name": "John Doe",
"code": "123456",
"expiry": "10"
}
# Validate all required properties are provided
missing_properties = required_properties - set(properties.keys())
assert len(missing_properties) == 0, f"Missing properties: {missing_properties}"
# Test rendering logic
subject = mock_template.subject.format(**properties)
body = mock_template.body.format(**properties)
assert subject == "Hello John Doe, your code is 123456"
assert body == "Welcome John Doe! Your verification code is 123456. Please use it within 10 minutes."
# Test error handling when missing properties
incomplete_properties = {"name": "John Doe"} # Missing code and expiry
missing_properties = required_properties - set(incomplete_properties.keys())
assert len(missing_properties) == 2
assert "code" in missing_properties
assert "expiry" in missing_properties
# Validate that KeyError is raised when missing properties
with pytest.raises(KeyError):
mock_template.subject.format(**incomplete_properties)
@pytest.mark.asyncio
async def test_render_template_success(self):
"""Test successful template rendering."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.subject = "Hello {name}"
mock_template.body = "Welcome {name}!"
properties = {"name": "John"}
# Test successful rendering
subject, body = await service.render_template(mock_template, properties)
assert subject == "Hello John"
assert body == "Welcome John!"
@pytest.mark.asyncio
async def test_render_template_missing_property(self):
"""Test template rendering with missing property."""
service = TemplateMessageService()
# Mock template
mock_template = Mock()
mock_template.subject = "Hello {name}"
mock_template.body = "Welcome {name}!"
properties = {} # Missing "name"
# Test error handling
with pytest.raises(ValueError, match="Missing template parameter"):
await service.render_template(mock_template, properties)
def test_complex_template_placeholder_analysis(self):
"""Test analyzing complex templates with multiple placeholders."""
# Complex template with various types of placeholders
complex_template = Mock()
complex_template.subject = "Interview {type} for {position} - {company}"
complex_template.body = """
Dear {name},
Your {type} interview for the {position} position at {company} has been scheduled.
Details:
- Date: {date}
- Time: {time}
- Duration: {duration} minutes
- Interviewer: {interviewer}
- Location: {location}
Please confirm your attendance by replying to this email.
Best regards,
{company} HR Team
"""
# Extract placeholders
subject_placeholders = re.findall(r'\{(\w+)\}', complex_template.subject)
body_placeholders = re.findall(r'\{(\w+)\}', complex_template.body)
# Analyze placeholder statistics
all_placeholders = subject_placeholders + body_placeholders
unique_placeholders = list(set(all_placeholders))
# Test counts - update based on actual count
assert len(subject_placeholders) == 3
assert len(body_placeholders) == 10 # Updated: actually 10 placeholders
assert len(unique_placeholders) == 9 # Total unique placeholders
# Test specific placeholders
expected_placeholders = {
"type", "position", "company", "name", "date",
"time", "duration", "interviewer", "location"
}
assert set(unique_placeholders) == expected_placeholders
# Test placeholder frequency
placeholder_frequency = {}
for placeholder in all_placeholders:
placeholder_frequency[placeholder] = placeholder_frequency.get(placeholder, 0) + 1
# Check which placeholders appear multiple times
repeated_placeholders = {k: v for k, v in placeholder_frequency.items() if v > 1}
assert "company" in repeated_placeholders
assert repeated_placeholders["company"] == 3 # Appears in subject and twice in body
class TestEmailSenderServiceUnit:
"""Unit tests for EmailSenderService """
def test_service_initialization(self):
"""Test service can be initialized."""
service = EmailSenderService()
assert service is not None
@pytest.mark.asyncio
async def test_get_email_sender_with_doc(self):
"""Test getting email senders when document exists."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.email_senders = ["test@example.com", "admin@example.com"]
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.get_email_sender("tenant_123")
assert result == ["test@example.com", "admin@example.com"]
@pytest.mark.asyncio
async def test_get_email_sender_no_doc(self):
"""Test getting email senders when document doesn't exist."""
service = EmailSenderService()
# Mock EmailSenderDoc.find_one returning None
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=None):
result = await service.get_email_sender("tenant_123")
assert result == []
@pytest.mark.asyncio
async def test_set_email_sender_existing_doc(self):
"""Test setting email senders for existing document."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.email_senders = ["new@example.com"]
mock_doc.set = AsyncMock()
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.set_email_sender("tenant_123", ["new@example.com"])
mock_doc.set.assert_called_once_with({"email_senders": ["new@example.com"]})
assert result["success"] is True
assert result["email_senders"] == ["new@example.com"]
@pytest.mark.asyncio
async def test_set_email_sender_new_doc(self):
"""Test setting email senders for new document."""
service = EmailSenderService()
# Mock document that will be returned by the constructor
mock_doc = Mock()
mock_doc.email_senders = ["new@example.com"]
mock_doc.create = AsyncMock()
# Create a simple async mock function
async def mock_find_one(query):
return None # No existing document
# Mock the entire EmailSenderDoc class
with patch('backend.services.email_sender_service.EmailSenderDoc') as mock_doc_class:
# Set up the find_one method
mock_doc_class.find_one = mock_find_one
# Set up the constructor
mock_doc_class.return_value = mock_doc
result = await service.set_email_sender("tenant_123", ["new@example.com"])
# Verify the constructor was called
mock_doc_class.assert_called_once_with(tenant_id="tenant_123", email_senders=["new@example.com"])
mock_doc.create.assert_called_once()
assert result["success"] is True
@pytest.mark.asyncio
async def test_add_email_senders_no_senders(self):
"""Test adding email senders with no senders provided."""
service = EmailSenderService()
result = await service.add_email_senders("tenant_123", None)
assert result["success"] is False
assert "No sender provided" in result["msg"]
@pytest.mark.asyncio
async def test_add_email_senders_not_list(self):
"""Test adding email senders with non-list input."""
service = EmailSenderService()
result = await service.add_email_senders("tenant_123", "not_a_list")
assert result["success"] is False
assert "No sender provided" in result["msg"]
@pytest.mark.asyncio
async def test_add_email_senders_existing_doc(self):
"""Test adding email senders to existing document."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.email_senders = ["existing@example.com"]
mock_doc.set = AsyncMock()
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.add_email_senders("tenant_123", ["new@example.com"])
# Verify the set was called with the correct email_senders (order doesn't matter)
mock_doc.set.assert_called_once()
call_args = mock_doc.set.call_args[0][0]
assert set(call_args["email_senders"]) == {"existing@example.com", "new@example.com"}
assert result["success"] is True
assert "new@example.com" in result["email_senders"]
@pytest.mark.asyncio
async def test_add_email_senders_all_exist(self):
"""Test adding email senders when all already exist."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.email_senders = ["existing@example.com"]
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.add_email_senders("tenant_123", ["existing@example.com"])
assert result["success"] is False
assert "All senders already exist" in result["msg"]
@pytest.mark.asyncio
async def test_add_email_senders_empty_list(self):
"""Test adding empty list of email senders."""
service = EmailSenderService()
result = await service.add_email_senders("tenant_123", [])
assert result["success"] is False
assert "No sender provided" in result["msg"]
@pytest.mark.asyncio
async def test_add_email_senders_new_doc_simple(self):
"""Test adding email senders when document doesn't exist with simple mocking."""
service = EmailSenderService()
# Mock document that will be returned by the constructor
mock_doc = Mock()
mock_doc.email_senders = ["new@example.com"]
mock_doc.create = AsyncMock()
# Create a simple async mock function
async def mock_find_one(query):
return None # No existing document
# Mock the entire EmailSenderDoc class
with patch('backend.services.email_sender_service.EmailSenderDoc') as mock_doc_class:
# Set up the find_one method
mock_doc_class.find_one = mock_find_one
# Set up the constructor
mock_doc_class.return_value = mock_doc
result = await service.add_email_senders("tenant_123", ["new@example.com"])
# Verify the constructor was called
mock_doc_class.assert_called_once_with(tenant_id="tenant_123", email_senders=["new@example.com"])
mock_doc.create.assert_called_once()
assert result["success"] is True
@pytest.mark.asyncio
async def test_remove_email_senders_no_doc(self):
"""Test removing email senders when document doesn't exist."""
service = EmailSenderService()
# Mock EmailSenderDoc.find_one returning None
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=None):
result = await service.remove_email_senders("tenant_123", ["test@example.com"])
assert result["success"] is False
assert "No sender found" in result["msg"]
@pytest.mark.asyncio
async def test_remove_email_senders_no_senders(self):
"""Test removing email senders when document has no senders."""
service = EmailSenderService()
# Mock document with no senders
mock_doc = Mock()
mock_doc.email_senders = []
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.remove_email_senders("tenant_123", ["test@example.com"])
assert result["success"] is False
assert "No sender found" in result["msg"]
@pytest.mark.asyncio
async def test_remove_email_senders_success(self):
"""Test successful email sender removal."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.email_senders = ["test@example.com", "admin@example.com"]
mock_doc.set = AsyncMock()
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.remove_email_senders("tenant_123", ["test@example.com"])
mock_doc.set.assert_called_once_with({"email_senders": ["admin@example.com"]})
assert result["success"] is True
assert result["remaining"] == ["admin@example.com"]
@pytest.mark.asyncio
async def test_remove_email_senders_no_match(self):
"""Test removing email senders when none match."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.email_senders = ["admin@example.com"]
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.remove_email_senders("tenant_123", ["test@example.com"])
assert result["success"] is False
assert "No sender matched for removal" in result["msg"]
@pytest.mark.asyncio
async def test_clear_email_senders_success(self):
"""Test successful email sender clearing."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.set = AsyncMock()
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.clear_email_senders("tenant_123")
mock_doc.set.assert_called_once_with({"email_senders": []})
assert result["success"] is True
@pytest.mark.asyncio
async def test_clear_email_senders_no_doc(self):
"""Test clearing email senders when document doesn't exist."""
service = EmailSenderService()
# Mock EmailSenderDoc.find_one returning None
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=None):
result = await service.clear_email_senders("tenant_123")
assert result["success"] is False
assert "No sender config found" in result["msg"]
@pytest.mark.asyncio
async def test_delete_email_sender_success(self):
"""Test successful email sender deletion."""
service = EmailSenderService()
# Mock document
mock_doc = Mock()
mock_doc.delete = AsyncMock()
# Mock EmailSenderDoc.find_one
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=mock_doc):
result = await service.delete_email_sender("tenant_123")
mock_doc.delete.assert_called_once()
assert result["success"] is True
@pytest.mark.asyncio
async def test_delete_email_sender_no_doc(self):
"""Test deleting email sender when document doesn't exist."""
service = EmailSenderService()
# Mock EmailSenderDoc.find_one returning None
with patch('backend.services.email_sender_service.EmailSenderDoc.find_one', new_callable=AsyncMock, return_value=None):
result = await service.delete_email_sender("tenant_123")
assert result["success"] is False
assert "No sender config found" in result["msg"]