Merge pull request #27456 from edx/ddumesnil/update-enrollment-activated-segment-aa-775

feat: AA-775: add course start and pacing to enrollment.activated segment event
This commit is contained in:
Dillon Dumesnil
2021-04-29 06:57:14 -07:00
committed by GitHub
3 changed files with 80 additions and 32 deletions

View File

@@ -1502,6 +1502,8 @@ class CourseEnrollment(models.Model):
# This next property is for an experiment, see method's comments for more information
segment_properties['external_course_updates'] = set_up_external_updates_for_enrollment(self.user,
self.course_id)
segment_properties['course_start'] = self.course.start
segment_properties['course_pacing'] = self.course.pacing
with tracker.get_tracker().context(event_name, context):
tracker.emit(event_name, data)
segment.track(self.user_id, event_name, segment_properties, traits=segment_traits)

View File

@@ -568,8 +568,11 @@ class EnrollmentEventTestMixin(EventTestMixin):
""" Mixin with assertions for validating enrollment events. """
def setUp(self): # lint-amnesty, pylint: disable=arguments-differ
super().setUp('common.djangoapps.student.models.tracker')
segment_patcher = patch('common.djangoapps.student.models.segment')
self.mock_segment_tracker = segment_patcher.start()
self.addCleanup(segment_patcher.stop)
def assert_enrollment_mode_change_event_was_emitted(self, user, course_key, mode):
def assert_enrollment_mode_change_event_was_emitted(self, user, course_key, mode, course, enrollment):
"""Ensures an enrollment mode change event was emitted"""
self.mock_tracker.emit.assert_called_once_with(
'edx.course.enrollment.mode_changed',
@@ -580,8 +583,13 @@ class EnrollmentEventTestMixin(EventTestMixin):
}
)
self.mock_tracker.reset_mock()
properties, traits = self._build_segment_properties_and_traits(user, course_key, course, enrollment)
self.mock_segment_tracker.track.assert_called_once_with(
user.id, 'edx.course.enrollment.mode_changed', properties, traits=traits
)
self.mock_segment_tracker.reset_mock()
def assert_enrollment_event_was_emitted(self, user, course_key):
def assert_enrollment_event_was_emitted(self, user, course_key, course, enrollment):
"""Ensures an enrollment event was emitted since the last event related assertion"""
self.mock_tracker.emit.assert_called_once_with(
'edx.course.enrollment.activated',
@@ -592,8 +600,13 @@ class EnrollmentEventTestMixin(EventTestMixin):
}
)
self.mock_tracker.reset_mock()
properties, traits = self._build_segment_properties_and_traits(user, course_key, course, enrollment, True)
self.mock_segment_tracker.track.assert_called_once_with(
user.id, 'edx.course.enrollment.activated', properties, traits=traits
)
self.mock_segment_tracker.reset_mock()
def assert_unenrollment_event_was_emitted(self, user, course_key):
def assert_unenrollment_event_was_emitted(self, user, course_key, course, enrollment):
"""Ensures an unenrollment event was emitted since the last event related assertion"""
self.mock_tracker.emit.assert_called_once_with(
'edx.course.enrollment.deactivated',
@@ -604,6 +617,35 @@ class EnrollmentEventTestMixin(EventTestMixin):
}
)
self.mock_tracker.reset_mock()
properties, traits = self._build_segment_properties_and_traits(user, course_key, course, enrollment)
self.mock_segment_tracker.track.assert_called_once_with(
user.id, 'edx.course.enrollment.deactivated', properties, traits=traits
)
self.mock_segment_tracker.reset_mock()
def _build_segment_properties_and_traits(self, user, course_key, course, enrollment, activated=False):
""" Builds the segment properties and traits that are sent during enrollment events """
properties = {
'category': 'conversion',
'label': str(course_key),
'org': course_key.org,
'course': course_key.course,
'run': course_key.run,
'mode': enrollment.mode,
}
traits = properties.copy()
traits.update({'course_title': course.display_name, 'email': user.email})
if activated:
properties.update({
'email': user.email,
# This next property is for an experiment, see method's comments for more information
# we will just hardcode the default value while the experiment runs
'external_course_updates': -1,
'course_start': course.start,
'course_pacing': course.pacing,
})
return properties, traits
class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
@@ -614,17 +656,18 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
user = User.objects.create_user("joe", "joe@joe.com", "password")
course_id = CourseKey.from_string("edX/Test101/2013")
course_id_partial = CourseKey.from_string("edX/Test101/")
course = CourseOverviewFactory.create(id=course_id)
# Test basic enrollment
assert not CourseEnrollment.is_enrolled(user, course_id)
assert not CourseEnrollment.is_enrolled_by_partial(user, course_id_partial)
CourseEnrollment.enroll(user, course_id)
enrollment = CourseEnrollment.enroll(user, course_id)
assert CourseEnrollment.is_enrolled(user, course_id)
assert CourseEnrollment.is_enrolled_by_partial(user, course_id_partial)
self.assert_enrollment_event_was_emitted(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id, course, enrollment)
# Enrolling them again should be harmless
CourseEnrollment.enroll(user, course_id)
enrollment = CourseEnrollment.enroll(user, course_id)
assert CourseEnrollment.is_enrolled(user, course_id)
assert CourseEnrollment.is_enrolled_by_partial(user, course_id_partial)
self.assert_no_events_were_emitted()
@@ -633,7 +676,7 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
CourseEnrollment.unenroll(user, course_id)
assert not CourseEnrollment.is_enrolled(user, course_id)
assert not CourseEnrollment.is_enrolled_by_partial(user, course_id_partial)
self.assert_unenrollment_event_was_emitted(user, course_id)
self.assert_unenrollment_event_was_emitted(user, course_id, course, enrollment)
# Unenrolling them again should also be harmless
CourseEnrollment.unenroll(user, course_id)
@@ -660,6 +703,7 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
# Testing enrollment of newly unsaved user (i.e. no database entry)
user = User(username="rusty", email="rusty@fake.edx.org")
course_id = CourseLocator("edX", "Test101", "2013")
course = CourseOverviewFactory.create(id=course_id)
assert not CourseEnrollment.is_enrolled(user, course_id)
@@ -669,18 +713,19 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
# Implicit save() happens on new User object when enrolling, so this
# should still work
CourseEnrollment.enroll(user, course_id)
enrollment = CourseEnrollment.enroll(user, course_id)
assert CourseEnrollment.is_enrolled(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id, course, enrollment)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_enrollment_by_email(self):
user = User.objects.create(username="jack", email="jack@fake.edx.org")
course_id = CourseLocator("edX", "Test101", "2013")
course = CourseOverviewFactory.create(id=course_id)
CourseEnrollment.enroll_by_email("jack@fake.edx.org", course_id)
enrollment = CourseEnrollment.enroll_by_email("jack@fake.edx.org", course_id)
assert CourseEnrollment.is_enrolled(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id, course, enrollment)
# This won't throw an exception, even though the user is not found
assert CourseEnrollment.enroll_by_email('not_jack@fake.edx.org', course_id) is None
@@ -698,7 +743,7 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
# Now unenroll them by email
CourseEnrollment.unenroll_by_email("jack@fake.edx.org", course_id)
assert not CourseEnrollment.is_enrolled(user, course_id)
self.assert_unenrollment_event_was_emitted(user, course_id)
self.assert_unenrollment_event_was_emitted(user, course_id, course, enrollment)
# Harmless second unenroll
CourseEnrollment.unenroll_by_email("jack@fake.edx.org", course_id)
@@ -714,21 +759,23 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
user = User(username="rusty", email="rusty@fake.edx.org")
course_id1 = CourseLocator("edX", "Test101", "2013")
course_id2 = CourseLocator("MITx", "6.003z", "2012")
course1 = CourseOverviewFactory.create(id=course_id1)
course2 = CourseOverviewFactory.create(id=course_id2)
CourseEnrollment.enroll(user, course_id1)
self.assert_enrollment_event_was_emitted(user, course_id1)
CourseEnrollment.enroll(user, course_id2)
self.assert_enrollment_event_was_emitted(user, course_id2)
enrollment1 = CourseEnrollment.enroll(user, course_id1)
self.assert_enrollment_event_was_emitted(user, course_id1, course1, enrollment1)
enrollment2 = CourseEnrollment.enroll(user, course_id2)
self.assert_enrollment_event_was_emitted(user, course_id2, course2, enrollment2)
assert CourseEnrollment.is_enrolled(user, course_id1)
assert CourseEnrollment.is_enrolled(user, course_id2)
CourseEnrollment.unenroll(user, course_id1)
self.assert_unenrollment_event_was_emitted(user, course_id1)
self.assert_unenrollment_event_was_emitted(user, course_id1, course1, enrollment1)
assert not CourseEnrollment.is_enrolled(user, course_id1)
assert CourseEnrollment.is_enrolled(user, course_id2)
CourseEnrollment.unenroll(user, course_id2)
self.assert_unenrollment_event_was_emitted(user, course_id2)
self.assert_unenrollment_event_was_emitted(user, course_id2, course2, enrollment2)
assert not CourseEnrollment.is_enrolled(user, course_id1)
assert not CourseEnrollment.is_enrolled(user, course_id2)
@@ -736,6 +783,7 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
def test_activation(self):
user = User.objects.create(username="jack", email="jack@fake.edx.org")
course_id = CourseLocator("edX", "Test101", "2013")
course = CourseOverviewFactory.create(id=course_id)
assert not CourseEnrollment.is_enrolled(user, course_id)
# Creating an enrollment doesn't actually enroll a student
@@ -747,7 +795,7 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
# Until you explicitly activate it
enrollment.activate()
assert CourseEnrollment.is_enrolled(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id, course, enrollment)
# Activating something that's already active does nothing
enrollment.activate()
@@ -757,7 +805,7 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
# Now deactive
enrollment.deactivate()
assert not CourseEnrollment.is_enrolled(user, course_id)
self.assert_unenrollment_event_was_emitted(user, course_id)
self.assert_unenrollment_event_was_emitted(user, course_id, course, enrollment)
# Deactivating something that's already inactive does nothing
enrollment.deactivate()
@@ -768,24 +816,25 @@ class EnrollInCourseTest(EnrollmentEventTestMixin, CacheIsolationTestCase):
# for that user/course_id combination
CourseEnrollment.enroll(user, course_id)
assert CourseEnrollment.is_enrolled(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id, course, enrollment)
def test_change_enrollment_modes(self):
user = User.objects.create(username="justin", email="jh@fake.edx.org")
course_id = CourseLocator("edX", "Test101", "2013")
course = CourseOverviewFactory.create(id=course_id)
CourseEnrollment.enroll(user, course_id, "audit")
self.assert_enrollment_event_was_emitted(user, course_id)
enrollment = CourseEnrollment.enroll(user, course_id, "audit")
self.assert_enrollment_event_was_emitted(user, course_id, course, enrollment)
CourseEnrollment.enroll(user, course_id, "honor")
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "honor")
enrollment = CourseEnrollment.enroll(user, course_id, "honor")
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "honor", course, enrollment)
# same enrollment mode does not emit an event
CourseEnrollment.enroll(user, course_id, "honor")
enrollment = CourseEnrollment.enroll(user, course_id, "honor")
self.assert_no_events_were_emitted()
CourseEnrollment.enroll(user, course_id, "audit")
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "audit")
enrollment = CourseEnrollment.enroll(user, course_id, "audit")
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "audit", course, enrollment)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')

View File

@@ -37,7 +37,7 @@ UTM_COOKIE_CONTENTS = {
@ddt.ddt
class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase):
class BasketsViewTests(UserMixin, ModuleStoreTestCase):
"""
Tests for the commerce Baskets view.
"""
@@ -86,9 +86,6 @@ class BasketsViewTests(EnrollmentEventTestMixin, UserMixin, ModuleStoreTestCase)
bulk_sku=f'BULK-{sku_string}'
)
# Ignore events fired from UserFactory creation
self.reset_tracker()
@mock.patch.dict(settings.FEATURES, {'EMBARGO': True})
def test_embargo_restriction(self):
"""