Skip to content

Commit

Permalink
[#2681] Add tests for InstructorConfirmedForWorkshop (complex email a…
Browse files Browse the repository at this point in the history
…ction)
  • Loading branch information
pbanaszkiewicz committed Aug 5, 2024
1 parent c71ea5d commit a16ce18
Show file tree
Hide file tree
Showing 6 changed files with 948 additions and 5 deletions.
2 changes: 1 addition & 1 deletion amy/emails/actions/instructor_confirmed_for_workshop.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def instructor_confirmed_for_workshop_strategy(task: Task) -> StrategyEnum:
person_email_exists=person_email_exists,
)

email_should_exist = instructor_role and person_email_exists
email_should_exist = task.pk and instructor_role and person_email_exists
logger.debug(f"{email_should_exist=}")

ct = ContentType.objects.get_for_model(task.person) # type: ignore
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
from datetime import UTC, date, datetime, timedelta
from unittest.mock import MagicMock, call, patch

from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse

from emails.actions.instructor_confirmed_for_workshop import (
instructor_confirmed_for_workshop_cancel_receiver,
instructor_confirmed_for_workshop_strategy,
run_instructor_confirmed_for_workshop_strategy,
)
from emails.models import EmailTemplate, ScheduledEmail, ScheduledEmailStatus
from emails.signals import (
INSTRUCTOR_CONFIRMED_FOR_WORKSHOP_SIGNAL_NAME,
instructor_confirmed_for_workshop_cancel_signal,
)
from workshops.models import Event, Organization, Person, Role, Task
from workshops.tests.base import TestBase


class TestInstructorBadgeAwardedCancelReceiver(TestCase):
def setUp(self) -> None:
host = Organization.objects.create(domain="test.com", fullname="Test")
self.event = Event.objects.create(
slug="test-event", host=host, start=date(2024, 8, 5), end=date(2024, 8, 5)
)
self.person = Person.objects.create(email="[email protected]")
instructor = Role.objects.create(name="instructor")
self.task = Task.objects.create(
role=instructor, person=self.person, event=self.event
)

def setUpEmailTemplate(self) -> EmailTemplate:
return EmailTemplate.objects.create(
name="Test Email Template",
signal=INSTRUCTOR_CONFIRMED_FOR_WORKSHOP_SIGNAL_NAME,
from_header="[email protected]",
cc_header=["[email protected]"],
bcc_header=[],
subject="Greetings {{ name }}",
body="Hello, {{ name }}! Nice to meet **you**.",
)

@patch("emails.actions.base_action.logger")
def test_disabled_when_no_feature_flag(self, mock_logger) -> None:
# Arrange
request = RequestFactory().get("/")
with self.settings(FLAGS={"EMAIL_MODULE": [("boolean", False)]}):
# Act
instructor_confirmed_for_workshop_cancel_receiver(None, request=request)
# Assert
mock_logger.debug.assert_called_once_with(
"EMAIL_MODULE feature flag not set, skipping "
"instructor_confirmed_for_workshop_cancel"
)

def test_receiver_connected_to_signal(self) -> None:
# Arrange
original_receivers = instructor_confirmed_for_workshop_cancel_signal.receivers[
:
]

# Act
# attempt to connect the receiver
instructor_confirmed_for_workshop_cancel_signal.connect(
instructor_confirmed_for_workshop_cancel_receiver
)
new_receivers = instructor_confirmed_for_workshop_cancel_signal.receivers[:]

# Assert
# the same receiver list means this receiver has already been connected
self.assertEqual(original_receivers, new_receivers)

@override_settings(FLAGS={"EMAIL_MODULE": [("boolean", True)]})
def test_action_triggered(self) -> None:
# Arrange
request = RequestFactory().get("/")

template = self.setUpEmailTemplate()
scheduled_email = ScheduledEmail.objects.create(
template=template,
scheduled_at=datetime.now(UTC),
to_header=[],
cc_header=[],
bcc_header=[],
state=ScheduledEmailStatus.SCHEDULED,
generic_relation=self.person,
)

# Act
with patch(
"emails.actions.base_action.messages_action_cancelled"
) as mock_messages_action_cancelled:
instructor_confirmed_for_workshop_cancel_signal.send(
sender=self.task,
request=request,
task=self.task,
person_id=self.person.pk,
event_id=self.event.pk,
instructor_recruitment_id=None,
instructor_recruitment_signup_id=None,
)

# Assert
scheduled_email = ScheduledEmail.objects.get(template=template)
mock_messages_action_cancelled.assert_called_once_with(
request,
INSTRUCTOR_CONFIRMED_FOR_WORKSHOP_SIGNAL_NAME,
scheduled_email,
)

@override_settings(FLAGS={"EMAIL_MODULE": [("boolean", True)]})
@patch("emails.actions.base_action.messages_action_cancelled")
def test_email_cancelled(
self,
mock_messages_action_cancelled: MagicMock,
) -> None:
# Arrange
request = RequestFactory().get("/")
template = self.setUpEmailTemplate()
scheduled_email = ScheduledEmail.objects.create(
template=template,
scheduled_at=datetime.now(UTC),
to_header=[],
cc_header=[],
bcc_header=[],
state=ScheduledEmailStatus.SCHEDULED,
generic_relation=self.person,
)

# Act
with patch(
"emails.actions.base_action.EmailController.cancel_email"
) as mock_cancel_email:
instructor_confirmed_for_workshop_cancel_signal.send(
sender=self.task,
request=request,
task=self.task,
person_id=self.person.pk,
event_id=self.event.pk,
instructor_recruitment_id=None,
instructor_recruitment_signup_id=None,
)

# Assert
mock_cancel_email.assert_called_once_with(
scheduled_email=scheduled_email,
author=None,
)

@override_settings(FLAGS={"EMAIL_MODULE": [("boolean", True)]})
@patch("emails.actions.base_action.messages_action_cancelled")
def test_multiple_emails_cancelled(
self,
mock_messages_action_cancelled: MagicMock,
) -> None:
# Arrange
request = RequestFactory().get("/")
template = self.setUpEmailTemplate()
scheduled_email1 = ScheduledEmail.objects.create(
template=template,
scheduled_at=datetime.now(UTC),
to_header=[],
cc_header=[],
bcc_header=[],
state=ScheduledEmailStatus.SCHEDULED,
generic_relation=self.person,
)
scheduled_email2 = ScheduledEmail.objects.create(
template=template,
scheduled_at=datetime.now(UTC),
to_header=[],
cc_header=[],
bcc_header=[],
state=ScheduledEmailStatus.SCHEDULED,
generic_relation=self.person,
)

# Act
with patch(
"emails.actions.base_action.EmailController.cancel_email"
) as mock_cancel_email:
instructor_confirmed_for_workshop_cancel_signal.send(
sender=self.task,
request=request,
task=self.task,
person_id=self.person.pk,
event_id=self.event.pk,
instructor_recruitment_id=None,
instructor_recruitment_signup_id=None,
)

# Assert
mock_cancel_email.assert_has_calls(
[
call(
scheduled_email=scheduled_email1,
author=None,
),
call(
scheduled_email=scheduled_email2,
author=None,
),
]
)


class TestInstructorBadgeAwardedCancelIntegration(TestBase):
@override_settings(FLAGS={"EMAIL_MODULE": [("boolean", True)]})
def test_integration(self) -> None:
# Arrange
self._setUpRoles()
self._setUpTags()
self._setUpUsersAndLogin()

template = EmailTemplate.objects.create(
name="Test Email Template",
signal=INSTRUCTOR_CONFIRMED_FOR_WORKSHOP_SIGNAL_NAME,
from_header="[email protected]",
cc_header=["[email protected]"],
bcc_header=[],
subject="Greetings",
body="Hello! Nice to meet **you**.",
)

ttt_organization = Organization.objects.create(
domain="carpentries.org", fullname="Instructor Training"
)
host_organization = Organization.objects.create(
domain="example.com", fullname="Example"
)
event = Event.objects.create(
slug="2024-08-05-test-event",
host=host_organization,
administrator=ttt_organization,
start=date.today() + timedelta(days=30),
)

instructor = Person.objects.create(
personal="Kelsi",
middle="",
family="Purdy",
username="purdy_kelsi",
email="[email protected]",
secondary_email="[email protected]",
gender="F",
airport=self.airport_0_0,
github="",
twitter="",
url="http://kelsipurdy.com/",
affiliation="University of Arizona",
occupation="TA at Biology Department",
orcid="0000-0000-0000",
is_active=True,
)
instructor_role = Role.objects.get(name="instructor")
task = Task.objects.create(event=event, person=instructor, role=instructor_role)

request = RequestFactory().get("/")
with patch(
"emails.actions.base_action.messages_action_scheduled"
) as mock_action_scheduled:
run_instructor_confirmed_for_workshop_strategy(
instructor_confirmed_for_workshop_strategy(task),
request,
task=task,
person_id=task.person.pk,
event_id=task.event.pk,
instructor_recruitment_id=None,
instructor_recruitment_signup_id=None,
)
scheduled_email = ScheduledEmail.objects.get(template=template)

url = reverse("task_delete", args=[task.pk])

# Act
rv = self.client.post(url)

# Arrange
mock_action_scheduled.assert_called_once()
self.assertEqual(rv.status_code, 302)
scheduled_email.refresh_from_db()
self.assertEqual(scheduled_email.state, ScheduledEmailStatus.CANCELLED)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from django.urls import reverse

from communityroles.models import CommunityRole, CommunityRoleConfig
from emails.actions import instructor_confirmed_for_workshop_receiver
from emails.actions.instructor_confirmed_for_workshop import (
instructor_confirmed_for_workshop_receiver,
)
from emails.models import EmailTemplate, ScheduledEmail
from emails.schemas import ContextModel, ToHeaderModel
from emails.signals import instructor_confirmed_for_workshop_signal
Expand Down
Loading

0 comments on commit a16ce18

Please sign in to comment.