Commit d2fcb7b3 by Dennis Jen Committed by GitHub

Added ccx library (#143)

* Refactored tests to use a variety of course IDs using ddt
* Bump versions of opaque keys and ccx libraries
* Added timeout check to see if the elasticsearch index is ready in tests (fixes flaky tests)
parent 75467f6e
......@@ -2,26 +2,18 @@ import json
import StringIO
import csv
from opaque_keys.edx.keys import CourseKey
from rest_framework import status
from analytics_data_api.utils import get_filename_safe_course_id
from analytics_data_api.v0.tests.utils import flatten
DEMO_COURSE_ID = u'course-v1:edX+DemoX+Demo_2014'
SANITIZED_DEMO_COURSE_ID = get_filename_safe_course_id(DEMO_COURSE_ID)
class CourseSamples(object):
class DemoCourseMixin(object):
course_key = None
course_id = None
@classmethod
def setUpClass(cls):
cls.course_id = DEMO_COURSE_ID
cls.course_key = CourseKey.from_string(cls.course_id)
super(DemoCourseMixin, cls).setUpClass()
course_ids = [
'edX/DemoX/Demo_Course',
'course-v1:edX+DemoX+Demo_2014',
'ccx-v1:edx+1.005x-CCX+rerun+ccx@15'
]
class VerifyCourseIdMixin(object):
......
......@@ -12,21 +12,21 @@ from analyticsdataserver.tests import TestCaseWithAuthentication
from analytics_data_api.constants.engagement_events import (ATTEMPTED, COMPLETED, CONTRIBUTED, DISCUSSION,
PROBLEM, VIDEO, VIEWED)
from analytics_data_api.v0 import models
from analytics_data_api.v0.tests.views import DemoCourseMixin, VerifyCourseIdMixin
from analytics_data_api.v0.tests.views import CourseSamples, VerifyCourseIdMixin
@ddt.ddt
class EngagementTimelineTests(DemoCourseMixin, VerifyCourseIdMixin, TestCaseWithAuthentication):
class EngagementTimelineTests(VerifyCourseIdMixin, TestCaseWithAuthentication):
DEFAULT_USERNAME = 'ed_xavier'
path_template = '/api/v0/engagement_timelines/{}/?course_id={}'
def create_engagement(self, entity_type, event_type, entity_id, count, date=None):
def create_engagement(self, course_id, entity_type, event_type, entity_id, count, date=None):
"""Create a ModuleEngagement model"""
if date is None:
date = datetime.datetime(2015, 1, 1, tzinfo=pytz.utc)
G(
models.ModuleEngagement,
course_id=self.course_id,
course_id=course_id,
username=self.DEFAULT_USERNAME,
date=date,
entity_type=entity_type,
......@@ -36,19 +36,19 @@ class EngagementTimelineTests(DemoCourseMixin, VerifyCourseIdMixin, TestCaseWith
)
@ddt.data(
(PROBLEM, ATTEMPTED, 'problems_attempted', True),
(PROBLEM, COMPLETED, 'problems_completed', True),
(VIDEO, VIEWED, 'videos_viewed', True),
(DISCUSSION, CONTRIBUTED, 'discussion_contributions', False),
(CourseSamples.course_ids[0], PROBLEM, ATTEMPTED, 'problems_attempted', True),
(CourseSamples.course_ids[1], PROBLEM, COMPLETED, 'problems_completed', True),
(CourseSamples.course_ids[2], VIDEO, VIEWED, 'videos_viewed', True),
(CourseSamples.course_ids[0], DISCUSSION, CONTRIBUTED, 'discussion_contributions', False),
)
@ddt.unpack
def test_metric_aggregation(self, entity_type, event_type, metric_display_name, expect_id_aggregation):
def test_metric_aggregation(self, course_id, entity_type, event_type, metric_display_name, expect_id_aggregation):
"""
Verify that some metrics are counted by unique ID, while some are
counted by total interactions.
"""
self.create_engagement(entity_type, event_type, 'entity-id', count=5)
self.create_engagement(entity_type, event_type, 'entity-id', count=5)
self.create_engagement(course_id, entity_type, event_type, 'entity-id', count=5)
self.create_engagement(course_id, entity_type, event_type, 'entity-id', count=5)
expected_data = {
'days': [
{
......@@ -64,7 +64,7 @@ class EngagementTimelineTests(DemoCourseMixin, VerifyCourseIdMixin, TestCaseWith
expected_data['days'][0][metric_display_name] = 1
else:
expected_data['days'][0][metric_display_name] = 10
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(self.course_id))
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(course_id))
response = self.authenticated_get(path)
self.assertEquals(response.status_code, 200)
self.assertEquals(
......@@ -72,20 +72,21 @@ class EngagementTimelineTests(DemoCourseMixin, VerifyCourseIdMixin, TestCaseWith
expected_data
)
def test_timeline(self):
@ddt.data(*CourseSamples.course_ids)
def test_timeline(self, course_id):
"""
Smoke test the learner engagement timeline.
"""
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(self.course_id))
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(course_id))
day_one = datetime.datetime(2015, 1, 1, tzinfo=pytz.utc)
day_two = datetime.datetime(2015, 1, 2, tzinfo=pytz.utc)
self.create_engagement(PROBLEM, ATTEMPTED, 'id-1', count=100, date=day_one)
self.create_engagement(PROBLEM, COMPLETED, 'id-2', count=12, date=day_one)
self.create_engagement(DISCUSSION, CONTRIBUTED, 'id-3', count=6, date=day_one)
self.create_engagement(DISCUSSION, CONTRIBUTED, 'id-4', count=10, date=day_two)
self.create_engagement(VIDEO, VIEWED, 'id-5', count=44, date=day_two)
self.create_engagement(PROBLEM, ATTEMPTED, 'id-6', count=8, date=day_two)
self.create_engagement(PROBLEM, ATTEMPTED, 'id-7', count=4, date=day_two)
self.create_engagement(course_id, PROBLEM, ATTEMPTED, 'id-1', count=100, date=day_one)
self.create_engagement(course_id, PROBLEM, COMPLETED, 'id-2', count=12, date=day_one)
self.create_engagement(course_id, DISCUSSION, CONTRIBUTED, 'id-3', count=6, date=day_one)
self.create_engagement(course_id, DISCUSSION, CONTRIBUTED, 'id-4', count=10, date=day_two)
self.create_engagement(course_id, VIDEO, VIEWED, 'id-5', count=44, date=day_two)
self.create_engagement(course_id, PROBLEM, ATTEMPTED, 'id-6', count=8, date=day_two)
self.create_engagement(course_id, PROBLEM, ATTEMPTED, 'id-7', count=4, date=day_two)
response = self.authenticated_get(path)
self.assertEquals(response.status_code, 200)
expected = {
......@@ -108,12 +109,13 @@ class EngagementTimelineTests(DemoCourseMixin, VerifyCourseIdMixin, TestCaseWith
}
self.assertEquals(response.data, expected)
def test_day_gap(self):
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(self.course_id))
@ddt.data(*CourseSamples.course_ids)
def test_day_gap(self, course_id):
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(course_id))
first_day = datetime.datetime(2015, 5, 26, tzinfo=pytz.utc)
last_day = datetime.datetime(2015, 5, 28, tzinfo=pytz.utc)
self.create_engagement(VIDEO, VIEWED, 'id-1', count=1, date=first_day)
self.create_engagement(PROBLEM, ATTEMPTED, entity_id='id-2', count=1, date=last_day)
self.create_engagement(course_id, VIDEO, VIEWED, 'id-1', count=1, date=first_day)
self.create_engagement(course_id, PROBLEM, ATTEMPTED, entity_id='id-2', count=1, date=last_day)
response = self.authenticated_get(path)
self.assertEquals(response.status_code, 200)
expected = {
......@@ -143,14 +145,15 @@ class EngagementTimelineTests(DemoCourseMixin, VerifyCourseIdMixin, TestCaseWith
}
self.assertEquals(response.data, expected)
def test_not_found(self):
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(self.course_id))
@ddt.data(*CourseSamples.course_ids)
def test_not_found(self, course_id):
path = self.path_template.format(self.DEFAULT_USERNAME, urlquote(course_id))
response = self.authenticated_get(path)
self.assertEquals(response.status_code, status.HTTP_404_NOT_FOUND)
expected = {
u"error_code": u"no_learner_engagement_timeline",
u"developer_message": u"Learner {} engagement timeline not found for course {}.".format(
self.DEFAULT_USERNAME, self.course_id)
self.DEFAULT_USERNAME, course_id)
}
self.assertDictEqual(json.loads(response.content), expected)
......
boto==2.42.0 # MIT
Django==1.9.9 # BSD License
django-countries==4.0 # MIT
django-model-utils==2.5.2 # BSD
djangorestframework==3.4.6 # BSD
django-rest-swagger==0.3.8 # BSD
djangorestframework-csv==1.4.1 # BSD
django-countries==4.0 # MIT
edx-django-release-util==0.1.2
django-storages==1.4.1 # BSD
elasticsearch-dsl==0.0.11 # Apache 2.0
ordered-set==2.0.1 # MIT
# markdown is used by swagger for rendering the api docs
Markdown==2.6.6 # BSD
-e git+https://github.com/edx/opaque-keys.git@d45d0bd8d64c69531be69178b9505b5d38806ce0#egg=opaque-keys
django-storages==1.4.1 # BSD
edx-ccx-keys==0.2.1
edx-django-release-util==0.1.2
edx-opaque-keys==0.4.0
# Test dependencies go here.
-r base.txt
coverage==4.2
ddt==1.1.0
ddt==1.1.1
diff-cover >= 0.9.9
django-dynamic-fixture==1.9.0
django-nose==1.4.4
......
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