add unit test for get_ticket_id_from_slug and alt queue processing for get_email

This commit is contained in:
Marc
2025-07-07 21:17:29 +00:00
parent 50fd6a07e8
commit a056e4d0a8
3 changed files with 136 additions and 3 deletions

View File

@ -1102,7 +1102,7 @@ def extract_email_metadata(
other_queues = Queue.objects.exclude(id=queue.id).filter(
email_box_type__isnull=False
)
for other_queue in other_queues:
ticket_id = get_ticket_id_from_subject_slug(
other_queue.slug, subject, logger
@ -1115,11 +1115,13 @@ def extract_email_metadata(
)
queue = other_queue
break
# If no ticket ID was found in any queue, revert to the original queue for new ticket
if ticket_id is None:
queue = original_queue
logger.info(f"No existing ticket found, reverting to original queue {queue.slug}")
logger.info(
f"No existing ticket found, reverting to original queue {queue.slug}"
)
files = []
# first message in thread, we save full body to avoid losing forwards and things like that

View File

@ -553,6 +553,97 @@ class GetEmailCommonTests(TestCase):
"Email attachment file not found in ticket attachment for empty body.",
)
@patch("helpdesk.email.get_ticket_id_from_subject_slug")
@patch("helpdesk.email.create_object_from_email_message")
def test_ticket_id_lookup_across_queues(
self, mock_create_object, mock_get_ticket_id
):
"""
Tests the logic for finding a ticket ID:
1. Not found in the current queue.
2. Found in another queue, leading to ticket association with that queue.
3. Not found in any queue, leading to a new ticket in the original queue.
"""
# Create additional queues for testing
queue_other1 = Queue.objects.create(
title="Other Queue 1", slug="other1", email_box_type="local"
)
queue_other2 = Queue.objects.create(
title="Other Queue 2", slug="other2", email_box_type="local"
)
# Scenario 1: Ticket ID not found in current queue, then found in another queue
mock_get_ticket_id.side_effect = [
None, # Not found in self.queue_public
123, # Found in queue_other1
]
# We need to mock Queue.objects.exclude().filter() to return our specific other queues
with patch("helpdesk.models.Queue.objects") as mock_queue_objects:
mock_queue_objects.exclude.return_value.filter.return_value = [
queue_other1,
queue_other2,
]
message, _, _ = utils.generate_email_with_subject(
subject="[other1-123] Test Subject"
)
ticket = extract_email_metadata(
message.as_string(), self.queue_public, self.logger
) # noqa
# Assert get_ticket_id_from_subject_slug was called for current and then other1
mock_get_ticket_id.assert_has_calls(
[
mock.call(self.queue_public.slug, mock.ANY, self.logger),
mock.call(queue_other1.slug, mock.ANY, self.logger),
]
)
# Assert that create_object_from_email_message was called with the ticket ID and the other queue
mock_create_object.assert_called_once()
args, kwargs = mock_create_object.call_args
self.assertEqual(args[1], 123) # ticket_id
self.assertEqual(args[2]["queue"], queue_other1) # payload
mock_get_ticket_id.reset_mock()
mock_create_object.reset_mock()
# Scenario 2: Ticket ID not found in any queue, leading to a new ticket in the original queue
mock_get_ticket_id.side_effect = [
None, # Not found in self.queue_public
None, # Not found in queue_other1
None, # Not found in queue_other2
]
with patch("helpdesk.models.Queue.objects") as mock_queue_objects:
mock_queue_objects.exclude.return_value.filter.return_value = [
queue_other1,
queue_other2,
]
message, _, _ = utils.generate_email_with_subject(
subject="[nonexistent-456] New Ticket Subject"
)
ticket = extract_email_metadata( # noqa
message.as_string(), self.queue_public, self.logger
)
# Assert get_ticket_id_from_subject_slug was called for all queues
mock_get_ticket_id.assert_has_calls(
[
mock.call(self.queue_public.slug, mock.ANY, self.logger),
mock.call(queue_other1.slug, mock.ANY, self.logger),
mock.call(queue_other2.slug, mock.ANY, self.logger),
]
)
# Assert that create_object_from_email_message was called with None ticket_id and the original queue
mock_create_object.assert_called_once()
args, kwargs = mock_create_object.call_args
self.assertIsNone(args[1])
self.assertEqual(args[2]["queue"], self.queue_public)
class EmailTaskTests(TestCase):
def setUp(self):

View File

@ -369,3 +369,43 @@ def generate_html_email(
msg, locale=locale, use_short_email=use_short_email
)
return msg, from_meta, to_meta
def generate_email_with_subject(
subject: str,
locale: str = "en_US",
use_short_email: bool = False,
body: str = None,
html_body: str = None,
) -> typing.Tuple[Message, typing.Tuple[str, str], typing.Tuple[str, str]]:
"""
Generates an email with a specified subject, and optional plain and HTML bodies.
:param subject: The desired subject for the email.
:param locale: Change this to generate locale-specific "real names" and body content.
:param use_short_email: Produces a "To" or "From" that is only the email address if True.
:param body: Optional plain text body for the email. If None, a fake text body is generated.
:param html_body: Optional HTML body for the email. If None and a plain body is used, a fake HTML body is generated.
"""
from_meta = generate_email_address(locale, use_short_email=use_short_email)
to_meta = generate_email_address(locale, use_short_email=use_short_email)
if body is None and html_body is None:
body = get_fake("text", locale=locale, min_length=1024)
html_body = get_fake_html(locale=locale, wrap_in_body_tag=True)
msg = MIMEMultipart("alternative")
msg.attach(MIMEText(body, "plain"))
msg.attach(MIMEText(html_body, "html"))
elif body is not None and html_body is None:
msg = MIMEText(body, "plain")
elif body is None and html_body is not None:
msg = MIMEText(html_body, "html")
else: # Both body and html_body are provided
msg = MIMEMultipart("alternative")
msg.attach(MIMEText(body, "plain"))
msg.attach(MIMEText(html_body, "html"))
msg["Subject"] = subject
msg["From"] = from_meta[0]
msg["To"] = to_meta[0]
return msg, from_meta, to_meta