diff --git a/.circleci/config.yml b/.circleci/config.yml index 04b98d5..c20ce16 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,13 +14,9 @@ workflows: only: /v?[0-9]+(\.[0-9]+)*/ matrix: parameters: - python_version: ["3.5", "3.8"] - debian_version: ["stretch", "buster"] - exclude: - - python_version: "3.8" - debian_version: "stretch" - - python_version: "3.5" - debian_version: "buster" + python_version: ["3.8"] + debian_version: ["buster"] + - pypi: requires: - test @@ -39,7 +35,6 @@ jobs: type: string debian_version: type: string - default: stretch docker: # specify the version you desire here # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 14f0985..dda5427 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,8 @@ Change Log Unreleased ---------- * **BREAKING CHANGE**: add support for lilac and therefore changed backends defaults. +* **BREAKING CHANGE**: add support for openedx-events. Only works for Lilac with PRs backport 28266 and 18640 + and >= Maple. [1.0.0] - 2021-08-17 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/eox_hooks/actions.py b/eox_hooks/actions.py index ca1b0fd..85d1833 100644 --- a/eox_hooks/actions.py +++ b/eox_hooks/actions.py @@ -8,13 +8,15 @@ from opaque_keys.edx.keys import CourseKey from eox_hooks.edxapp_wrapper.courses import get_item_not_found_exception, get_load_single_xblock +from eox_hooks.edxapp_wrapper.models import get_certificate_model from eox_hooks.serializers import CertificateSerializer, CourseSerializer, UserSerializer from eox_hooks.tasks import create_enrollments_for_program from eox_hooks.utils import _get_course, flatten_dict, get_trigger_settings +COURSE_PASSING_GRADE = 1 ItemNotFoundError = get_item_not_found_exception() load_single_xblock = get_load_single_xblock() -COURSE_PASSING_GRADE = 1 +GeneratedCertificate = get_certificate_model() log = logging.getLogger(__name__) @@ -61,6 +63,9 @@ def post_to_webhook_url(**kwargs): if trigger_settings.get("send_certificate_data", False): certificate = kwargs.get("certificate", {}) + certificate = GeneratedCertificate.objects.get( + user__id=certificate.user.id, course_id=certificate.course.course_key, + ) extended_data = get_extended_certificate_data(certificate) data.update(extended_data) @@ -144,8 +149,8 @@ def trigger_enrollments_creation(**kwargs): course_key (str): course identifier. user (User): user that just enrolled in the course. """ - course = _get_course(kwargs.get("course_key")) - user = kwargs.get("user") + enrollment = kwargs.get("enrollment") + course = _get_course(enrollment.course.course_key) followup_enrollments = getattr(course, "other_course_settings", {}).get( "EDNX_TRIGGER_FOLLOWUP_ENROLLMENTS" @@ -154,7 +159,9 @@ def trigger_enrollments_creation(**kwargs): if not followup_enrollments: return - create_enrollments_for_program.delay(user.username, followup_enrollments) + create_enrollments_for_program.delay( + enrollment.user.pii.username, followup_enrollments, + ) def trigger_grades_assignment(**kwargs): @@ -189,10 +196,10 @@ def trigger_grades_assignment(**kwargs): User `U` obtains 90% of the grade in X, then 1 is assigned to the component x. Keyword args: - certificate (GeneratedCertificate): certificate generated by the course. + certificate (CertificateData): certificate data generated by the course. """ certificate = kwargs.get("certificate") - course = _get_course(certificate.course_id) + course = _get_course(certificate.course.course_key) grades_assignment_settings = getattr(course, "other_course_settings", {}).get( "EDNX_TRIGGER_GRADES_ASSIGNMENT", {} diff --git a/eox_hooks/apps.py b/eox_hooks/apps.py index c63adb4..73b8a38 100644 --- a/eox_hooks/apps.py +++ b/eox_hooks/apps.py @@ -67,23 +67,48 @@ class EoxHooksConfig(AppConfig): 'receivers': [ { 'receiver_func_name': 'hooks_handler', - 'signal_path': get_signal_module('pre_enrollment'), - 'dispatch_uid': 'eox-hooks:pre_enrollment', + 'signal_path': 'openedx_events.learning.signals.STUDENT_REGISTRATION_COMPLETED', + 'dispatch_uid': 'eox-hooks:post_register', + }, + { + 'receiver_func_name': 'hooks_handler', + 'signal_path': 'openedx_events.learning.signals.SESSION_LOGIN_COMPLETED', + 'dispatch_uid': 'eox-hooks:post_session_login', + }, + { + 'receiver_func_name': 'hooks_handler', + 'signal_path': 'openedx_events.learning.signals.COURSE_ENROLLMENT_CREATED', + 'dispatch_uid': 'eox-hooks:post_enrollment', }, { 'receiver_func_name': 'hooks_handler', - 'signal_path': get_signal_module('post_certificate_creation'), + 'signal_path': 'openedx_events.learning.signals.COURSE_ENROLLMENT_CHANGED', + 'dispatch_uid': 'eox-hooks:post_enrollment_change', + }, + { + 'receiver_func_name': 'hooks_handler', + 'signal_path': 'openedx_events.learning.signals.COURSE_UNENROLLMENT_COMPLETED', + 'dispatch_uid': 'eox-hooks:post_unenrollment', + }, + { + 'receiver_func_name': 'hooks_handler', + 'signal_path': 'openedx_events.learning.signals.CERTIFICATE_CREATED', 'dispatch_uid': 'eox-hooks:post_certificate_creation', }, { 'receiver_func_name': 'hooks_handler', - 'signal_path': get_signal_module('post_register'), - 'dispatch_uid': 'eox-hooks:post_register', + 'signal_path': 'openedx_events.learning.signals.CERTIFICATE_CHANGED', + 'dispatch_uid': 'eox-hooks:post_certificate_change', }, { 'receiver_func_name': 'hooks_handler', - 'signal_path': get_signal_module('post_enrollment'), - 'dispatch_uid': 'eox-hooks:post_enrollment', + 'signal_path': 'openedx_events.learning.signals.CERTIFICATE_REVOKED', + 'dispatch_uid': 'eox-hooks:post_certificate_revoke', + }, + { + 'receiver_func_name': 'hooks_handler', + 'signal_path': 'openedx_events.learning.signals.COHORT_MEMBERSHIP_CHANGED', + 'dispatch_uid': 'eox-hooks:post_cohort_change', }, ], } diff --git a/eox_hooks/serializers.py b/eox_hooks/serializers.py index 6a414d1..aa7ad9e 100644 --- a/eox_hooks/serializers.py +++ b/eox_hooks/serializers.py @@ -8,7 +8,7 @@ from eox_hooks.edxapp_wrapper.models import get_certificate_model, get_user_profile_model -Certificate = get_certificate_model() +GeneratedCertificate = get_certificate_model() UserProfile = get_user_profile_model() @@ -20,7 +20,7 @@ class CertificateSerializer(serializers.ModelSerializer): class Meta: """Meta class.""" - model = Certificate + model = GeneratedCertificate fields = '__all__' diff --git a/eox_hooks/tests/test_actions.py b/eox_hooks/tests/test_actions.py index 3114260..ef11aa1 100644 --- a/eox_hooks/tests/test_actions.py +++ b/eox_hooks/tests/test_actions.py @@ -4,11 +4,12 @@ TestPostToWebhookUrl. TriggerEnrollmentsTest. """ +import datetime from unittest.mock import MagicMock, patch -from django.contrib.auth import get_user_model from django.test import TestCase from opaque_keys.edx.keys import CourseKey +from openedx_events.learning.data import CertificateData, CourseData, CourseEnrollmentData, UserData, UserPersonalData from eox_hooks.actions import get_request_fields, trigger_enrollments_creation, trigger_grades_assignment @@ -18,11 +19,14 @@ class TestPostToWebhookUrl(TestCase): def setUp(self): """Set up class for post_to_webhook_url testing.""" - self.user = get_user_model().objects.create( - id='1', - first_name='Tania', - last_name='Chernova', - username='taniacher', + self.user = UserData( + pii=UserPersonalData( + username="taniacher", + email="test@example.com", + name="Tania Chernova", + ), + id=1, + is_active=True, ) self.kwargs = { 'user': self.user, @@ -35,13 +39,11 @@ def test_get_request_fields(self): This should return a dictionary with all the fields found. """ fields = { - "first_name": "user.first_name", - "last_name": "user.last_name", - "username": "user.username", + "name": "user.pii.name", + "username": "user.pii.username", } expected_data = { - "first_name": "Tania", - "last_name": "Chernova", + "name": "Tania Chernova", "username": "taniacher", } @@ -60,7 +62,7 @@ def test_get_request_fields_missing_fields(self): fields = { "favorite_color": "user.favorite_color", "favorite_food": "user.favorite_food", - "username": "user.username", + "username": "user.pii.username", "course": "course.id", } extra_fields = { @@ -91,9 +93,26 @@ def setUp(self): """ Setup common conditions for test cases. """ - self.user = MagicMock(username="test") + enrollment = CourseEnrollmentData( + user=UserData( + pii=UserPersonalData( + username="test", + email="test@example.com", + name="Test Example", + ), + id=39, + is_active=True, + ), + course=CourseData( + course_key=CourseKey.from_string("course-v1:edX+DemoX+Demo_Course"), + display_name="Demonstration Course", + ), + mode="audit", + is_active=True, + creation_date=datetime.datetime.now(), + ) self.kwargs = { - "user": self.user, + "enrollment": enrollment, } @create_enrollments_for_program @@ -177,8 +196,26 @@ def setUp(self): """ Setup common conditions for test cases. """ - user = MagicMock(id=1, username="test") - self.certificate = MagicMock(user=user, grade=0.5) + self.certificate = CertificateData( + user=UserData( + pii=UserPersonalData( + username="test", + email="test@example.com", + name="Test Example", + ), + id=39, + is_active=True, + ), + course=CourseData( + course_key=CourseKey.from_string("course-v1:edX+DemoX+Demo_Course"), + display_name="Demonstration Course", + ), + mode="audit", + current_status="notpassing", + grade=0.5, + download_url="https://downdloadurl.com", + name="Certs", + ) self.kwargs = { "certificate": self.certificate, } diff --git a/eox_hooks/tests/test_receivers.py b/eox_hooks/tests/test_receivers.py index 8734e2e..7d899d2 100644 --- a/eox_hooks/tests/test_receivers.py +++ b/eox_hooks/tests/test_receivers.py @@ -3,9 +3,33 @@ Classes: TestReceivers. """ +import datetime + +import attr from django.conf import settings from django.test import TestCase, override_settings from mock import Mock, patch +from opaque_keys.edx.keys import CourseKey +from openedx_events.data import EventsMetadata +from openedx_events.learning.data import ( + CertificateData, + CohortData, + CourseData, + CourseEnrollmentData, + UserData, + UserPersonalData, +) +from openedx_events.learning.signals import ( + CERTIFICATE_CHANGED, + CERTIFICATE_CREATED, + CERTIFICATE_REVOKED, + COHORT_MEMBERSHIP_CHANGED, + COURSE_ENROLLMENT_CHANGED, + COURSE_ENROLLMENT_CREATED, + COURSE_UNENROLLMENT_COMPLETED, + SESSION_LOGIN_COMPLETED, + STUDENT_REGISTRATION_COMPLETED, +) from eox_hooks.receivers import hooks_handler @@ -66,3 +90,394 @@ def test_without_hooks_configuration_defined(self): This should result in the calling of a default action. """ self.assertIsNone(hooks_handler(self.sender, self.signal)) + + +@override_settings(USE_EOX_HOOKS=True) +class TestAuthEventsHandler(TestCase): + """ + Tests for hooks_handler when receiving Open edX Events related to the auth process. + """ + + def setUp(self): + """ + Setup common conditions for every test case. + """ + super().setUp() + self.user = UserData( + pii=UserPersonalData( + username="test", + email="test@example.com", + name="Test Example", + ), + id=39, + is_active=True, + ) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_register": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_registration(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + STUDENT_REGISTRATION_COMPLETED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.student.registration.completed.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + STUDENT_REGISTRATION_COMPLETED.connect(hooks_handler, dispatch_uid="eox-hooks:post_register") + + STUDENT_REGISTRATION_COMPLETED.send_event( + user=self.user, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.user, action_handler.call_args.kwargs.get("user")) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_session_login": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_login(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + SESSION_LOGIN_COMPLETED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.auth.session.login.completed.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + SESSION_LOGIN_COMPLETED.connect(hooks_handler, dispatch_uid="eox-hooks:post_session_login") + + SESSION_LOGIN_COMPLETED.send_event( + user=self.user, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.user, action_handler.call_args.kwargs.get("user")) + + +class TestEnrollmentEventsHandler(TestCase): + """ + Tests for hooks_handler when receiving Open edX Events related to the enrollment process. + """ + + def setUp(self): + """ + Setup common conditions for every test case. + """ + super().setUp() + self.enrollment = CourseEnrollmentData( + user=UserData( + pii=UserPersonalData( + username="test", + email="test@example.com", + name="Test Example", + ), + id=39, + is_active=True, + ), + course=CourseData( + course_key=CourseKey.from_string("course-v1:edX+DemoX+Demo_Course"), + display_name="Demonstration Course", + ), + mode="audit", + is_active=True, + creation_date=datetime.datetime.now(), + ) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_enrollment": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_enrollment(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + COURSE_ENROLLMENT_CREATED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.course.enrollment.created.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + COURSE_ENROLLMENT_CREATED.connect(hooks_handler, dispatch_uid="eox-hooks:post_enrollment") + + COURSE_ENROLLMENT_CREATED.send_event( + enrollment=self.enrollment, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.enrollment, action_handler.call_args.kwargs.get("enrollment")) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_enrollment_change": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_enroll_change(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + COURSE_ENROLLMENT_CHANGED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.course.enrollment.changed.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + COURSE_ENROLLMENT_CHANGED.connect(hooks_handler, dispatch_uid="eox-hooks:post_enrollment_change") + + COURSE_ENROLLMENT_CHANGED.send_event( + enrollment=self.enrollment, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.enrollment, action_handler.call_args.kwargs.get("enrollment")) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_unenrollment": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_unenrollment(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + COURSE_UNENROLLMENT_COMPLETED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.course.unenrollment.completed.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + COURSE_UNENROLLMENT_COMPLETED.connect(hooks_handler, dispatch_uid="eox-hooks:post_unenrollment") + + COURSE_UNENROLLMENT_COMPLETED.send_event( + enrollment=self.enrollment, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.enrollment, action_handler.call_args.kwargs.get("enrollment")) + + +class TestCertificateEventsHandler(TestCase): + """ + Tests for hooks_handler when receiving Open edX Events related to the certification process. + """ + + def setUp(self): + """ + Setup common conditions for every test case. + """ + super().setUp() + self.certificate = CertificateData( + user=UserData( + pii=UserPersonalData( + username="test", + email="test@example.com", + name="Test Example", + ), + id=39, + is_active=True, + ), + course=CourseData( + course_key=CourseKey.from_string("course-v1:edX+DemoX+Demo_Course"), + display_name="Demonstration Course", + ), + mode="audit", + current_status="notpassing", + grade=100, + download_url="https://downdloadurl.com", + name="Certs", + ) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_certificate_creation": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_cert_creation(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + CERTIFICATE_CREATED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.certificate.created.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + CERTIFICATE_CREATED.connect(hooks_handler, dispatch_uid="eox-hooks:post_certificate_creation") + + CERTIFICATE_CREATED.send_event( + certificate=self.certificate, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.certificate, action_handler.call_args.kwargs.get("certificate")) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_certificate_change": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_cert_change(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + CERTIFICATE_CHANGED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.certificate.changed.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + CERTIFICATE_CHANGED.connect(hooks_handler, dispatch_uid="eox-hooks:post_certificate_change") + + CERTIFICATE_CHANGED.send_event( + certificate=self.certificate, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.certificate, action_handler.call_args.kwargs.get("certificate")) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_certificate_revoke": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_cert_revoked(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + CERTIFICATE_REVOKED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.certificate.revoked.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + CERTIFICATE_REVOKED.connect(hooks_handler, dispatch_uid="eox-hooks:post_certificate_revoke") + + CERTIFICATE_REVOKED.send_event( + certificate=self.certificate, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.certificate, action_handler.call_args.kwargs.get("certificate")) + + +class TestCohortEventsHandler(TestCase): + """ + Tests for hooks_handler when receiving Open edX Events related to the cohort process. + """ + + def setUp(self): + """ + Setup common conditions for every test case. + """ + super().setUp() + self.cohort = CohortData( + user=UserData( + pii=UserPersonalData( + username="test", + email="test@example.com", + name="Test Example", + ), + id=39, + is_active=True, + ), + course=CourseData( + course_key=CourseKey.from_string("course-v1:edX+DemoX+Demo_Course"), + display_name="Demonstration Course", + ), + name="Uchiha", + ) + + @override_settings(EOX_HOOKS_DEFINITIONS={"post_cohort_change": {}}) + @patch("eox_hooks.receivers.action_handler") + def test_receiver_called_after_cert_change(self, action_handler): + """ + Test that hooks_handler is called the correct information after sending + COHORT_MEMBERSHIP_CHANGED event. + """ + metadata = EventsMetadata( + event_type="org.openedx.learning.cohort_membership.changed.v1", + minorversion=0, + ) + expected_metadata_subset = { + "event_type": metadata.event_type, + "minorversion": metadata.minorversion, + "source": metadata.source, + "sourcehost": metadata.sourcehost, + "sourcelib": list(metadata.sourcelib), + } + action_handler.return_value.__name__ = "receiver" + action_handler.return_value.__module__ = "receiver_module" + COHORT_MEMBERSHIP_CHANGED.connect(hooks_handler, dispatch_uid="eox-hooks:post_cohort_change") + + COHORT_MEMBERSHIP_CHANGED.send_event( + cohort=self.cohort, + ) + + self.assertDictContainsSubset( + expected_metadata_subset, attr.asdict(action_handler.call_args.kwargs.get("metadata")), + ) + self.assertEqual(self.cohort, action_handler.call_args.kwargs.get("cohort")) diff --git a/requirements/base.in b/requirements/base.in index 0c2cb23..d5eccea 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -6,3 +6,4 @@ djangorestframework django-crum edx-opaque-keys[django] celery +openedx-events diff --git a/requirements/base.txt b/requirements/base.txt index 6389536..0b61ecd 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,49 +1,54 @@ # -# This file is autogenerated by pip-compile +# This file is autogenerated by pip-compile with python 3.8 # To update, run: # # make upgrade # -amqp==1.4.9 +amqp==2.6.1 # via kombu -anyjson==0.3.3 - # via kombu -billiard==3.3.0.23 +attrs==21.2.0 + # via openedx-events +billiard==3.6.4.0 # via celery -celery==3.1.26.post2 +celery==4.4.7 # via # -c requirements/constraints.txt # -r requirements/base.in -django-crum==0.7.9 - # via -r requirements/base.in django==2.2.24 # via # -r requirements/base.in # django-crum + # djangorestframework # edx-opaque-keys -djangorestframework==3.9.4 + # openedx-events +django-crum==0.7.9 + # via -r requirements/base.in +djangorestframework==3.12.4 # via # -c requirements/constraints.txt # -r requirements/base.in -edx-opaque-keys[django]==2.1.0 +edx-opaque-keys[django]==2.2.0 # via # -c requirements/constraints.txt # -r requirements/base.in -kombu==3.0.37 + # openedx-events +kombu==4.6.11 # via celery +openedx-events==0.6.0 + # via -r requirements/base.in pbr==5.6.0 # via stevedore -pymongo==3.12.0 +pymongo==3.12.1 # via edx-opaque-keys -pytz==2021.1 +pytz==2021.3 # via # celery # django -six==1.16.0 - # via - # edx-opaque-keys - # stevedore -sqlparse==0.4.1 +sqlparse==0.4.2 # via django -stevedore==1.32.0 +stevedore==3.5.0 # via edx-opaque-keys +vine==1.3.0 + # via + # amqp + # celery diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 00d3e4f..b5bf71e 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -8,14 +8,9 @@ # pin when possible. Writing an issue against the offending project and # linking to it here is good. -# This version avoids conflict with wrapt -pylint==2.5.0 - -# TODO: Add constraint explanation -pycodestyle==2.6.0 # Keep same platform version -celery==3.1.26.post2 -djangorestframework==3.9.4 -edx-opaque-keys[django]==2.1.0 -testfixtures==6.4.3 +celery==4.4.7 +djangorestframework==3.12.4 +edx-opaque-keys[django]==2.2.0 +testfixtures==6.17.1 diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index aa6ffb8..51eb3dc 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -1,13 +1,20 @@ # -# This file is autogenerated by pip-compile +# This file is autogenerated by pip-compile with python 3.8 # To update, run: # # make upgrade # -click==7.1.2 +click==8.0.3 # via pip-tools -pip-tools==5.5.0 +pep517==0.12.0 + # via pip-tools +pip-tools==6.4.0 # via -r requirements/pip-tools.in +tomli==1.2.2 + # via pep517 +wheel==0.37.0 + # via pip-tools # The following packages are considered to be unsafe in a requirements file: # pip +# setuptools diff --git a/requirements/test.txt b/requirements/test.txt index 47403fb..dbc2d44 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,53 +1,60 @@ # -# This file is autogenerated by pip-compile +# This file is autogenerated by pip-compile with python 3.8 # To update, run: # # make upgrade # -amqp==1.4.9 - # via - # -r requirements/base.txt - # kombu -anyjson==0.3.3 +amqp==2.6.1 # via # -r requirements/base.txt # kombu astroid==2.4.2 # via pylint -billiard==3.3.0.23 +attrs==21.2.0 + # via + # -r requirements/base.txt + # openedx-events +billiard==3.6.4.0 # via # -r requirements/base.txt # celery -celery==3.1.26.post2 +celery==4.4.7 # via # -c requirements/constraints.txt # -r requirements/base.txt -certifi==2021.5.30 +certifi==2021.10.8 # via requests chardet==4.0.0 # via requests coverage==5.5 - # via -r requirements/test.in -django-crum==0.7.9 - # via -r requirements/base.txt + # via + # -c requirements/constraints.txt + # -r requirements/test.in django==2.2.24 # via # -r requirements/base.txt # django-crum + # djangorestframework # edx-opaque-keys -djangorestframework==3.9.4 + # openedx-events +django-crum==0.7.9 + # via -r requirements/base.txt +djangorestframework==3.12.4 # via # -c requirements/constraints.txt # -r requirements/base.txt -edx-opaque-keys[django]==2.1.0 +edx-opaque-keys[django]==2.2.0 # via # -c requirements/constraints.txt # -r requirements/base.txt + # openedx-events idna==2.10 # via requests isort==4.3.21 - # via pylint -kombu==3.0.37 + # via + # -c requirements/constraints.txt + # pylint +kombu==4.6.11 # via # -r requirements/base.txt # celery @@ -56,54 +63,58 @@ lazy-object-proxy==1.4.3 mccabe==0.6.1 # via pylint mock==3.0.5 - # via -r requirements/test.in + # via + # -c requirements/constraints.txt + # -r requirements/test.in +openedx-events==0.6.0 + # via -r requirements/base.txt pbr==5.6.0 # via # -r requirements/base.txt # stevedore -pycodestyle==2.6.0 - # via - # -c requirements/constraints.txt - # -r requirements/test.in -pylint==2.5.0 +pycodestyle==2.8.0 + # via -r requirements/test.in +pylint==2.6.2 # via # -c requirements/constraints.txt # -r requirements/test.in -pymongo==3.12.0 +pymongo==3.12.1 # via # -r requirements/base.txt # edx-opaque-keys -pytz==2021.1 +pytz==2021.3 # via # -r requirements/base.txt # celery # django requests==2.25.1 - # via -r requirements/test.in + # via + # -c requirements/constraints.txt + # -r requirements/test.in six==1.16.0 # via - # -r requirements/base.txt # astroid - # edx-opaque-keys # mock - # stevedore -sqlparse==0.4.1 +sqlparse==0.4.2 # via # -r requirements/base.txt # django -stevedore==1.32.0 +stevedore==3.5.0 # via # -r requirements/base.txt # edx-opaque-keys -testfixtures==6.4.3 +testfixtures==6.17.1 # via # -c requirements/constraints.txt # -r requirements/test.in toml==0.10.2 # via pylint -typed-ast==1.4.3 - # via astroid -urllib3==1.26.6 +urllib3==1.26.7 # via requests -wrapt==1.12.1 +vine==1.3.0 + # via + # -r requirements/base.txt + # amqp + # celery +wrapt==1.13.3 # via astroid diff --git a/requirements/tox.txt b/requirements/tox.txt index 7695582..66ea353 100644 --- a/requirements/tox.txt +++ b/requirements/tox.txt @@ -1,46 +1,43 @@ # -# This file is autogenerated by pip-compile +# This file is autogenerated by pip-compile with python 3.8 # To update, run: # # make upgrade # backports.entry-points-selectable==1.1.0 # via virtualenv -distlib==0.3.2 +distlib==0.3.3 # via virtualenv -filelock==3.0.12 +filelock==3.2.1 # via + # -c requirements/constraints.txt # tox # virtualenv -importlib-metadata==2.1.1 +packaging==20.9 # via - # backports.entry-points-selectable - # pluggy + # -c requirements/constraints.txt # tox - # virtualenv -importlib-resources==3.2.1 - # via virtualenv -packaging==20.9 - # via tox platformdirs==2.0.2 - # via virtualenv + # via + # -c requirements/constraints.txt + # virtualenv pluggy==0.13.1 - # via tox + # via + # -c requirements/constraints.txt + # tox py==1.10.0 # via tox pyparsing==2.4.7 - # via packaging + # via + # -c requirements/constraints.txt + # packaging six==1.16.0 # via # tox # virtualenv toml==0.10.2 # via tox -tox==3.24.1 +tox==3.24.4 # via -r requirements/tox.in -virtualenv==20.7.2 +virtualenv==20.10.0 # via tox -zipp==1.2.0 - # via - # importlib-metadata - # importlib-resources