-
Notifications
You must be signed in to change notification settings - Fork 4.2k
[BD-32] feat: 1st batch of Open edX Events #28266
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| import pytest | ||
| from django.conf import settings | ||
| from django.urls import reverse | ||
| from openedx_events.tests.utils import OpenEdxEventsTestMixin | ||
|
|
||
| from common.djangoapps.course_modes.models import CourseMode | ||
| from common.djangoapps.course_modes.tests.factories import CourseModeFactory | ||
|
|
@@ -30,19 +31,28 @@ | |
| @ddt.ddt | ||
| @patch.dict('django.conf.settings.FEATURES', {'ENABLE_SPECIAL_EXAMS': True}) | ||
| @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') | ||
| class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase): | ||
| class EnrollmentTest(UrlResetMixin, SharedModuleStoreTestCase, OpenEdxEventsTestMixin): | ||
|
||
| """ | ||
| Test student enrollment, especially with different course modes. | ||
| """ | ||
|
|
||
| ENABLED_OPENEDX_EVENTS = [] | ||
|
|
||
| USERNAME = "Bob" | ||
| EMAIL = "[email protected]" | ||
| PASSWORD = "edx" | ||
| URLCONF_MODULES = ['openedx.core.djangoapps.embargo'] | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls): | ||
| """ | ||
| Set up class method for the Test class. | ||
|
|
||
| This method starts manually events isolation. Explanation here: | ||
| openedx/core/djangoapps/user_authn/views/tests/test_events.py#L44 | ||
| """ | ||
| super().setUpClass() | ||
| cls.start_events_isolation() | ||
| cls.course = CourseFactory.create() | ||
| cls.course_limited = CourseFactory.create() | ||
| cls.proctored_course = CourseFactory( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,10 +10,23 @@ | |
| from django.test import TestCase | ||
| from django_countries.fields import Country | ||
|
|
||
| from common.djangoapps.student.models import CourseEnrollmentAllowed | ||
| from common.djangoapps.student.tests.factories import CourseEnrollmentAllowedFactory, UserFactory | ||
| from common.djangoapps.student.models import CourseEnrollmentAllowed, CourseEnrollment | ||
| from common.djangoapps.student.tests.factories import CourseEnrollmentAllowedFactory, UserFactory, UserProfileFactory | ||
| from common.djangoapps.student.tests.tests import UserSettingsEventTestMixin | ||
|
|
||
| from openedx_events.learning.data import ( | ||
| CourseData, | ||
| CourseEnrollmentData, | ||
| UserData, | ||
| UserPersonalData, | ||
| ) | ||
| from openedx_events.learning.signals import COURSE_ENROLLMENT_CREATED | ||
| from openedx_events.tests.utils import OpenEdxEventsTestMixin | ||
| from openedx.core.djangolib.testing.utils import skip_unless_lms | ||
|
|
||
| from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase | ||
| from xmodule.modulestore.tests.factories import CourseFactory | ||
|
|
||
|
|
||
| class TestUserProfileEvents(UserSettingsEventTestMixin, TestCase): | ||
| """ | ||
|
|
@@ -179,3 +192,87 @@ def test_enrolled_after_email_change(self): | |
| # CEAs shouldn't have been affected | ||
| assert CourseEnrollmentAllowed.objects.count() == 1 | ||
| assert CourseEnrollmentAllowed.objects.filter(email='[email protected]').count() == 1 | ||
|
|
||
|
|
||
| @skip_unless_lms | ||
| class EnrollmentEventsTest(SharedModuleStoreTestCase, OpenEdxEventsTestMixin): | ||
| """ | ||
| Tests for the Open edX Events associated with the enrollment process through the enroll method. | ||
|
|
||
| This class guarantees that the following events are sent during the user's enrollment, with | ||
| the exact Data Attributes as the event definition stated: | ||
|
|
||
| - COURSE_ENROLLMENT_CREATED: sent after the user's enrollment. | ||
| """ | ||
|
|
||
| ENABLED_OPENEDX_EVENTS = ["org.openedx.learning.course.enrollment.created.v1"] | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls): | ||
| """ | ||
| Set up class method for the Test class. | ||
|
|
||
| This method starts manually events isolation. Explanation here: | ||
| openedx/core/djangoapps/user_authn/views/tests/test_events.py#L44 | ||
| """ | ||
| super().setUpClass() | ||
| cls.start_events_isolation() | ||
|
|
||
| def setUp(self): # pylint: disable=arguments-differ | ||
| super().setUp() | ||
| self.course = CourseFactory.create() | ||
| self.user = UserFactory.create( | ||
| username="test", | ||
| email="[email protected]", | ||
| password="password", | ||
| ) | ||
| self.user_profile = UserProfileFactory.create(user=self.user, name="Test Example") | ||
| self.receiver_called = False | ||
|
|
||
| def _event_receiver_side_effect(self, **kwargs): # pylint: disable=unused-argument | ||
| """ | ||
| Used show that the Open edX Event was called by the Django signal handler. | ||
| """ | ||
| self.receiver_called = True | ||
|
|
||
| def test_enrollment_created_event_emitted(self): | ||
| """ | ||
| Test whether the student enrollment event is sent after the user's | ||
| enrollment process. | ||
|
|
||
| Expected result: | ||
| - COURSE_ENROLLMENT_CREATED is sent and received by the mocked receiver. | ||
| - The arguments that the receiver gets are the arguments sent by the event | ||
| except the metadata generated on the fly. | ||
| """ | ||
| event_receiver = mock.Mock(side_effect=self._event_receiver_side_effect) | ||
| COURSE_ENROLLMENT_CREATED.connect(event_receiver) | ||
|
|
||
| enrollment = CourseEnrollment.enroll(self.user, self.course.id) | ||
|
|
||
| self.assertTrue(self.receiver_called) | ||
| self.assertDictContainsSubset( | ||
| { | ||
| "signal": COURSE_ENROLLMENT_CREATED, | ||
| "sender": None, | ||
| "enrollment": CourseEnrollmentData( | ||
| user=UserData( | ||
| pii=UserPersonalData( | ||
| username=self.user.username, | ||
| email=self.user.email, | ||
| name=self.user.profile.name, | ||
| ), | ||
| id=self.user.id, | ||
| is_active=self.user.is_active, | ||
| ), | ||
| course=CourseData( | ||
| course_key=self.course.id, | ||
| display_name=self.course.display_name, | ||
| ), | ||
| mode=enrollment.mode, | ||
| is_active=enrollment.is_active, | ||
| creation_date=enrollment.created, | ||
| ), | ||
| }, | ||
| event_receiver.call_args.kwargs | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the abstraction layers that are being created for these data objects as part of this effort!