Commit e78a398f by Justin Helbert

This emits enrollment mode changes events

parent d352d4ae
......@@ -328,6 +328,7 @@ class PendingEmailChange(models.Model):
EVENT_NAME_ENROLLMENT_ACTIVATED = 'edx.course.enrollment.activated'
EVENT_NAME_ENROLLMENT_DEACTIVATED = 'edx.course.enrollment.deactivated'
EVENT_NAME_ENROLLMENT_MODE_CHANGED = 'edx.course.enrollment.mode_changed'
class PasswordHistory(models.Model):
......@@ -716,6 +717,10 @@ class CourseEnrollment(models.Model):
u"offering:{}".format(self.course_id.offering),
u"mode:{}".format(self.mode)]
)
if mode_changed:
# the user's default mode is "honor" and disabled for a course
# mode change events will only be emitted when the user's mode changes from this
self.emit_event(EVENT_NAME_ENROLLMENT_MODE_CHANGED)
def emit_event(self, event_name):
"""
......
......@@ -310,6 +310,18 @@ class EnrollInCourseTest(TestCase):
self.assertFalse(self.mock_tracker.emit.called) # pylint: disable=maybe-no-member
self.mock_tracker.reset_mock()
def assert_enrollment_mode_change_event_was_emitted(self, user, course_key, mode):
"""Ensures an enrollment mode change event was emitted"""
self.mock_tracker.emit.assert_called_once_with( # pylint: disable=maybe-no-member
'edx.course.enrollment.mode_changed',
{
'course_id': course_key.to_deprecated_string(),
'user_id': user.pk,
'mode': mode
}
)
self.mock_tracker.reset_mock()
def assert_enrollment_event_was_emitted(self, user, course_key):
"""Ensures an enrollment event was emitted since the last event related assertion"""
self.mock_tracker.emit.assert_called_once_with( # pylint: disable=maybe-no-member
......@@ -447,6 +459,23 @@ class EnrollInCourseTest(TestCase):
self.assertTrue(CourseEnrollment.is_enrolled(user, course_id))
self.assert_enrollment_event_was_emitted(user, course_id)
def test_change_enrollment_modes(self):
user = User.objects.create(username="justin", email="jh@fake.edx.org")
course_id = SlashSeparatedCourseKey("edX", "Test101", "2013")
CourseEnrollment.enroll(user, course_id)
self.assert_enrollment_event_was_emitted(user, course_id)
CourseEnrollment.enroll(user, course_id, "audit")
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "audit")
# same enrollment mode does not emit an event
CourseEnrollment.enroll(user, course_id, "audit")
self.assert_no_events_were_emitted()
CourseEnrollment.enroll(user, course_id, "honor")
self.assert_enrollment_mode_change_event_was_emitted(user, course_id, "honor")
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
......
Feature: Change Enrollment Events
As a registered user
I want to change my enrollment mode
Scenario: I can change my enrollment
Given The course "6.002x" exists
And the course "6.002x" has all enrollment modes
And I am logged in
And I visit the courses page
When I register to audit the course
And a "edx.course.enrollment.activated" server event is emitted
And a "edx.course.enrollment.mode_changed" server events is emitted
And I visit the dashboard
And I click on Challenge Yourself
And I choose an honor code upgrade
Then I should be on the dashboard page
Then 2 "edx.course.enrollment.mode_changed" server event is emitted
# don't emit another mode_changed event upon unenrollment
When I unregister for the course numbered "6.002x"
Then 2 "edx.course.enrollment.mode_changed" server events is emitted
""" Provides lettuce acceptance methods for course enrollment changes """
from __future__ import absolute_import
from lettuce import world, step
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from logging import getLogger
logger = getLogger(__name__)
@step(u'the course "([^"]*)" has all enrollment modes$')
def add_enrollment_modes_to_course(_step, course):
""" Add honor, audit, and verified modes to the sample course """
world.CourseModeFactory.create(
course_id=SlashSeparatedCourseKey("edx", course, 'Test_Course'),
mode_slug="verified",
mode_display_name="Verified Course",
min_price=3
)
world.CourseModeFactory.create(
course_id=SlashSeparatedCourseKey("edx", course, 'Test_Course'),
mode_slug="honor",
mode_display_name="Honor Course",
)
world.CourseModeFactory.create(
course_id=SlashSeparatedCourseKey("edx", course, 'Test_Course'),
mode_slug="audit",
mode_display_name="Audit Course",
)
@step(u'I click on Challenge Yourself$')
def challenge_yourself(_step):
""" Simulates clicking 'Challenge Yourself' button on course """
challenge_button = world.browser.find_by_css('.wrapper-tip')
challenge_button.click()
verified_button = world.browser.find_by_css('#upgrade-to-verified')
verified_button.click()
@step(u'I choose an honor code upgrade$')
def honor_code_upgrade(_step):
""" Simulates choosing the honor code mode on the upgrade page """
honor_code_link = world.browser.find_by_css('.title-expand')
honor_code_link.click()
honor_code_checkbox = world.browser.find_by_css('#honor-code')
honor_code_checkbox.click()
upgrade_button = world.browser.find_by_name("certificate_mode")
upgrade_button.click()
......@@ -15,7 +15,6 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.course_module import CourseDescriptor
from courseware.courses import get_course_by_id
from xmodule import seq_module, vertical_module
from logging import getLogger
logger = getLogger(__name__)
......@@ -27,7 +26,7 @@ def configure_screenshots_for_all_steps(_step, action):
automatic saving of screenshots before and after each step in a
scenario.
"""
action=action.strip()
action = action.strip()
if action == 'enable':
world.auto_capture_screenshots = True
elif action == 'disable':
......@@ -35,6 +34,7 @@ def configure_screenshots_for_all_steps(_step, action):
else:
raise ValueError('Parameter `action` should be one of "enable" or "disable".')
@world.absorb
def capture_screenshot_before_after(func):
"""
......@@ -43,12 +43,12 @@ def capture_screenshot_before_after(func):
for each step in a scenario, but rather want to debug a single function.
"""
def inner(*args, **kwargs):
prefix=round(time.time() * 1000)
prefix = round(time.time() * 1000)
world.capture_screenshot("{}_{}_{}".format(
prefix, func.func_name, 'before'
))
ret_val=func(*args, **kwargs)
ret_val = func(*args, **kwargs)
world.capture_screenshot("{}_{}_{}".format(
prefix, func.func_name, 'after'
))
......@@ -94,11 +94,11 @@ def i_am_registered_for_the_course(step, course):
# Create the user
world.create_user('robot', 'test')
u = User.objects.get(username='robot')
user = User.objects.get(username='robot')
# If the user is not already enrolled, enroll the user.
# TODO: change to factory
CourseEnrollment.enroll(u, course_id(course))
CourseEnrollment.enroll(user, course_id(course))
world.log_in(username='robot', password='test')
......
......@@ -36,8 +36,8 @@ def reset_between_outline_scenarios(_scenario, order, outline, reasons_to_fail):
world.event_collection.drop()
@step('[aA]n? "(.*)" (server|browser) event is emitted')
def event_is_emitted(_step, event_type, event_source):
@step(r'([aA]n?|\d+) "(.*)" (server|browser) events? is emitted$')
def n_events_are_emitted(_step, count, event_type, event_source):
# Ensure all events are written out to mongo before querying.
world.mongo_client.fsync()
......@@ -54,8 +54,15 @@ def event_is_emitted(_step, event_type, event_source):
'$ne': 'python/splinter'
}
}
cursor = world.event_collection.find(criteria)
assert_equals(cursor.count(), 1)
try:
number_events = int(count)
except ValueError:
number_events = 1
assert_equals(cursor.count(), number_events)
event = cursor.next()
......
......@@ -10,7 +10,16 @@ def i_register_for_the_course(_step, course):
url = django_url('courses/%s/about' % world.scenario_dict['COURSE'].id.to_deprecated_string())
world.browser.visit(url)
world.css_click('section.intro a.register')
assert world.is_css_present('section.container.dashboard')
@step('I register to audit the course$')
def i_register_to_audit_the_course(_step):
url = django_url('courses/%s/about' % world.scenario_dict['COURSE'].id.to_deprecated_string())
world.browser.visit(url)
world.css_click('section.intro a.register')
audit_button = world.browser.find_by_name("audit_mode")
audit_button.click()
assert world.is_css_present('section.container.dashboard')
......
......@@ -35,7 +35,6 @@ from verify_student.models import SoftwareSecurePhotoVerification
from reverification.tests.factories import MidcourseReverificationWindowFactory
def mock_render_to_response(*args, **kwargs):
return render_to_response(*args, **kwargs)
......@@ -386,8 +385,17 @@ class TestMidCourseReverifyView(TestCase):
kwargs={"course_id": self.course_key.to_deprecated_string()})
response = self.client.get(url)
# Check that user entering the reverify flow was logged
self.mock_tracker.emit.assert_called_once_with( # pylint: disable=maybe-no-member
self.mock_tracker.emit.assert_any_call( # pylint: disable=maybe-no-member
'edx.course.enrollment.mode_changed',
{
'user_id': self.user.id,
'course_id': self.course_key.to_deprecated_string(),
'mode': "verified",
}
)
# Check that user entering the reverify flow was logged, and that it was the last call
self.mock_tracker.emit.assert_called_with( # pylint: disable=maybe-no-member
'edx.course.enrollment.reverify.started',
{
'user_id': self.user.id,
......@@ -395,6 +403,9 @@ class TestMidCourseReverifyView(TestCase):
'mode': "verified",
}
)
self.assertTrue(self.mock_tracker.emit.call_count, 2)
self.mock_tracker.emit.reset_mock() # pylint: disable=maybe-no-member
self.assertEquals(response.status_code, 200)
......@@ -408,8 +419,17 @@ class TestMidCourseReverifyView(TestCase):
response = self.client.post(url, {'face_image': ','})
# Check that submission event was logged
self.mock_tracker.emit.assert_called_once_with( # pylint: disable=maybe-no-member
self.mock_tracker.emit.assert_any_call( # pylint: disable=maybe-no-member
'edx.course.enrollment.mode_changed',
{
'user_id': self.user.id,
'course_id': self.course_key.to_deprecated_string(),
'mode': "verified",
}
)
# Check that submission event was logged, and that it was the last call
self.mock_tracker.emit.assert_called_with( # pylint: disable=maybe-no-member
'edx.course.enrollment.reverify.submitted',
{
'user_id': self.user.id,
......@@ -417,6 +437,9 @@ class TestMidCourseReverifyView(TestCase):
'mode': "verified",
}
)
self.assertTrue(self.mock_tracker.emit.call_count, 2)
self.mock_tracker.emit.reset_mock() # pylint: disable=maybe-no-member
self.assertEquals(response.status_code, 302)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment