class TrackMiddlewareTestCase(TestCase): def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() def test_normal_request(self, mock_server_track): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(mock_server_track.called) def test_default_filters_do_not_render_view(self, mock_server_track): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(mock_server_track.called) mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self, mock_server_track): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self, mock_server_track): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(mock_server_track.called) mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(mock_server_track.called)
def test_user_track_with_middleware(self): middleware = TrackMiddleware() request = self.request_factory.get('/event', { 'page': self.url_with_course, 'event_type': sentinel.event_type, 'event': {} }) middleware.process_request(request) try: views.user_track(request) expected_event = { 'username': '******', 'session': '', 'ip': '127.0.0.1', 'event_source': 'browser', 'event_type': str(sentinel.event_type), 'event': '{}', 'agent': '', 'page': self.url_with_course, 'time': expected_time, 'host': 'testserver', 'context': { 'course_id': 'foo/bar/baz', 'org_id': 'foo', 'user_id': '', 'path': u'/event' }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event)
def test_server_track_with_middleware(self): middleware = TrackMiddleware() request = self.request_factory.get(self.path_with_course) middleware.process_request(request) # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature. self.mock_tracker.reset_mock() try: views.server_track(request, str(sentinel.event_type), '{}') expected_event = { 'username': '******', 'ip': '127.0.0.1', 'event_source': 'server', 'event_type': str(sentinel.event_type), 'event': '{}', 'agent': '', 'page': None, 'time': expected_time, 'host': 'testserver', 'context': { 'user_id': '', 'course_id': u'foo/bar/baz', 'org_id': 'foo', 'path': u'/courses/foo/bar/baz/xmod/' }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event)
def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop)
def test_server_track_with_middleware_and_google_analytics_cookie(self): middleware = TrackMiddleware() request = self.request_factory.get(self.path_with_course) request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899' middleware.process_request(request) # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature. self.mock_tracker.reset_mock() try: views.server_track(request, str(sentinel.event_type), '{}') expected_event = { 'accept_language': '', 'referer': '', 'username': '******', 'ip': '127.0.0.1', 'event_source': 'server', 'event_type': str(sentinel.event_type), 'event': '{}', 'agent': '', 'page': None, 'time': FROZEN_TIME, 'host': 'testserver', 'context': { 'user_id': '', 'course_id': u'foo/bar/baz', 'org_id': 'foo', 'path': u'/courses/foo/bar/baz/xmod/' }, } finally: middleware.process_response(request, None) self.assert_mock_tracker_call_matches(expected_event)
def test_success(self, course_id): middleware = TrackMiddleware() request = self.create_request( data=self.create_segmentio_event_json(data={'foo': 'bar'}, course_id=course_id), content_type='application/json' ) User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) # The middleware normally emits an event, make sure it doesn't in this case. self.assert_no_events_emitted() try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'accept_language': '', 'referer': '', 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': str(sentinel.name), 'name': str(sentinel.name), 'event': {'foo': 'bar'}, 'agent': str(sentinel.user_agent), 'page': None, 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'application': { 'name': 'edx.mobile.android', 'version': '1.0.1', }, 'user_id': USER_ID, 'course_id': course_id, 'org_id': u'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'app': { 'version': '1.0.1', }, }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, } finally: middleware.process_response(request, None) assert_event_matches(expected_event, self.get_event())
def test_user_track_with_middleware_and_processors(self): self.recreate_tracker() middleware = TrackMiddleware() payload = '{"foo": "bar"}' user_id = 1 request = self.request_factory.get('/event', { 'page': self.url_with_course, 'event_type': sentinel.event_type, 'event': payload }) request.user = User.objects.create(pk=user_id, username=str(sentinel.username)) request.META['REMOTE_ADDR'] = '10.0.0.1' request.META['HTTP_REFERER'] = str(sentinel.referer) request.META['HTTP_ACCEPT_LANGUAGE'] = str(sentinel.accept_language) request.META['HTTP_USER_AGENT'] = str(sentinel.user_agent) request.META['SERVER_NAME'] = 'testserver2' middleware.process_request(request) try: views.user_track(request) expected_event = { 'accept_language': str(sentinel.accept_language), 'referer': str(sentinel.referer), 'username': str(sentinel.username), 'session': '', 'ip': '10.0.0.1', 'event_source': 'browser', 'event_type': str(sentinel.event_type), 'name': str(sentinel.event_type), 'event': payload, 'agent': str(sentinel.user_agent), 'page': self.url_with_course, 'time': FROZEN_TIME, 'host': 'testserver2', 'context': { 'course_id': 'foo/bar/baz', 'org_id': 'foo', 'user_id': user_id, 'path': u'/event' }, } finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event)
def setUp(self): super(TrackMiddlewareTestCase, self).setUp() self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch("track.views.server_track") self.mock_server_track = patcher.start() self.addCleanup(patcher.stop)
def test_success(self, course_id): middleware = TrackMiddleware() request = self.create_request( data=self.create_segmentio_event_json(event_type=str(sentinel.event_type), event={'foo': 'bar'}, course_id=course_id), content_type='application/json' ) User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) # The middleware normally emits an event, make sure it doesn't in this case. self.assertFalse(self.mock_tracker.send.called) # pylint: disable=maybe-no-member try: response = segmentio.track_segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'username': str(sentinel.username), 'ip': '', 'event_source': 'mobile', 'event_type': str(sentinel.event_type), 'name': str(sentinel.name), 'event': {'foo': 'bar'}, 'agent': str(sentinel.user_agent), 'page': None, 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'unknown', 'version': 'unknown' }, 'userAgent': str(sentinel.user_agent) }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event) # pylint: disable=maybe-no-member
def test_server_track_with_middleware(self): middleware = TrackMiddleware() request = self.request_factory.get(self.path_with_course) middleware.process_request(request) # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature. self.mock_tracker.reset_mock() try: views.server_track(request, str(sentinel.event_type), '{}') expected_event = { 'accept_language': '', 'referer': '', 'username': '******', 'ip': '127.0.0.1', 'event_source': 'server', 'event_type': str(sentinel.event_type), 'event': '{}', 'agent': '', 'page': None, 'time': FROZEN_TIME, 'host': 'testserver', 'context': { 'user_id': '', 'course_id': u'foo/bar/baz', 'org_id': 'foo', 'path': u'/courses/foo/bar/baz/xmod/' }, } finally: middleware.process_response(request, None) self.assert_mock_tracker_call_matches(expected_event)
def test_server_track_with_middleware_and_google_analytics_cookie(self): middleware = TrackMiddleware() request = self.request_factory.get(self.path_with_course) request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899' middleware.process_request(request) # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature. self.mock_tracker.reset_mock() try: views.server_track(request, str(sentinel.event_type), '{}') expected_event = { 'username': '******', 'ip': '127.0.0.1', 'event_source': 'server', 'event_type': str(sentinel.event_type), 'event': '{}', 'agent': '', 'page': None, 'time': expected_time, 'host': 'testserver', 'context': { 'user_id': '', 'course_id': u'foo/bar/baz', 'org_id': 'foo', 'path': u'/courses/foo/bar/baz/xmod/' }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event)
def test_user_track_with_middleware(self): middleware = TrackMiddleware() request = self.request_factory.get('/event', { 'page': self.url_with_course, 'event_type': sentinel.event_type, 'event': {} }) request.user = self.user request.session = {"referer": "www.baidu.com"} middleware.process_request(request) try: views.user_track(request) expected_event = { 'username': '', 'session': None, 'ip': '127.0.0.1', 'event_source': 'browser', 'event_type': str(sentinel.event_type), 'event': {}, 'agent': '', 'page': self.url_with_course, 'time': '2013/10/03 16:24:55', 'host': 'testserver', 'spam': None, 'referer': '', 'origin_referer': 'www.baidu.com', 'context': { 'course_id': 'foo/bar/baz', 'org_id': 'foo', 'user_id': '', 'path': u'/event' }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event)
def test_server_track_with_middleware_and_google_analytics_cookie(self): middleware = TrackMiddleware() request = self.request_factory.get(self.path_with_course) request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899' request.user = self.user request.session = {"referer": "www.baidu.com"} middleware.process_request(request) # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature. self.mock_tracker.reset_mock() try: views.server_track(request, str(sentinel.event_type), '{}') expected_event = { 'username': '', 'ip': '127.0.0.1', 'event_source': 'server', 'event_type': str(sentinel.event_type), 'event': '{}', 'agent': '', 'page': None, 'time': '2013/10/03 16:24:55', 'host': 'testserver', 'session': None, 'referer': '', 'origin_referer': 'www.baidu.com', 'spam': None, 'method': 'GET', 'context': { 'user_id': '', 'course_id': u'foo/bar/baz', 'org_id': 'foo', 'path': u'/courses/foo/bar/baz/xmod/' }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event)
def test_user_track_with_middleware_and_processors(self): self.recreate_tracker() middleware = TrackMiddleware() payload = '{"foo": "bar"}' user_id = 1 request = self.request_factory.get( '/event', { 'page': self.url_with_course, 'event_type': sentinel.event_type, 'event': payload }) request.user = User.objects.create(pk=user_id, username=str(sentinel.username)) request.META['REMOTE_ADDR'] = '10.0.0.1' request.META['HTTP_REFERER'] = str(sentinel.referer) request.META['HTTP_ACCEPT_LANGUAGE'] = str(sentinel.accept_language) request.META['HTTP_USER_AGENT'] = str(sentinel.user_agent) request.META['SERVER_NAME'] = 'testserver2' middleware.process_request(request) try: views.user_track(request) expected_event = { 'accept_language': str(sentinel.accept_language), 'referer': str(sentinel.referer), 'username': str(sentinel.username), 'session': '', 'ip': '10.0.0.1', 'event_source': 'browser', 'event_type': str(sentinel.event_type), 'name': str(sentinel.event_type), 'event': payload, 'agent': str(sentinel.user_agent), 'page': self.url_with_course, 'time': FROZEN_TIME, 'host': 'testserver2', 'context': { 'course_id': 'foo/bar/baz', 'org_id': 'foo', 'user_id': user_id, 'path': u'/event' }, } finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event)
def test_server_track_with_middleware_and_google_analytics_cookie(self): middleware = TrackMiddleware() request = self.request_factory.get(self.path_with_course) request.COOKIES['_ga'] = 'GA1.2.1033501218.1368477899' middleware.process_request(request) # The middleware emits an event, reset the mock to ignore it since we aren't testing that feature. self.mock_tracker.reset_mock() try: views.server_track(request, str(sentinel.event_type), '{}') expected_event = { 'timestamp': FROZEN_TIME, 'data': '{"GET": {}, "POST": {}}', 'name': self.path_with_course, 'context': { 'username': '******', 'user_id': '', 'accept_language': '', 'ip': '127.0.0.1', 'org_id': 'foo', 'agent': '', 'event_source': 'server', 'host': 'testserver', 'session': '', 'referer': '', 'client_id': '1033501218.1368477899', 'course_id': 'foo/bar/baz', 'path': self.path_with_course, 'page': None } } finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event, tolerate={ 'string_payload', })
class TrackMiddlewareTestCase(TestCase): def setUp(self): super(TrackMiddlewareTestCase, self).setUp() self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path('/courses/') self.assertEquals(context, { 'accept_language': '', 'referer': '', 'user_id': '', 'session': '', 'username': '', 'ip': '127.0.0.1', 'host': 'testserver', 'agent': '', 'path': '/courses/', 'org_id': '', 'course_id': '', 'client_id': None, }) def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals( tracker.get_tracker().resolve_context(), {} ) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path('/courses/test_org/test_course/test_run/foo') expected_context_subset = { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', } self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get('/courses/') request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'user_id': user_id, 'username': username, }) def test_request_with_session(self): request = self.request_factory.get('/courses/') SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key expected_session_key = self.track_middleware.encrypt_session_key(session_key) self.assertEquals(len(session_key), len(expected_session_key)) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'session': expected_session_key, }) @override_settings(SECRET_KEY='85920908f28904ed733fe576320db18cabd7b6cd') def test_session_key_encryption(self): session_key = '665924b49a93e22b46ee9365abf28c2a' expected_session_key = '3b81f559d14130180065d635a4f35dd2' encrypted_session_key = self.track_middleware.encrypt_session_key(session_key) self.assertEquals(encrypted_session_key, expected_session_key) def test_request_headers(self): ip_address = '10.0.0.0' user_agent = 'UnitTest/1.0' factory = RequestFactory(REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent) request = factory.get('/some-path') context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'ip': ip_address, 'agent': user_agent, }) @patch('track.middleware.TRUNCATION_LENGTH', 6) def test_student_answer_request(self): request = self.request_factory.post('/dummy') request.POST = {'student_answer': ['firstanswer', 'secondanswer']} self.track_middleware.process_request(request) event = '{"POST": {"student_answer": ["fir", "sec"]}, "GET": {}}' self.mock_server_track.assert_called_with(request, request.META['PATH_INFO'], event) @patch('track.middleware.TRUNCATION_LENGTH', 20) def test_submission_request(self): request = self.request_factory.post('/dummy') request.POST = {'{"submission":["first open response", "second open response"]}': []} self.track_middleware.process_request(request) event = '{"POST": {"submission": ["first open", "second ope"]}, "GET": {}}' self.mock_server_track.assert_called_with(request, request.META['PATH_INFO'], event)
class TrackMiddlewareTestCase(TestCase): def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path('/courses/') self.assertEquals(context, { 'user_id': '', 'session': '', 'username': '', 'ip': '127.0.0.1', 'host': 'testserver', 'agent': '', 'path': '/courses/', 'org_id': '', 'course_id': '', }) def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals( tracker.get_tracker().resolve_context(), {} ) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path('/courses/test_org/test_course/test_run/foo') expected_context_subset = { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', } self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get('/courses/') request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'user_id': user_id, 'username': username, }) def test_request_with_session(self): request = self.request_factory.get('/courses/') SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'session': session_key, }) def test_request_headers(self): ip_address = '10.0.0.0' user_agent = 'UnitTest/1.0' factory = RequestFactory(REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent) request = factory.get('/some-path') context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'ip': ip_address, 'agent': user_agent, })
def test_video_event(self, name, event_type): course_id = 'foo/bar/baz' middleware = TrackMiddleware() input_payload = { 'current_time': 132.134456, 'module_id': 'i4x://foo/bar/baz/some_module', 'code': 'mobile' } if name == 'edx.video.loaded': del input_payload['current_time'] request = self.create_request( data=self.create_segmentio_event_json( name=name, data=input_payload, open_in_browser_url='https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity/2', context={ 'course_id': course_id, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' } }), content_type='application/json' ) User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event_without_payload = { 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': event_type, 'name': name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' } }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, } expected_payload = { 'currentTime': 132.134456, 'id': 'i4x-foo-bar-baz-some_module', 'code': 'mobile' } if name == 'edx.video.loaded': del expected_payload['currentTime'] finally: middleware.process_response(request, None) actual_event = dict(self.get_event()) payload = json.loads(actual_event.pop('event')) self.assertEquals(actual_event, expected_event_without_payload) self.assertEquals(payload, expected_payload)
def test_success(self, course_id): middleware = TrackMiddleware() request = self.create_request(data=self.create_segmentio_event_json( event_type=str(sentinel.event_type), event={'foo': 'bar'}, course_id=course_id), content_type='application/json') User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) # The middleware normally emits an event, make sure it doesn't in this case. self.assertFalse(self.mock_tracker.send.called) # pylint: disable=maybe-no-member try: response = segmentio.track_segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'username': str(sentinel.username), 'ip': '', 'event_source': 'mobile', 'event_type': str(sentinel.event_type), 'name': str(sentinel.name), 'event': { 'foo': 'bar' }, 'agent': str(sentinel.user_agent), 'page': None, 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'unknown', 'version': 'unknown' }, 'userAgent': str(sentinel.user_agent) }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, } finally: middleware.process_response(request, None) self.mock_tracker.send.assert_called_once_with(expected_event) # pylint: disable=maybe-no-member
class TrackMiddlewareTestCase(TestCase): """ Class for checking tracking requests """ def setUp(self): super(TrackMiddlewareTestCase, self).setUp() self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @ddt.unpack @ddt.data( ('HTTP_USER_AGENT', 'agent'), ('PATH_INFO', 'path'), ('HTTP_REFERER', 'referer'), ('HTTP_ACCEPT_LANGUAGE', 'accept_language'), ) def test_request_with_latin1_characters(self, meta_key, context_key): """ When HTTP headers contains latin1 characters. """ request = self.request_factory.get('/somewhere') # pylint: disable=no-member request.META[meta_key] = 'test latin1 \xd3 \xe9 \xf1' # pylint: disable=no-member context = self.get_context_for_request(request) # The bytes in the string on the right are utf8 encoded in the source file, so we decode them to construct # a valid unicode string. self.assertEqual(context[context_key], 'test latin1 Ó é ñ'.decode('utf8')) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path('/courses/') self.assertEquals(context, { 'accept_language': '', 'referer': '', 'user_id': '', 'session': '', 'username': '', 'ip': '127.0.0.1', 'host': 'testserver', 'agent': '', 'path': '/courses/', 'org_id': '', 'course_id': '', 'client_id': None, }) def test_no_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' request.META['REMOTE_ADDR'] = remote_addr context = self.get_context_for_request(request) self.assertEquals(context['ip'], remote_addr) def test_single_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' forwarded_ip = '11.22.33.44' request.META['REMOTE_ADDR'] = remote_addr request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip context = self.get_context_for_request(request) self.assertEquals(context['ip'], forwarded_ip) def test_multiple_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' forwarded_ip = '11.22.33.44, 10.0.0.1, 127.0.0.1' request.META['REMOTE_ADDR'] = remote_addr request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip context = self.get_context_for_request(request) self.assertEquals(context['ip'], '11.22.33.44') def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals( tracker.get_tracker().resolve_context(), {} ) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path('/courses/test_org/test_course/test_run/foo') expected_context_subset = { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', } self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get('/courses/') request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'user_id': user_id, 'username': username, }) def test_request_with_session(self): request = self.request_factory.get('/courses/') SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key expected_session_key = self.track_middleware.encrypt_session_key(session_key) self.assertEquals(len(session_key), len(expected_session_key)) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'session': expected_session_key, }) @override_settings(SECRET_KEY='85920908f28904ed733fe576320db18cabd7b6cd') def test_session_key_encryption(self): session_key = '665924b49a93e22b46ee9365abf28c2a' expected_session_key = '3b81f559d14130180065d635a4f35dd2' encrypted_session_key = self.track_middleware.encrypt_session_key(session_key) self.assertEquals(encrypted_session_key, expected_session_key) def test_request_headers(self): ip_address = '10.0.0.0' user_agent = 'UnitTest/1.0' client_id_header = '123.123' factory = RequestFactory( REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent, HTTP_X_EDX_GA_CLIENT_ID=client_id_header ) request = factory.get('/some-path') context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'ip': ip_address, 'agent': user_agent, 'client_id': client_id_header }) @patch('track.middleware.TRUNCATION_LENGTH', 6) def test_student_answer_request(self): request = self.request_factory.post('/dummy') request.POST = {'student_answer': ['firstanswer', 'secondanswer']} self.track_middleware.process_request(request) event = '{"POST": {"student_answer": ["fir", "sec"]}, "GET": {}}' self.mock_server_track.assert_called_with(request, request.META['PATH_INFO'], event) @patch('track.middleware.TRUNCATION_LENGTH', 20) def test_submission_request(self): request = self.request_factory.post('/dummy') request.POST = {'{"submission":["first open response", "second open response"]}': []} self.track_middleware.process_request(request) event = '{"POST": {"submission": ["first open", "second ope"]}, "GET": {}}' self.mock_server_track.assert_called_with(request, request.META['PATH_INFO'], event)
def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory()
class TrackMiddlewareTestCase(TestCase): def setUp(self): super(TrackMiddlewareTestCase, self).setUp() self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path('/courses/') self.assertEquals( context, { 'accept_language': '', 'referer': '', 'user_id': '', 'session': '', 'username': '', 'ip': '127.0.0.1', 'host': 'testserver', 'agent': '', 'path': '/courses/', 'org_id': '', 'course_id': '', 'client_id': None, }) def test_no_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' request.META['REMOTE_ADDR'] = remote_addr context = self.get_context_for_request(request) self.assertEquals(context['ip'], remote_addr) def test_single_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' forwarded_ip = '11.22.33.44' request.META['REMOTE_ADDR'] = remote_addr request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip context = self.get_context_for_request(request) self.assertEquals(context['ip'], forwarded_ip) def test_multiple_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' forwarded_ip = '11.22.33.44, 10.0.0.1, 127.0.0.1' request.META['REMOTE_ADDR'] = remote_addr request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip context = self.get_context_for_request(request) self.assertEquals(context['ip'], '11.22.33.44') def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals(tracker.get_tracker().resolve_context(), {}) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path( '/courses/test_org/test_course/test_run/foo') expected_context_subset = { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', } self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get('/courses/') request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'user_id': user_id, 'username': username, }) def test_request_with_session(self): request = self.request_factory.get('/courses/') SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key expected_session_key = self.track_middleware.encrypt_session_key( session_key) self.assertEquals(len(session_key), len(expected_session_key)) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'session': expected_session_key, }) @override_settings(SECRET_KEY='85920908f28904ed733fe576320db18cabd7b6cd') def test_session_key_encryption(self): session_key = '665924b49a93e22b46ee9365abf28c2a' expected_session_key = '3b81f559d14130180065d635a4f35dd2' encrypted_session_key = self.track_middleware.encrypt_session_key( session_key) self.assertEquals(encrypted_session_key, expected_session_key) def test_request_headers(self): ip_address = '10.0.0.0' user_agent = 'UnitTest/1.0' client_id_header = '123.123' factory = RequestFactory(REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent, HTTP_X_EDX_GA_CLIENT_ID=client_id_header) request = factory.get('/some-path') context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'ip': ip_address, 'agent': user_agent, 'client_id': client_id_header })
class TrackMiddlewareTestCase(TestCase): def setUp(self): super(TrackMiddlewareTestCase, self).setUp() self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch("track.views.server_track") self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get("/somewhere") self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) def test_default_filters_do_not_render_view(self): for url in ["/event", "/event/1", "/login", "/heartbeat"]: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get("/event") self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r"^/some/excluded.*"]) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get("/excluded") self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get("/some/excluded/url") self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path("/courses/") self.assertEquals( context, { "accept_language": "", "referer": "", "user_id": "", "session": "", "username": "", "ip": "127.0.0.1", "host": "testserver", "agent": "", "path": "/courses/", "org_id": "", "course_id": "", "client_id": None, }, ) def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals(tracker.get_tracker().resolve_context(), {}) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path("/courses/test_org/test_course/test_run/foo") expected_context_subset = {"course_id": "test_org/test_course/test_run", "org_id": "test_org"} self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get("/courses/") request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, {"user_id": user_id, "username": username}) def test_request_with_session(self): request = self.request_factory.get("/courses/") SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key expected_session_key = self.track_middleware.encrypt_session_key(session_key) self.assertEquals(len(session_key), len(expected_session_key)) context = self.get_context_for_request(request) self.assert_dict_subset(context, {"session": expected_session_key}) @override_settings(SECRET_KEY="85920908f28904ed733fe576320db18cabd7b6cd") def test_session_key_encryption(self): session_key = "665924b49a93e22b46ee9365abf28c2a" expected_session_key = "3b81f559d14130180065d635a4f35dd2" encrypted_session_key = self.track_middleware.encrypt_session_key(session_key) self.assertEquals(encrypted_session_key, expected_session_key) def test_request_headers(self): ip_address = "10.0.0.0" user_agent = "UnitTest/1.0" factory = RequestFactory(REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent) request = factory.get("/some-path") context = self.get_context_for_request(request) self.assert_dict_subset(context, {"ip": ip_address, "agent": user_agent})
def test_video_event(self, name, event_type): course_id = 'foo/bar/baz' middleware = TrackMiddleware() input_payload = { 'current_time': 132.134456, 'module_id': 'i4x://foo/bar/baz/some_module', 'code': 'mobile' } if name == 'edx.video.loaded': # We use the same expected payload for all of these types of events, but the load video event is the only # one that is not actually expected to contain a "current time" field. So we remove it from the expected # event here. del input_payload['current_time'] request = self.create_request( data=self.create_segmentio_event_json( name=name, data=input_payload, context={ 'open_in_browser_url': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity/2', 'course_id': course_id, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' } }), content_type='application/json' ) User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'accept_language': '', 'referer': '', 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': event_type, 'name': name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'app': { 'version': '1.0.1', }, }, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, 'event': { 'currentTime': 132.134456, 'id': 'i4x-foo-bar-baz-some_module', 'code': 'mobile' } } if name == 'edx.video.loaded': # We use the same expected payload for all of these types of events, but the load video event is the # only one that is not actually expected to contain a "current time" field. So we remove it from the # expected event here. del expected_event['event']['currentTime'] finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event)
def test_video_event(self, name, event_type): course_id = 'foo/bar/baz' middleware = TrackMiddleware() input_payload = { 'current_time': 132.134456, 'module_id': 'i4x://foo/bar/baz/some_module', 'code': 'mobile' } if name == 'edx.video.loaded': # We use the same expected payload for all of these types of events, but the load video event is the only # one that is not actually expected to contain a "current time" field. So we remove it from the expected # event here. del input_payload['current_time'] request = self.create_request(data=self.create_segmentio_event_json( name=name, data=input_payload, context={ 'open_in_browser_url': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity/2', 'course_id': course_id, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' } }), content_type='application/json') User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'accept_language': '', 'referer': '', 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': event_type, 'name': name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': SEGMENTIO_TEST_USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': SEGMENTIO_TEST_ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'app': { 'version': '1.0.1', }, }, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, 'event': { 'currentTime': 132.134456, 'id': 'i4x-foo-bar-baz-some_module', 'code': 'mobile' } } if name == 'edx.video.loaded': # We use the same expected payload for all of these types of events, but the load video event is the # only one that is not actually expected to contain a "current time" field. So we remove it from the # expected event here. del expected_event['event']['currentTime'] finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event)
def test_previous_builds( self, requested_skip_interval, expected_skip_interval, seek_type_key, seek_type, expected_seek_type, name, expected_name, platform, version, ): """ Test backwards compatibility of previous app builds iOS version 1.0.02: Incorrectly emits the skip back 30 seconds as +30 instead of -30. Android version 1.0.02: Skip and slide were both being returned as a skip. Skip or slide is determined by checking if the skip time is == -30 Additionally, for both of the above mentioned versions, edx.video.seeked was sent instead of edx.video.position.changed """ course_id = 'foo/bar/baz' middleware = TrackMiddleware() input_payload = { "code": "mobile", "new_time": 89.699177437, "old_time": 119.699177437, seek_type_key: seek_type, "requested_skip_interval": requested_skip_interval, 'module_id': 'i4x://foo/bar/baz/some_module', } request = self.create_request(data=self.create_segmentio_event_json( name=name, data=input_payload, context={ 'open_in_browser_url': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity/2', 'course_id': course_id, 'application': { 'name': platform, 'version': version, 'component': 'videoplayer' } }, ), content_type='application/json') User.objects.create(pk=SEGMENTIO_TEST_USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'accept_language': '', 'referer': '', 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': "seek_video", 'name': expected_name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': SEGMENTIO_TEST_USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': SEGMENTIO_TEST_ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'app': { 'version': '1.0.1', }, }, 'application': { 'name': platform, 'version': version, 'component': 'videoplayer' }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, 'event': { "code": "mobile", "new_time": 89.699177437, "old_time": 119.699177437, "type": expected_seek_type, "requested_skip_interval": expected_skip_interval, 'id': 'i4x-foo-bar-baz-some_module', } } finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event)
def test_video_event(self, name, event_type): course_id = 'foo/bar/baz' middleware = TrackMiddleware() input_payload = { 'current_time': 132.134456, 'module_id': 'i4x://foo/bar/baz/some_module', 'code': 'mobile' } if name == 'edx.video.loaded': del input_payload['current_time'] request = self.create_request(data=self.create_segmentio_event_json( name=name, data=input_payload, context={ 'open_in_browser_url': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity/2', 'course_id': course_id, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' } }), content_type='application/json') User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event_without_payload = { 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': event_type, 'name': name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'app': { 'version': '1.0.1', }, }, 'application': { 'name': 'edx.mobileapp.android', 'version': '29', 'component': 'videoplayer' }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, } expected_payload = { 'currentTime': 132.134456, 'id': 'i4x-foo-bar-baz-some_module', 'code': 'mobile' } if name == 'edx.video.loaded': del expected_payload['currentTime'] finally: middleware.process_response(request, None) actual_event = dict(self.get_event()) payload = json.loads(actual_event.pop('event')) self.assertEquals(actual_event, expected_event_without_payload) self.assertEquals(payload, expected_payload)
class TrackMiddlewareTestCase(TestCase): def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_request_in_course_context(self): request = self.request_factory.get('/courses/test_org/test_course/test_run/foo') self.track_middleware.process_request(request) captured_context = tracker.get_tracker().resolve_context() self.track_middleware.process_response(request, None) self.assertEquals( captured_context, { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', 'user_id': '' } ) self.assertEquals( tracker.get_tracker().resolve_context(), {} ) def test_request_with_user(self): request = self.request_factory.get('/courses/') request.user = User(pk=1) self.track_middleware.process_request(request) self.addCleanup(self.track_middleware.process_response, request, None) self.assertEquals( tracker.get_tracker().resolve_context(), { 'course_id': '', 'org_id': '', 'user_id': 1 } )
def test_previous_builds(self, requested_skip_interval, expected_skip_interval, seek_type_key, seek_type, expected_seek_type, name, expected_name, platform, version, ): """ Test backwards compatibility of previous app builds iOS version 1.0.02: Incorrectly emits the skip back 30 seconds as +30 instead of -30. Android version 1.0.02: Skip and slide were both being returned as a skip. Skip or slide is determined by checking if the skip time is == -30 Additionally, for both of the above mentioned versions, edx.video.seeked was sent instead of edx.video.position.changed """ course_id = 'foo/bar/baz' middleware = TrackMiddleware() input_payload = { "code": "mobile", "new_time": 89.699177437, "old_time": 119.699177437, seek_type_key: seek_type, "requested_skip_interval": requested_skip_interval, 'module_id': 'i4x://foo/bar/baz/some_module', } request = self.create_request( data=self.create_segmentio_event_json( name=name, data=input_payload, context={ 'open_in_browser_url': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity/2', 'course_id': course_id, 'application': { 'name': platform, 'version': version, 'component': 'videoplayer' } }, ), content_type='application/json' ) User.objects.create(pk=USER_ID, username=str(sentinel.username)) middleware.process_request(request) try: response = segmentio.segmentio_event(request) self.assertEquals(response.status_code, 200) expected_event = { 'accept_language': '', 'referer': '', 'username': str(sentinel.username), 'ip': '', 'session': '', 'event_source': 'mobile', 'event_type': "seek_video", 'name': expected_name, 'agent': str(sentinel.user_agent), 'page': 'https://testserver/courses/foo/bar/baz/courseware/Week_1/Activity', 'time': datetime.strptime("2014-08-27T16:33:39.215Z", "%Y-%m-%dT%H:%M:%S.%fZ"), 'host': 'testserver', 'context': { 'user_id': USER_ID, 'course_id': course_id, 'org_id': 'foo', 'path': ENDPOINT, 'client': { 'library': { 'name': 'test-app', 'version': 'unknown' }, 'app': { 'version': '1.0.1', }, }, 'application': { 'name': platform, 'version': version, 'component': 'videoplayer' }, 'received_at': datetime.strptime("2014-08-27T16:33:39.100Z", "%Y-%m-%dT%H:%M:%S.%fZ"), }, 'event': { "code": "mobile", "new_time": 89.699177437, "old_time": 119.699177437, "type": expected_seek_type, "requested_skip_interval": expected_skip_interval, 'id': 'i4x-foo-bar-baz-some_module', } } finally: middleware.process_response(request, None) actual_event = self.get_event() assert_event_matches(expected_event, actual_event)
class TrackMiddlewareTestCase(TestCase): def setUp(self): self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path('/courses/') self.assertEquals( context, { 'user_id': '', 'session': '', 'username': '', 'ip': '127.0.0.1', 'host': 'testserver', 'agent': '', 'path': '/courses/', 'org_id': '', 'course_id': '', }) def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals(tracker.get_tracker().resolve_context(), {}) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path( '/courses/test_org/test_course/test_run/foo') expected_context_subset = { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', } self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get('/courses/') request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'user_id': user_id, 'username': username, }) def test_request_with_session(self): request = self.request_factory.get('/courses/') SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'session': session_key, }) def test_request_headers(self): ip_address = '10.0.0.0' user_agent = 'UnitTest/1.0' factory = RequestFactory(REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent) request = factory.get('/some-path') context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'ip': ip_address, 'agent': user_agent, })
class TrackMiddlewareTestCase(TestCase): """ Class for checking tracking requests """ def setUp(self): super(TrackMiddlewareTestCase, self).setUp() self.track_middleware = TrackMiddleware() self.request_factory = RequestFactory() patcher = patch('track.views.server_track') self.mock_server_track = patcher.start() self.addCleanup(patcher.stop) def test_normal_request(self): request = self.request_factory.get('/somewhere') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @ddt.unpack @ddt.data( ('HTTP_USER_AGENT', 'agent'), ('PATH_INFO', 'path'), ('HTTP_REFERER', 'referer'), ('HTTP_ACCEPT_LANGUAGE', 'accept_language'), ) def test_request_with_latin1_characters(self, meta_key, context_key): """ When HTTP headers contains latin1 characters. """ request = self.request_factory.get('/somewhere') # pylint: disable=no-member request.META[meta_key] = 'test latin1 \xd3 \xe9 \xf1' # pylint: disable=no-member context = self.get_context_for_request(request) # The bytes in the string on the right are utf8 encoded in the source file, so we decode them to construct # a valid unicode string. self.assertEqual(context[context_key], 'test latin1 Ó é ñ'.decode('utf8')) def test_default_filters_do_not_render_view(self): for url in ['/event', '/event/1', '/login', '/heartbeat']: request = self.request_factory.get(url) self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) self.mock_server_track.reset_mock() @override_settings(TRACKING_IGNORE_URL_PATTERNS=[]) def test_reading_filtered_urls_from_settings(self): request = self.request_factory.get('/event') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) @override_settings(TRACKING_IGNORE_URL_PATTERNS=[r'^/some/excluded.*']) def test_anchoring_of_patterns_at_beginning(self): request = self.request_factory.get('/excluded') self.track_middleware.process_request(request) self.assertTrue(self.mock_server_track.called) self.mock_server_track.reset_mock() request = self.request_factory.get('/some/excluded/url') self.track_middleware.process_request(request) self.assertFalse(self.mock_server_track.called) def test_default_request_context(self): context = self.get_context_for_path('/courses/') self.assertEquals( context, { 'accept_language': '', 'referer': '', 'user_id': '', 'session': '', 'username': '', 'ip': '127.0.0.1', 'host': 'testserver', 'agent': '', 'path': '/courses/', 'org_id': '', 'course_id': '', 'client_id': None, }) def test_no_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' request.META['REMOTE_ADDR'] = remote_addr context = self.get_context_for_request(request) self.assertEquals(context['ip'], remote_addr) def test_single_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' forwarded_ip = '11.22.33.44' request.META['REMOTE_ADDR'] = remote_addr request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip context = self.get_context_for_request(request) self.assertEquals(context['ip'], forwarded_ip) def test_multiple_forward_for_header_ip_context(self): request = self.request_factory.get('/courses/') remote_addr = '127.0.0.1' forwarded_ip = '11.22.33.44, 10.0.0.1, 127.0.0.1' request.META['REMOTE_ADDR'] = remote_addr request.META['HTTP_X_FORWARDED_FOR'] = forwarded_ip context = self.get_context_for_request(request) self.assertEquals(context['ip'], '11.22.33.44') def get_context_for_path(self, path): """Extract the generated event tracking context for a given request for the given path.""" request = self.request_factory.get(path) return self.get_context_for_request(request) def get_context_for_request(self, request): """Extract the generated event tracking context for the given request.""" self.track_middleware.process_request(request) try: captured_context = tracker.get_tracker().resolve_context() finally: self.track_middleware.process_response(request, None) self.assertEquals(tracker.get_tracker().resolve_context(), {}) return captured_context def test_request_in_course_context(self): captured_context = self.get_context_for_path( '/courses/test_org/test_course/test_run/foo') expected_context_subset = { 'course_id': 'test_org/test_course/test_run', 'org_id': 'test_org', } self.assert_dict_subset(captured_context, expected_context_subset) def assert_dict_subset(self, superset, subset): """Assert that the superset dict contains all of the key-value pairs found in the subset dict.""" for key, expected_value in subset.iteritems(): self.assertEquals(superset[key], expected_value) def test_request_with_user(self): user_id = 1 username = sentinel.username request = self.request_factory.get('/courses/') request.user = User(pk=user_id, username=username) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'user_id': user_id, 'username': username, }) def test_request_with_session(self): request = self.request_factory.get('/courses/') SessionMiddleware().process_request(request) request.session.save() session_key = request.session.session_key expected_session_key = self.track_middleware.encrypt_session_key( session_key) self.assertEquals(len(session_key), len(expected_session_key)) context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'session': expected_session_key, }) @override_settings(SECRET_KEY='85920908f28904ed733fe576320db18cabd7b6cd') def test_session_key_encryption(self): session_key = '665924b49a93e22b46ee9365abf28c2a' expected_session_key = '3b81f559d14130180065d635a4f35dd2' encrypted_session_key = self.track_middleware.encrypt_session_key( session_key) self.assertEquals(encrypted_session_key, expected_session_key) def test_request_headers(self): ip_address = '10.0.0.0' user_agent = 'UnitTest/1.0' client_id_header = '123.123' factory = RequestFactory(REMOTE_ADDR=ip_address, HTTP_USER_AGENT=user_agent, HTTP_X_EDX_GA_CLIENT_ID=client_id_header) request = factory.get('/some-path') context = self.get_context_for_request(request) self.assert_dict_subset(context, { 'ip': ip_address, 'agent': user_agent, 'client_id': client_id_header }) @patch('track.middleware.TRUNCATION_LENGTH', 6) def test_student_answer_request(self): request = self.request_factory.post('/dummy') request.POST = {'student_answer': ['firstanswer', 'secondanswer']} self.track_middleware.process_request(request) event = '{"POST": {"student_answer": ["fir", "sec"]}, "GET": {}}' self.mock_server_track.assert_called_with(request, request.META['PATH_INFO'], event) @patch('track.middleware.TRUNCATION_LENGTH', 20) def test_submission_request(self): request = self.request_factory.post('/dummy') request.POST = { '{"submission":["first open response", "second open response"]}': [] } self.track_middleware.process_request(request) event = '{"POST": {"submission": ["first open", "second ope"]}, "GET": {}}' self.mock_server_track.assert_called_with(request, request.META['PATH_INFO'], event)