-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor!: [FC-0074] make receivers trigger tasks to implement retry …
…mechanism (#8)
- Loading branch information
1 parent
d5003eb
commit ee00ac2
Showing
14 changed files
with
635 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"""Celery tasks for sending data to Zapier or another webhook.""" | ||
|
||
import logging | ||
|
||
from celery import shared_task | ||
from requests import exceptions, post | ||
|
||
from openedx_events_2_zapier.utils import flatten_dict | ||
|
||
ZAPIER_REQUEST_TIMEOUT = 5 | ||
ZAPIER_RETRY_COUNTDOWN = 3 | ||
log = logging.getLogger(__name__) | ||
|
||
|
||
@shared_task( | ||
bind=True, | ||
autoretry_for=(exceptions.RequestException,), | ||
retry_backoff=True, | ||
retry_kwargs={"max_retries": ZAPIER_RETRY_COUNTDOWN}, | ||
) | ||
def send_data_to_zapier(self, zap_url, data): # pylint: disable=unused-argument | ||
""" | ||
Send data to Zapier using a webhook. | ||
Arguments: | ||
self: The task instance. | ||
zap_url: The URL of the Zapier webhook. | ||
data: The data to send to the webhook. | ||
""" | ||
flattened_data = flatten_dict(data) | ||
try: | ||
log.info("Sending data to Zapier: %s", flattened_data) | ||
post(zap_url, flattened_data, timeout=ZAPIER_REQUEST_TIMEOUT) | ||
except exceptions.RequestException as e: | ||
log.error("Error sending data to Zapier: %s", e) | ||
raise |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,10 @@ | ||
"""This file contains all test for the handlers.py file. | ||
"""This file contains all test for the handlers.py file.""" | ||
|
||
Classes: | ||
EventsToolingTest: Test events tooling. | ||
""" | ||
|
||
import datetime | ||
from datetime import datetime | ||
from unittest.mock import patch | ||
|
||
from django.test import TestCase | ||
from attr import asdict | ||
from django.test import TestCase, override_settings | ||
from opaque_keys.edx.keys import CourseKey | ||
from openedx_events.data import EventsMetadata | ||
from openedx_events.learning.data import ( | ||
|
@@ -28,6 +25,7 @@ | |
send_persistent_grade_course_data_to_webhook, | ||
send_user_data_to_webhook, | ||
) | ||
from openedx_events_2_zapier.utils import serialize_course_key | ||
|
||
|
||
class RegistrationCompletedReceiverTest(TestCase): | ||
|
@@ -54,33 +52,38 @@ def setUp(self): | |
minorversion=0, | ||
) | ||
|
||
@patch("openedx_events_2_zapier.handlers.requests") | ||
def test_receiver_called_after_event(self, request_mock): | ||
@override_settings(ZAPIER_REGISTRATION_WEBHOOK="https://webhook.site") | ||
@patch("openedx_events_2_zapier.handlers.send_data_to_zapier") | ||
def test_receiver_called_after_event(self, task_mock): | ||
""" | ||
Test that send_user_data_to_webhook is called the correct information after sending | ||
STUDENT_REGISTRATION_COMPLETED event. | ||
Expected Behavior: | ||
- The task is called with the correct URL and payload. | ||
""" | ||
expected_payload_subset = { | ||
"user_id": 39, | ||
"user_is_active": True, | ||
"user_pii_username": "test", | ||
"user_pii_email": "[email protected]", | ||
"user_pii_name": "Test Example", | ||
"event_metadata_event_type": self.metadata.event_type, | ||
"event_metadata_minorversion": self.metadata.minorversion, | ||
"event_metadata_source": self.metadata.source, | ||
"event_metadata_sourcehost": self.metadata.sourcehost, | ||
"event_metadata_sourcelib": list(self.metadata.sourcelib), | ||
expected_payload = { | ||
"user": asdict(self.user), | ||
"event_metadata": asdict(self.metadata), | ||
} | ||
STUDENT_REGISTRATION_COMPLETED.connect(send_user_data_to_webhook) | ||
|
||
STUDENT_REGISTRATION_COMPLETED.send_event( | ||
user=self.user, | ||
) | ||
|
||
task_mock.delay.assert_called_once() | ||
self.assertDictContainsSubset( | ||
expected_payload_subset, | ||
request_mock.post.call_args.args[1], | ||
expected_payload["user"], | ||
task_mock.delay.call_args[0][1]["user"], | ||
) | ||
self.assertEqual( | ||
task_mock.delay.call_args[0][1]["event_metadata"], | ||
{ | ||
**expected_payload["event_metadata"], | ||
"id": task_mock.delay.call_args[0][1]["event_metadata"]["id"], | ||
"time": task_mock.delay.call_args[0][1]["event_metadata"]["time"], | ||
}, | ||
) | ||
|
||
|
||
|
@@ -110,55 +113,54 @@ def setUp(self): | |
), | ||
mode="audit", | ||
is_active=True, | ||
creation_date=datetime.datetime(2021, 9, 21, 17, 40, 27), | ||
creation_date=datetime(2021, 9, 21, 17, 40, 27), | ||
) | ||
self.metadata = EventsMetadata( | ||
event_type="org.openedx.learning.course.enrollment.created.v1", | ||
minorversion=0, | ||
) | ||
|
||
@patch("openedx_events_2_zapier.handlers.requests") | ||
def test_receiver_called_after_event(self, request_mock): | ||
@override_settings(ZAPIER_ENROLLMENT_WEBHOOK="https://webhook.site") | ||
@patch("openedx_events_2_zapier.handlers.send_data_to_zapier") | ||
def test_receiver_called_after_event(self, task_mock): | ||
""" | ||
Test that send_user_data_to_webhook is called the correct information after sending | ||
COURSE_ENROLLMENT_CREATED event. | ||
Expected Behavior: | ||
- The task is called with the correct URL and payload. | ||
""" | ||
expected_payload_subset = { | ||
"enrollment_user_id": 42, | ||
"enrollment_user_is_active": True, | ||
"enrollment_user_pii_username": "test", | ||
"enrollment_user_pii_email": "[email protected]", | ||
"enrollment_user_pii_name": "Test Example", | ||
"enrollment_course_course_key": "course-v1:edX+100+2021", | ||
"enrollment_course_display_name": "Demonstration Course", | ||
"enrollment_course_start": None, | ||
"enrollment_course_end": None, | ||
"enrollment_mode": "audit", | ||
"enrollment_is_active": True, | ||
"enrollment_creation_date": datetime.datetime(2021, 9, 21, 17, 40, 27), | ||
"enrollment_created_by": None, | ||
"event_metadata_event_type": self.metadata.event_type, | ||
"event_metadata_minorversion": self.metadata.minorversion, | ||
"event_metadata_source": self.metadata.source, | ||
"event_metadata_sourcehost": self.metadata.sourcehost, | ||
"event_metadata_sourcelib": list(self.metadata.sourcelib), | ||
expected_payload = { | ||
"enrollment": asdict( | ||
self.enrollment, value_serializer=serialize_course_key | ||
), | ||
"event_metadata": asdict(self.metadata), | ||
} | ||
COURSE_ENROLLMENT_CREATED.connect(send_enrollment_data_to_webhook) | ||
|
||
COURSE_ENROLLMENT_CREATED.send_event( | ||
enrollment=self.enrollment, | ||
) | ||
|
||
self.assertDictContainsSubset( | ||
expected_payload_subset, | ||
request_mock.post.call_args.args[1], | ||
task_mock.delay.assert_called_once() | ||
self.assertEqual( | ||
expected_payload["enrollment"], | ||
task_mock.delay.call_args[0][1]["enrollment"], | ||
) | ||
self.assertEqual( | ||
task_mock.delay.call_args[0][1]["event_metadata"], | ||
{ | ||
**expected_payload["event_metadata"], | ||
"id": task_mock.delay.call_args[0][1]["event_metadata"]["id"], | ||
"time": task_mock.delay.call_args[0][1]["event_metadata"]["time"], | ||
}, | ||
) | ||
|
||
|
||
class PersistentGradeEventsTest(TestCase): | ||
""" | ||
Test that send_persistent_grade_course_data_to_webhook is called the correct information after sending | ||
COURSE_ENROLLMENT_CREATED event. | ||
PERSISTENT_GRADE_SUMMARY_CHANGED event. | ||
""" | ||
|
||
def setUp(self): | ||
|
@@ -172,39 +174,31 @@ def setUp(self): | |
course_key=CourseKey.from_string("course-v1:edX+100+2021"), | ||
display_name="Demonstration Course", | ||
), | ||
course_edited_timestamp=datetime.datetime(2021, 9, 21, 17, 40, 27), | ||
course_edited_timestamp=datetime(2021, 9, 21, 17, 40, 27), | ||
course_version="", | ||
grading_policy_hash="", | ||
percent_grade=80, | ||
letter_grade="Great", | ||
passed_timestamp=datetime.datetime(2021, 9, 21, 17, 40, 27), | ||
passed_timestamp=datetime(2021, 9, 21, 17, 40, 27), | ||
) | ||
self.metadata = EventsMetadata( | ||
event_type="org.openedx.learning.course.persistent_grade_summary.changed.v1", | ||
minorversion=0, | ||
) | ||
|
||
@patch("openedx_events_2_zapier.handlers.requests") | ||
def test_receiver_called_after_event(self, request_mock): | ||
@override_settings(ZAPIER_PERSISTENT_GRADE_COURSE_WEBHOOK="https://webhook.site") | ||
@patch("openedx_events_2_zapier.handlers.send_data_to_zapier") | ||
def test_receiver_called_after_event(self, task_mock): | ||
""" | ||
Test that send_persistent_grade_course_data_to_webhook is called the correct information after sending | ||
COURSE_ENROLLMENT_CREATED event. | ||
PERSISTENT_GRADE_SUMMARY_CHANGED event. | ||
Expected Behavior: | ||
- The task is called with the correct URL and payload. | ||
""" | ||
expected_payload_subset = { | ||
"grade_user_id": 42, | ||
"grade_course_course_key": "course-v1:edX+100+2021", | ||
"grade_course_display_name": "Demonstration Course", | ||
"grade_course_edited_timestamp": datetime.datetime(2021, 9, 21, 17, 40, 27), | ||
"grade_course_version": "", | ||
"grade_grading_policy_hash": "", | ||
"grade_percent_grade": 80, | ||
"grade_letter_grade": "Great", | ||
"grade_passed_timestamp": datetime.datetime(2021, 9, 21, 17, 40, 27), | ||
"event_metadata_event_type": self.metadata.event_type, | ||
"event_metadata_minorversion": self.metadata.minorversion, | ||
"event_metadata_source": self.metadata.source, | ||
"event_metadata_sourcehost": self.metadata.sourcehost, | ||
"event_metadata_sourcelib": list(self.metadata.sourcelib), | ||
expected_payload = { | ||
"grade": asdict(self.grade, value_serializer=serialize_course_key), | ||
"event_metadata": asdict(self.metadata), | ||
} | ||
PERSISTENT_GRADE_SUMMARY_CHANGED.connect( | ||
send_persistent_grade_course_data_to_webhook | ||
|
@@ -214,7 +208,16 @@ def test_receiver_called_after_event(self, request_mock): | |
grade=self.grade, | ||
) | ||
|
||
self.assertDictContainsSubset( | ||
expected_payload_subset, | ||
request_mock.post.call_args.args[1], | ||
task_mock.delay.assert_called_once() | ||
self.assertEqual( | ||
expected_payload["grade"], | ||
task_mock.delay.call_args[0][1]["grade"], | ||
) | ||
self.assertEqual( | ||
task_mock.delay.call_args[0][1]["event_metadata"], | ||
{ | ||
**expected_payload["event_metadata"], | ||
"id": task_mock.delay.call_args[0][1]["event_metadata"]["id"], | ||
"time": task_mock.delay.call_args[0][1]["event_metadata"]["time"], | ||
}, | ||
) |
Oops, something went wrong.