Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: changed message object to dictionary when sending ACE_MESSAGE_SENT signal #306

Merged
merged 5 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion edx_ace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .recipient import Recipient
from .recipient_resolver import RecipientResolver

__version__ = '1.11.1'
__version__ = '1.11.2'


__all__ = [
Expand Down
4 changes: 2 additions & 2 deletions edx_ace/delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from django.conf import settings

from edx_ace.errors import RecoverableChannelDeliveryError
from edx_ace.signals import ACE_MESSAGE_SENT
from edx_ace.utils.date import get_current_time
from edx_ace.utils.signals import send_ace_message_sent_signal

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -61,7 +61,7 @@ def deliver(channel, rendered_message, message):
message.report(f'{channel_type}_delivery_retried', num_seconds)
else:
message.report(f'{channel_type}_delivery_succeeded', True)
ACE_MESSAGE_SENT.send(sender=channel, message=message)
send_ace_message_sent_signal(channel, message)
return

delivery_expired_report = f'{channel_type}_delivery_expired'
Expand Down
10 changes: 5 additions & 5 deletions edx_ace/tests/test_delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ def setUp(self):
)
self.current_time = datetime.datetime.utcnow().replace(tzinfo=tzutc())

@patch('edx_ace.delivery.ACE_MESSAGE_SENT.send')
@patch('edx_ace.delivery.send_ace_message_sent_signal')
def test_happy_path(self, mock_ace_message_sent):
deliver(self.mock_channel, sentinel.rendered_email, self.message)
self.mock_channel.deliver.assert_called_once_with(self.message, sentinel.rendered_email)
# check if ACE_MESSAGE_SENT is raised
mock_ace_message_sent.assert_called_once_with(sender=self.mock_channel, message=self.message)
mock_ace_message_sent.assert_called_once_with(self.mock_channel, self.message)

def test_fatal_error(self):
self.mock_channel.deliver.side_effect = FatalChannelDeliveryError('testing')
with self.assertRaises(FatalChannelDeliveryError):
deliver(self.mock_channel, sentinel.rendered_email, self.message)

@patch('edx_ace.delivery.ACE_MESSAGE_SENT.send')
@patch('edx_ace.delivery.send_ace_message_sent_signal')
@patch('edx_ace.delivery.get_current_time')
def test_custom_message_expiration(self, mock_get_current_time, mock_ace_message_sent):
self.message.expiration_time = self.current_time - datetime.timedelta(seconds=10)
Expand Down Expand Up @@ -106,7 +106,7 @@ def test_multiple_retries(self, mock_get_current_time, mock_time):
assert mock_time.sleep.call_args_list == [call(1), call(1)]
assert self.mock_channel.deliver.call_count == 3

@patch('edx_ace.delivery.ACE_MESSAGE_SENT.send')
@patch('edx_ace.delivery.send_ace_message_sent_signal')
def test_message_sent_signal_for_push_channel(self, mock_ace_message_sent):
"""
Test that ACE_MESSAGE_SENT signal is sent when a message is delivered to a push channel.
Expand All @@ -117,4 +117,4 @@ def test_message_sent_signal_for_push_channel(self, mock_ace_message_sent):
)
deliver(mock_push_channel, sentinel.rendered_email, self.message)
# check if ACE_MESSAGE_SENT is raised
mock_ace_message_sent.assert_called_once_with(sender=mock_push_channel, message=self.message)
mock_ace_message_sent.assert_called_once_with(mock_push_channel, self.message)
47 changes: 47 additions & 0 deletions edx_ace/tests/utils/test_signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
Tests for the utils/signals module.
"""
from django.test import TestCase

from edx_ace.utils.signals import make_serializable_object


class TestMakeSerializableObject(TestCase):
def test_primitive_types(self):
self.assertEqual(make_serializable_object(42), 42)
self.assertEqual(make_serializable_object(3.14), 3.14)
self.assertEqual(make_serializable_object("string"), "string")
self.assertEqual(make_serializable_object(True), True)
self.assertEqual(make_serializable_object(None), None)

def test_dict(self):
input_dict = {
"int": 1,
"float": 2.0,
"str": "test",
"bool": False,
"none": None,
"list": [1, 2, 3],
"nested_dict": {"key": "value"}
}
self.assertEqual(make_serializable_object(input_dict), input_dict)

def test_list(self):
input_list = [1, 2.0, "test", False, None, [1, 2, 3], {"key": "value"}]
self.assertEqual(make_serializable_object(input_list), input_list)

def test_non_serializable(self):
class NonSerializable:
pass

obj = NonSerializable()
self.assertEqual(make_serializable_object(obj), str(obj))

def test_non_serializable_list(self):
class NonSerializable:
pass

obj = NonSerializable()
obj2 = NonSerializable()
obj_list = [obj, obj2]
self.assertEqual(make_serializable_object(obj_list), [str(obj), str(obj2)])
46 changes: 46 additions & 0 deletions edx_ace/utils/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
Utils for signals.
"""
from edx_ace.signals import ACE_MESSAGE_SENT


def make_serializable_object(obj):
"""
Takes a dictionary/list and returns a dictionary/list with all the values converted
to JSON serializable objects.
"""
try:
if isinstance(obj, (int, float, str, bool)) or obj is None:
return obj
elif isinstance(obj, dict):
return {key: make_serializable_object(value) for key, value in obj.items()}
elif isinstance(obj, list):
return [make_serializable_object(element) for element in obj]
except Exception: # pylint: disable=broad-except
pass

Check warning on line 20 in edx_ace/utils/signals.py

View check run for this annotation

Codecov / codecov/patch

edx_ace/utils/signals.py#L19-L20

Added lines #L19 - L20 were not covered by tests
return str(obj)


def send_ace_message_sent_signal(channel, message):
"""
Creates dictionary from message, makes it JSON serializable and
sends the ACE_MESSAGE_SENT signal.
"""
try:
channel_name = channel.__class__.__name__
except AttributeError:
channel_name = 'Other'

Check warning on line 32 in edx_ace/utils/signals.py

View check run for this annotation

Codecov / codecov/patch

edx_ace/utils/signals.py#L31-L32

Added lines #L31 - L32 were not covered by tests
data = {
'name': message.name,
'app_label': message.app_label,
'recipient': {
'email': getattr(message.recipient, 'email_address', ''),
'user_id': getattr(message.recipient, 'lms_user_id', ''),
},
'channel': channel_name,
'context': message.context,
'options': message.options,
'uuid': str(message.uuid),
'send_uuid': str(message.send_uuid),
}
ACE_MESSAGE_SENT.send(sender=channel, message=make_serializable_object(data))
Loading