Add tests for EmailTemplate and NotificationLog models
Introduced comprehensive unit tests for EmailTemplate and NotificationLog, including creation, field validation, and custom methods. Added relevant test fixtures to support these models and expanded `conftest.py` for reusability. Validates functionality and maintains model integrity.
This commit is contained in:
@@ -5,7 +5,8 @@ from datetime import datetime, timezone
|
||||
import pytest
|
||||
|
||||
from app.models import GiftItem, GiftStatus, GiftPriority, RSVP, RSVPStatus, EventMedia, MediaType, MediaPurpose, \
|
||||
EventTheme, Guest, GuestStatus, ActivityType, ActivityLog
|
||||
EventTheme, Guest, GuestStatus, ActivityType, ActivityLog, EmailTemplate, TemplateType, NotificationLog, \
|
||||
NotificationType, NotificationStatus
|
||||
from app.models.user import User
|
||||
from app.utils.test_utils import setup_test_db, teardown_test_db
|
||||
|
||||
@@ -193,3 +194,48 @@ def activity_log_fixture(db_session, mock_user, guest_fixture):
|
||||
db_session.add(activity_log_entry)
|
||||
db_session.commit()
|
||||
return activity_log_entry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def email_template_fixture(db_session, mock_user):
|
||||
"""
|
||||
Fixture to create and return a default EmailTemplate instance.
|
||||
"""
|
||||
email_template = EmailTemplate(
|
||||
id=uuid.uuid4(),
|
||||
name="Invitation Template",
|
||||
description="A template for event invitations.",
|
||||
template_type=TemplateType.INVITATION,
|
||||
subject="You're invited to {{event_name}}!",
|
||||
html_content="<h1>Welcome to {{event_name}}</h1><p>We look forward to seeing you!</p>",
|
||||
text_content="Welcome to {{event_name}}. We look forward to seeing you!",
|
||||
variables={"event_name": "Birthday Party"},
|
||||
event_id=None, # Global template
|
||||
created_by=mock_user.id,
|
||||
is_active=True,
|
||||
is_system=False,
|
||||
)
|
||||
db_session.add(email_template)
|
||||
db_session.commit()
|
||||
return email_template
|
||||
|
||||
@pytest.fixture
|
||||
def notification_log_fixture(db_session, email_template_fixture, guest_fixture):
|
||||
"""
|
||||
Fixture to create and return a default NotificationLog entry.
|
||||
"""
|
||||
notification_log = NotificationLog(
|
||||
id=uuid.uuid4(),
|
||||
notification_type=NotificationType.EMAIL,
|
||||
status=NotificationStatus.QUEUED,
|
||||
subject="You're invited!",
|
||||
content_preview="Join us for an unforgettable event.",
|
||||
template_id=email_template_fixture.id,
|
||||
event_id=guest_fixture.event_id,
|
||||
guest_id=guest_fixture.id,
|
||||
recipient="example@example.com",
|
||||
notification_metadata={"extra_info": "Email sent via SendGrid"},
|
||||
)
|
||||
db_session.add(notification_log)
|
||||
db_session.commit()
|
||||
return notification_log
|
||||
120
backend/tests/models/test_email_template.py
Normal file
120
backend/tests/models/test_email_template.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# tests/models/test_email_template.py
|
||||
import uuid
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
from app.models.email_template import EmailTemplate, TemplateType
|
||||
|
||||
|
||||
def test_create_email_template(db_session, mock_user):
|
||||
# Arrange
|
||||
email_template = EmailTemplate(
|
||||
id=uuid.uuid4(),
|
||||
name="Reminder Template",
|
||||
description="A template for sending reminders.",
|
||||
template_type=TemplateType.REMINDER,
|
||||
subject="Reminder: {{event_name}} is happening soon!",
|
||||
html_content="<h1>Reminder: {{event_name}}</h1><p>Don't miss it!</p>",
|
||||
text_content="Reminder: {{event_name}}. Don't miss it!",
|
||||
variables={"event_name": "Birthday Party"},
|
||||
event_id=None, # Global template
|
||||
created_by=mock_user.id,
|
||||
is_active=True,
|
||||
is_system=False,
|
||||
)
|
||||
db_session.add(email_template)
|
||||
|
||||
# Act
|
||||
db_session.commit()
|
||||
created_template = db_session.query(EmailTemplate).filter_by(id=email_template.id).first()
|
||||
|
||||
# Assert
|
||||
assert created_template is not None
|
||||
assert created_template.name == "Reminder Template"
|
||||
assert created_template.description == "A template for sending reminders."
|
||||
assert created_template.template_type == TemplateType.REMINDER
|
||||
assert created_template.subject == "Reminder: {{event_name}} is happening soon!"
|
||||
assert created_template.html_content == "<h1>Reminder: {{event_name}}</h1><p>Don't miss it!</p>"
|
||||
assert created_template.text_content == "Reminder: {{event_name}}. Don't miss it!"
|
||||
assert created_template.variables == {"event_name": "Birthday Party"}
|
||||
assert created_template.created_by == mock_user.id
|
||||
assert created_template.is_active is True
|
||||
assert created_template.is_system is False
|
||||
|
||||
|
||||
def test_render_email_template(email_template_fixture):
|
||||
# Arrange
|
||||
context = {"event_name": "Emma's 1st Birthday"}
|
||||
|
||||
# Act
|
||||
rendered_subject, rendered_html, rendered_text = email_template_fixture.render(context)
|
||||
|
||||
# Assert
|
||||
assert rendered_subject == "You're invited to Emma's 1st Birthday!"
|
||||
assert rendered_html == "<h1>Welcome to Emma's 1st Birthday</h1><p>We look forward to seeing you!</p>"
|
||||
assert rendered_text == "Welcome to Emma's 1st Birthday. We look forward to seeing you!"
|
||||
|
||||
|
||||
def test_unique_event_template_name_constraint(db_session, email_template_fixture, mock_user):
|
||||
# Arrange: Ensure both templates share the same event_id
|
||||
event_id = uuid.uuid4()
|
||||
email_template_fixture.event_id = event_id # Set the event_id for the existing fixture
|
||||
db_session.commit()
|
||||
|
||||
# Attempt to create another template with the same name for the same event
|
||||
duplicate_template = EmailTemplate(
|
||||
id=uuid.uuid4(),
|
||||
name=email_template_fixture.name,
|
||||
description="Another template with the same name.",
|
||||
template_type=TemplateType.INVITATION,
|
||||
subject="Duplicate Subject",
|
||||
html_content="<p>Duplicate Content</p>",
|
||||
text_content="Duplicate Content",
|
||||
variables={},
|
||||
event_id=event_id, # Use the same event_id
|
||||
created_by=mock_user.id,
|
||||
is_active=True,
|
||||
is_system=False,
|
||||
)
|
||||
db_session.add(duplicate_template)
|
||||
|
||||
# Act & Assert
|
||||
try:
|
||||
db_session.commit()
|
||||
assert False, "Expected IntegrityError due to unique constraint on event-specific template names."
|
||||
except sqlalchemy.exc.IntegrityError as e:
|
||||
# Validate that the constraint error relates to `uq_event_template_name`
|
||||
assert "uq_event_template_name" in str(e.orig) or "email_templates.event_id, email_templates.name" in str(
|
||||
e.orig)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_template_is_active_field(email_template_fixture):
|
||||
# Assert
|
||||
assert email_template_fixture.is_active is True
|
||||
|
||||
# Deactivate the template
|
||||
email_template_fixture.is_active = False
|
||||
|
||||
# Assert
|
||||
assert email_template_fixture.is_active is False
|
||||
|
||||
|
||||
def test_template_is_system_field(email_template_fixture):
|
||||
# Assert
|
||||
assert email_template_fixture.is_system is False
|
||||
|
||||
# Promote to system template
|
||||
email_template_fixture.is_system = True
|
||||
|
||||
# Assert
|
||||
assert email_template_fixture.is_system is True
|
||||
|
||||
|
||||
def test_repr_method(email_template_fixture):
|
||||
# Act
|
||||
repr_output = repr(email_template_fixture)
|
||||
|
||||
# Assert
|
||||
assert repr_output == f"<EmailTemplate {email_template_fixture.name} ({email_template_fixture.template_type.value})>"
|
||||
105
backend/tests/test_notification_log.py
Normal file
105
backend/tests/test_notification_log.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# tests/models/test_notification_log.py
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from app.models.notification_log import NotificationLog, NotificationType, NotificationStatus
|
||||
|
||||
|
||||
def test_create_notification_log(db_session, email_template_fixture, guest_fixture):
|
||||
# Arrange
|
||||
notification_log = NotificationLog(
|
||||
id=uuid.uuid4(),
|
||||
notification_type=NotificationType.SMS,
|
||||
status=NotificationStatus.QUEUED,
|
||||
subject="Event Reminder",
|
||||
content_preview="Don't forget the event!",
|
||||
template_id=email_template_fixture.id,
|
||||
event_id=guest_fixture.event_id,
|
||||
guest_id=guest_fixture.id,
|
||||
recipient="+1234567890",
|
||||
notification_metadata={"provider": "Twilio", "priority": "High"},
|
||||
)
|
||||
db_session.add(notification_log)
|
||||
|
||||
# Act
|
||||
db_session.commit()
|
||||
created_log = db_session.query(NotificationLog).filter_by(id=notification_log.id).first()
|
||||
|
||||
# Assert
|
||||
assert created_log is not None
|
||||
assert created_log.notification_type == NotificationType.SMS
|
||||
assert created_log.status == NotificationStatus.QUEUED
|
||||
assert created_log.subject == "Event Reminder"
|
||||
assert created_log.content_preview == "Don't forget the event!"
|
||||
assert created_log.template_id == email_template_fixture.id
|
||||
assert created_log.event_id == guest_fixture.event_id
|
||||
assert created_log.guest_id == guest_fixture.id
|
||||
assert created_log.recipient == "+1234567890"
|
||||
assert created_log.notification_metadata == {"provider": "Twilio", "priority": "High"}
|
||||
|
||||
|
||||
def test_mark_sent(notification_log_fixture):
|
||||
# Act
|
||||
notification_log_fixture.mark_sent()
|
||||
|
||||
# Assert
|
||||
assert notification_log_fixture.status == NotificationStatus.SENT
|
||||
assert notification_log_fixture.sent_at is not None
|
||||
assert notification_log_fixture.sent_at < datetime.now(timezone.utc)
|
||||
|
||||
|
||||
def test_mark_delivered(notification_log_fixture):
|
||||
# Act
|
||||
notification_log_fixture.mark_delivered()
|
||||
|
||||
# Assert
|
||||
assert notification_log_fixture.status == NotificationStatus.DELIVERED
|
||||
assert notification_log_fixture.delivered_at is not None
|
||||
assert notification_log_fixture.delivered_at < datetime.now(timezone.utc)
|
||||
|
||||
|
||||
def test_mark_opened(notification_log_fixture):
|
||||
# Act
|
||||
notification_log_fixture.mark_opened()
|
||||
|
||||
# Assert
|
||||
assert notification_log_fixture.status == NotificationStatus.OPENED
|
||||
assert notification_log_fixture.opened_at is not None
|
||||
assert notification_log_fixture.opened_at < datetime.now(timezone.utc)
|
||||
|
||||
|
||||
def test_mark_failed(notification_log_fixture):
|
||||
# Act
|
||||
notification_log_fixture.mark_failed("Undeliverable address")
|
||||
|
||||
# Assert
|
||||
assert notification_log_fixture.status == NotificationStatus.FAILED
|
||||
assert notification_log_fixture.error_message == "Undeliverable address"
|
||||
assert notification_log_fixture.retry_count == 1
|
||||
|
||||
|
||||
def test_can_retry_property(notification_log_fixture):
|
||||
# Arrange
|
||||
notification_log_fixture.retry_count = 2
|
||||
notification_log_fixture.status = NotificationStatus.FAILED # Ensure initial FAILED status
|
||||
|
||||
# Act: Call mark_failed and inspect retry_count/state
|
||||
notification_log_fixture.mark_failed("Temporary issue")
|
||||
|
||||
# Assert: Still retryable since retry_count < 3
|
||||
assert notification_log_fixture.retry_count == 3 # Ensure retry_count incremented
|
||||
assert notification_log_fixture.status == NotificationStatus.FAILED # Ensure status is 'FAILED'
|
||||
assert notification_log_fixture.can_retry is False # Now retries are exhausted
|
||||
|
||||
# Reset retry count and revalidate
|
||||
notification_log_fixture.retry_count = 1
|
||||
can_retry = notification_log_fixture.can_retry
|
||||
assert can_retry is True # Should be retryable with retry_count = 1
|
||||
|
||||
|
||||
|
||||
def test_repr_method(notification_log_fixture):
|
||||
# Act
|
||||
repr_output = repr(notification_log_fixture)
|
||||
|
||||
# Assert
|
||||
assert repr_output == f"<NotificationLog {notification_log_fixture.notification_type.value} to {notification_log_fixture.recipient} status={notification_log_fixture.status.value}>"
|
||||
Reference in New Issue
Block a user