Commit ae5cbf8b by Clinton Blackburn

Merge pull request #7347 from edx/clintonb/commerce-events

Validating event emission by the commerce app
parents 3d520f4f eb72ab58
......@@ -485,14 +485,60 @@ class DashboardTest(ModuleStoreTestCase):
self.assertContains(response, expected_url)
class EnrollInCourseTest(TestCase):
"""Tests enrolling and unenrolling in courses."""
class EnrollmentEventTestMixin(object):
""" Mixin with assertions for validating enrollment events. """
def setUp(self):
super(EnrollmentEventTestMixin, self).setUp()
patcher = patch('student.models.tracker')
self.mock_tracker = patcher.start()
self.addCleanup(patcher.stop)
def assert_no_events_were_emitted(self):
"""Ensures no events were emitted since the last event related assertion"""
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
'edx.course.enrollment.activated',
{
'course_id': course_key.to_deprecated_string(),
'user_id': user.pk,
'mode': 'honor'
}
)
self.mock_tracker.reset_mock()
def assert_unenrollment_event_was_emitted(self, user, course_key):
"""Ensures an unenrollment event was emitted since the last event related assertion"""
self.mock_tracker.emit.assert_called_once_with( # pylint: disable=maybe-no-member
'edx.course.enrollment.deactivated',
{
'course_id': course_key.to_deprecated_string(),
'user_id': user.pk,
'mode': 'honor'
}
)
self.mock_tracker.reset_mock()
class EnrollInCourseTest(EnrollmentEventTestMixin, TestCase):
"""Tests enrolling and unenrolling in courses."""
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
def test_enrollment(self):
user = User.objects.create_user("joe", "joe@joe.com", "password")
......@@ -540,47 +586,6 @@ class EnrollInCourseTest(TestCase):
self.assertTrue(CourseEnrollment.is_enrolled(user, course_id))
self.assertEquals(enrollment.mode, "audit")
def assert_no_events_were_emitted(self):
"""Ensures no events were emitted since the last event related assertion"""
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
'edx.course.enrollment.activated',
{
'course_id': course_key.to_deprecated_string(),
'user_id': user.pk,
'mode': 'honor'
}
)
self.mock_tracker.reset_mock()
def assert_unenrollment_event_was_emitted(self, user, course_key):
"""Ensures an unenrollment event was emitted since the last event related assertion"""
self.mock_tracker.emit.assert_called_once_with( # pylint: disable=maybe-no-member
'edx.course.enrollment.deactivated',
{
'course_id': course_key.to_deprecated_string(),
'user_id': user.pk,
'mode': 'honor'
}
)
self.mock_tracker.reset_mock()
def test_enrollment_non_existent_user(self):
# Testing enrollment of newly unsaved user (i.e. no database entry)
user = User(username="rusty", email="rusty@fake.edx.org")
......
......@@ -18,6 +18,7 @@ from course_modes.models import CourseMode
from enrollment.api import add_enrollment
from student.models import CourseEnrollment
from student.tests.factories import UserFactory, CourseModeFactory
from student.tests.tests import EnrollmentEventTestMixin
ECOMMERCE_API_URL = 'http://example.com/api'
......@@ -28,7 +29,7 @@ ECOMMERCE_API_SUCCESSFUL_BODY = json.dumps({'status': OrderStatus.COMPLETE, 'num
@ddt
@override_settings(ECOMMERCE_API_URL=ECOMMERCE_API_URL, ECOMMERCE_API_SIGNING_KEY=ECOMMERCE_API_SIGNING_KEY)
class OrdersViewTests(ModuleStoreTestCase):
class OrdersViewTests(EnrollmentEventTestMixin, ModuleStoreTestCase):
"""
Tests for the commerce orders view.
"""
......@@ -71,6 +72,16 @@ class OrdersViewTests(ModuleStoreTestCase):
self.assertEqual(response.status_code, 503)
self.assertResponseMessage(response, 'Call to E-Commerce API failed. Order creation failed.')
def assertUserEnrolled(self):
""" Asserts that the user is enrolled in the course, and that an enrollment event was fired. """
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assert_enrollment_event_was_emitted(self.user, self.course.id)
def assertUserNotEnrolled(self):
""" Asserts that the user is NOT enrolled in the course, and that an enrollment event was NOT fired. """
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assert_no_events_were_emitted()
def setUp(self):
super(OrdersViewTests, self).setUp()
self.url = reverse('commerce:orders')
......@@ -128,7 +139,7 @@ class OrdersViewTests(ModuleStoreTestCase):
self._mock_ecommerce_api(status=status, body=json.dumps({'user_message': 'FAIL!'}))
response = self._post_to_view()
self.assertValidEcommerceApiErrorResponse(response)
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserNotEnrolled()
@httpretty.activate
def test_ecommerce_api_timeout(self):
......@@ -143,7 +154,7 @@ class OrdersViewTests(ModuleStoreTestCase):
self._mock_ecommerce_api(body=request_callback)
response = self._post_to_view()
self.assertValidEcommerceApiErrorResponse(response)
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserNotEnrolled()
@httpretty.activate
def test_ecommerce_api_bad_data(self):
......@@ -153,7 +164,7 @@ class OrdersViewTests(ModuleStoreTestCase):
self._mock_ecommerce_api(body='TOTALLY NOT JSON!')
response = self._post_to_view()
self.assertValidEcommerceApiErrorResponse(response)
self.assertFalse(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserNotEnrolled()
@data(True, False)
@httpretty.activate
......@@ -179,7 +190,7 @@ class OrdersViewTests(ModuleStoreTestCase):
msg = Messages.ORDER_COMPLETED.format(order_number=ORDER_NUMBER)
self.assertResponseMessage(response, msg)
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserEnrolled()
# Verify the correct information was passed to the E-Commerce API
request = httpretty.last_request()
......@@ -201,7 +212,7 @@ class OrdersViewTests(ModuleStoreTestCase):
self.assertResponseMessage(response, msg)
# TODO Eventually we should NOT be enrolling users directly from this view.
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserEnrolled()
def _test_course_without_sku(self):
"""
......@@ -218,7 +229,7 @@ class OrdersViewTests(ModuleStoreTestCase):
self.assertResponseMessage(response, msg)
# The user should be enrolled, and no calls made to the E-Commerce API
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserEnrolled()
self.assertIsInstance(httpretty.last_request(), HTTPrettyRequestEmpty)
@httpretty.activate
......@@ -249,7 +260,7 @@ class OrdersViewTests(ModuleStoreTestCase):
self.assertResponseMessage(response, msg)
# Ensure that the user is not enrolled and that no calls were made to the E-Commerce API
self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course.id))
self.assertUserEnrolled()
self.assertIsInstance(httpretty.last_request(), HTTPrettyRequestEmpty)
@httpretty.activate
......
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