diff --git a/lms/djangoapps/courseware/features/events.feature b/lms/djangoapps/courseware/features/events.feature new file mode 100644 index 0000000000..3ffe817ca6 --- /dev/null +++ b/lms/djangoapps/courseware/features/events.feature @@ -0,0 +1,14 @@ +@shard_2 +Feature: LMS.Events + As a researcher, I want to be able to track events in the LMS + + Scenario Outline: An event is emitted for each request + Given: I am registered for the course "6.002x" + And I visit the url "" + Then a "" server event is emitted + + Examples: + | url | + | /dashboard | + | /courses/edx/6.002x/Test_Course/info | + | /courses/edx/6.002x/Test_Course/courseware | diff --git a/lms/djangoapps/courseware/features/events.py b/lms/djangoapps/courseware/features/events.py new file mode 100644 index 0000000000..6fa1d5d190 --- /dev/null +++ b/lms/djangoapps/courseware/features/events.py @@ -0,0 +1,62 @@ +#pylint: disable=C0111 + +from lettuce import step +from lettuce import world +from lettuce import before +from pymongo import MongoClient +from nose.tools import assert_equals +from nose.tools import assert_in + + +@before.all +def connect_to_mongodb(): + world.mongo_client = MongoClient() + world.event_collection = world.mongo_client['track']['events'] + + +@before.each_scenario +def reset_captured_events(_scenario): + world.event_collection.drop() + + +@before.outline +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): + + # Ensure all events are written out to mongo before querying. + world.mongo_client.fsync() + + # Note that splinter makes 2 requests when you call browser.visit('/foo') + # the first just checks to see if the server responds with a status + # code of 200, the next actually uses the browser to submit the request. + # We filter out events associated with the status code checks by ignoring + # events that come directly from splinter. + criteria = { + 'event_type': event_type, + 'event_source': event_source, + 'agent': { + '$ne': 'python/splinter' + } + } + cursor = world.event_collection.find(criteria) + assert_equals(cursor.count(), 1) + + event = cursor.next() + + # These fields should be present in the event, but we won't bother + # validating them since it is difficult to predict their values. + for expected_field in ['host', 'time', 'agent', 'ip', 'event_source', 'event', 'page']: + assert_in(expected_field, event, msg='Expected field {} not found in event'.format(expected_field)) + + expected_field_values = { + "username": world.scenario_dict['USER'].username, + "event_type": event_type, + } + for key, value in expected_field_values.iteritems(): + assert_equals(event[key], value) + + # Note that the event may contain other fields, which is fine! diff --git a/lms/djangoapps/courseware/features/navigation.feature b/lms/djangoapps/courseware/features/navigation.feature index ad84019725..ca23f49828 100644 --- a/lms/djangoapps/courseware/features/navigation.feature +++ b/lms/djangoapps/courseware/features/navigation.feature @@ -18,6 +18,7 @@ Feature: LMS.Navigate Course Given I am viewing a section with multiple sequences When I navigate to an item in a sequence Then I see the content of the sequence item + And a "seq_goto" browser event is emitted Scenario: I can return to the last section I visited Given I am viewing a course with multiple sections diff --git a/lms/djangoapps/courseware/features/problems.feature b/lms/djangoapps/courseware/features/problems.feature index 2f15619a94..0dca3201c1 100644 --- a/lms/djangoapps/courseware/features/problems.feature +++ b/lms/djangoapps/courseware/features/problems.feature @@ -10,6 +10,8 @@ Feature: LMS.Answer problems When I answer a "" problem "correctly" Then my "" answer is marked "correct" And The "" problem displays a "correct" answer + And a "problem_check" server event is emitted + And a "problem_check" browser event is emitted Examples: | ProblemType | diff --git a/lms/envs/acceptance.py b/lms/envs/acceptance.py index 0914805ae2..b0e8174e4b 100644 --- a/lms/envs/acceptance.py +++ b/lms/envs/acceptance.py @@ -74,6 +74,12 @@ DATABASES = { } } +TRACKING_BACKENDS.update({ + 'mongo': { + 'ENGINE': 'track.backends.mongodb.MongoBackend' + } +}) + # Forums are disabled in test.py to speed up unit tests, but we do not have # per-test control for acceptance tests MITX_FEATURES['ENABLE_DISCUSSION_SERVICE'] = True