def test_students_one_page(self): course_offering = CourseOfferingFactory(start_date=self.course_offering.start_date, no_weeks=2) course_offering.owners.add(self.user) self.api_url = reverse('olap:communication_students', kwargs={'course_id': course_offering.id}) # Two pages, two users page1 = PageFactory(course_offering=course_offering, content_type='resource/x-bb-discussionboard') page2 = PageFactory(course_offering=course_offering, content_type='resource/x-bb-discussionboard') lms_user1 = LMSUserFactory(course_offering=course_offering) lms_user2 = LMSUserFactory(course_offering=course_offering) # 2 pages and 2 weeks gives a 2x2 grid. # Top left: 1xU1, 2xU2 visit_dt = self.course_offering.start_datetime + datetime.timedelta(days=3) visit = PageVisitFactory(page=page1, lms_user=lms_user1, visited_at=visit_dt) visit = PageVisitFactory(page=page1, lms_user=lms_user2, visited_at=visit_dt) visit = PageVisitFactory(page=page2, lms_user=lms_user2, visited_at=visit_dt) # Top right: 1xU1 visit_dt = self.course_offering.start_datetime + datetime.timedelta(days=10) visit = PageVisitFactory(page=page1, lms_user=lms_user1, visited_at=visit_dt) # Bottom left: 1xU2 visit_dt = self.course_offering.start_datetime + datetime.timedelta(days=5) visit = PageVisitFactory(page=page2, lms_user=lms_user2, visited_at=visit_dt) # Nothing in bottom right # Call the API endpoint response = self.client.get(self.api_url) self.assertEqual(response.status_code, HTTP_200_OK) expected = { 'pageSet': [ { 'id': page1.id, 'title': page1.title, 'content_type': page1.content_type, 'weeks': [2, 1], 'total': 2, 'percent': 100.0, # 100% of users interacted with this page }, { 'id': page2.id, 'title': page2.title, 'content_type': page2.content_type, 'weeks': [1, 0], 'total': 1, 'percent': 50.0, # 50% of users (u2) interacted with this page }, ], 'totalsByWeek': [ 2, # 2 users (u1, u2) viewed the two pages in week 1 1, # 1 users viewed the two pages in week 2 2, ], } response_dict = json.loads(response.content.decode('utf-8')) self.assertEqual(response_dict, expected)
def test_only_include_pages_for_a_given_user(self): # Have four pages split across two users. Make sure the calculated sessions for both users are correct, # especially the aspect that visits due to one user are ignored when calculating the session for another user. u1 = LMSUserFactory(course_offering=self.offering) u1_p1 = PageFactory() u1_p2 = PageFactory() u2 = LMSUserFactory(course_offering=self.offering) u2_p1 = PageFactory() u2_p2 = PageFactory() orphan = PageFactory() # Visits for u1 which should result in a session starting at test_start_dt, lasting 25 mins u1_expected_session_start_dt = self.test_start_datetime v_u1_p1 = PageVisitFactory(lms_user=u1, page=u1_p1, visited_at=u1_expected_session_start_dt) v_u1_p2 = PageVisitFactory(lms_user=u1, page=u1_p2, visited_at=u1_expected_session_start_dt + datetime.timedelta(minutes=25)) # Visits for u2 which should result in a session starting at test_start_dt+10mins, and lasting 21 mins u2_expected_session_start_dt = self.test_start_datetime + datetime.timedelta( minutes=10) v_u2_p1 = PageVisitFactory(lms_user=u2, page=u2_p1, visited_at=u2_expected_session_start_dt) v_u2_p2 = PageVisitFactory(lms_user=u2, page=u2_p2, visited_at=u2_expected_session_start_dt + datetime.timedelta(minutes=21)) importer = ImportLmsData(self.offering, 'ignore.txt') importer._calculate_sessions() sessions = LMSSession.objects.all() session_info_extractor = lambda s: ( s.first_visit.lms_user, s.first_visit.visited_at, s. session_length_in_mins, s.pageviews) extracted_session_info = tuple( session_info_extractor(session) for session in sessions) expected_session_info = ( (u1, u1_expected_session_start_dt, 25, 2), (u2, u2_expected_session_start_dt, 21, 2), ) self.assertEqual(expected_session_info, extracted_session_info)
def test_accesses_one_page(self): self.api_url = reverse('olap:communication_accesses', kwargs={'course_id': self.course_offering.id}) page = PageFactory(course_offering=self.course_offering, content_type='course/x-bb-collabsession') # For this one page, generate one visit per week for the duration of the course for week_no in range(self.course_offering.no_weeks): week_start_dt = self.course_offering.start_datetime + datetime.timedelta(weeks=week_no) week_end_dt = week_start_dt + datetime.timedelta(days=7) visit_dt = fuzzy.FuzzyDateTime(week_start_dt, week_end_dt) visit = PageVisitFactory(page=page, module='course/x-bb-collabsession', lms_user=self.lms_user, visited_at=visit_dt) # Call the API endpoint response = self.client.get(self.api_url) self.assertEqual(response.status_code, HTTP_200_OK) totals = [1] * self.course_offering.no_weeks # One visit per week totals.append(self.course_offering.no_weeks) # Add a final number for the total visits expected = { 'pageSet': [ { # These keys aren't getting camel cased. No idea why. 'id': page.id, 'title': page.title, 'content_type': page.content_type, 'weeks': [1] * self.course_offering.no_weeks, # One visit per week 'total': self.course_offering.no_weeks, # One visit per week 'percent': 100.0, }, ], 'totalsByWeek': totals, } response_dict = json.loads(response.content.decode('utf-8')) self.assertEqual(response_dict, expected)
def test_multiusers_same_pages(self): # Have two users accessing almost the same pages. Make sure the sessions calculated for both users include # the common pages, and the distinct ones. u1 = LMSUserFactory(course_offering=self.offering) u2 = LMSUserFactory(course_offering=self.offering) pre_page = PageFactory() common_visit_pages = PageFactory.create_batch(3) post_page = PageFactory() user_visit_info = { u1.pk: ((-2, pre_page), (0, common_visit_pages[0]), (15, common_visit_pages[1]), (30, common_visit_pages[2]), (39, post_page)), u2.pk: ( (-1, pre_page), (5, common_visit_pages[0]), (25, common_visit_pages[1]), (45, common_visit_pages[2]), (89, post_page), ) } for user_pk, visit_list in user_visit_info.items(): user = LMSUser.objects.get(pk=user_pk) for visit_offset_mins, page in visit_list: visit_obj = PageVisitFactory( lms_user=user, page=page, visited_at=self.test_start_datetime + datetime.timedelta(minutes=visit_offset_mins)) importer = ImportLmsData(self.offering, 'ignore.txt') importer._calculate_sessions() sessions = LMSSession.objects.all() session_info_extractor = lambda s: ( s.first_visit.lms_user, s.first_visit.visited_at, s. session_length_in_mins, s.pageviews) extracted_session_info = tuple( session_info_extractor(session) for session in sessions) expected_session_info = ( (u1, self.test_start_datetime + datetime.timedelta(minutes=-2), 41, 5), (u2, self.test_start_datetime + datetime.timedelta(minutes=-1), 46, 4), (u2, self.test_start_datetime + datetime.timedelta(minutes=89), 0, 1), ) self.assertEqual(expected_session_info, extracted_session_info)
def events_setUp(self): self.course_offering_start = datetime.datetime(2016, 2, 1, 8, 0, 10, tzinfo=self.our_tz) # Mon assert self.course_offering_start.weekday() == 0 # Date chosen to be a monday. Test won't work otherwise. course_offering = CourseOfferingFactory(start_date=self.course_offering_start, no_weeks=2) course_offering.owners.add(self.user) self.page = PageFactory(course_offering=course_offering, content_type='resource/x-bb-discussionboard') visit_dt = self.course_offering_start + datetime.timedelta(days=3) # Thu visit = PageVisitFactory(page=self.page, lms_user=self.lms_user, visited_at=visit_dt) # Default to Monday, but each test will change this to each side of the page visit self.repeating_event = CourseRepeatingEventFactory(course_offering=course_offering, start_week=1, end_week=2, day_of_week=0) self.api_url = reverse('olap:communication_events', kwargs={'course_id': course_offering.id, 'event_id': self.repeating_event.id})
def test_accesses_shedload_of_pages(self): self.api_url = reverse('olap:communication_accesses', kwargs={'course_id': self.course_offering.id}) NR_PAGES = 5 NR_PAGEVISITS = 100 all_pages = PageFactory.create_batch(NR_PAGES, course_offering=self.course_offering, content_type='course/x-bb-collabsession') # Pick a random page, and create a visit to that page. for visit in range(NR_PAGEVISITS): end_dt = self.course_offering.start_datetime + datetime.timedelta(weeks=self.course_offering.no_weeks) random_visit_dt = fuzzy.FuzzyDateTime(self.course_offering.start_datetime, end_dt) random_page = all_pages[random.randint(0, NR_PAGES - 1)] visit = PageVisitFactory(page=random_page, module='course/x-bb-collabsession', lms_user=self.lms_user, visited_at=random_visit_dt) # Call the API endpoint response = self.client.get(self.api_url) self.assertEqual(response.status_code, HTTP_200_OK) response_dict = json.loads(response.content.decode('utf-8')) # FIXME: This could be greatly expanded to check the numbers in the response. self.assertEqual(len(response_dict), 2) self.assertIn('pageSet', response_dict) self.assertIn('totalsByWeek', response_dict) page_set = response_dict['pageSet'] self.assertEqual(len(page_set), NR_PAGES)
def test_events_one_page_view_before_event_in_week1_one_page_view_after_event_in_week2(self): self.events_setUp() # At this moment, we have one visit on the Thursday of the first week. This will make the visit before # the event (Friday) self.repeating_event.day_of_week = 4 # Every friday self.repeating_event.save() # Now create a second visit that's on the Saturday of week 2. This will make the visit after the event. visit2_dt = self.course_offering_start + datetime.timedelta(weeks=1, days=5) # Sat visit2 = PageVisitFactory(page=self.page, lms_user=self.lms_user, visited_at=visit2_dt) response = self.client.get(self.api_url) self.assertEqual(response.status_code, HTTP_200_OK) expected = [ { 'id': self.page.id, 'title': self.page.title, 'contentType': self.page.content_type, 'weeks': [[1, 0], [0, 1]], } ] response_dict = json.loads(response.content.decode('utf-8')) self.assertEqual(response_dict, expected)
def test_session_calculation(self): mins_in_24h10m = 24 * 60 + 10 cases = ( # PageVisit t= Inputs # Expected session starts, durations and pageviews ((), []), # No visits => no sessions ((0, ), [(0, 0, 1)]), # One visit => one session of 0 mins ((0, 20), [(0, 20, 2) ]), # Two visits 20m apart => one session of 20 mins ((0, 50), [(0, 0, 1), (50, 0, 1) ]), # Two visits 50m apart => two sessions of 0 mins ((0, 20, 30), [ (0, 30, 3) ]), # Three visits 20 then 10 mins apart => one session of 30 mins ((0, 20, 50), [ (0, 50, 3) ]), # Three visits 20 then 30 mins apart => one session of 50 mins ((0, 40, 80), [ (0, 80, 3) ]), # Three visits 40 then 40 mins apart => one session of 80 mins ((0, 40, 90), [ (0, 40, 2), (90, 0, 1) ]), # Three visits 40 then 50 mins apart => two sessions ((0, mins_in_24h10m), [ (0, 0, 1), (mins_in_24h10m, 0, 1) ]), # Two visits 1d10m apart => two sessions ) lms_user = LMSUserFactory(course_offering=self.offering) page = PageFactory() importer = ImportLmsData(self.offering, 'ignore.txt') for visit_event_times, expected_outputs in cases: # Erase results from last case PageVisit.objects.all().delete() LMSSession.objects.all().delete() # Turn tuple of time-in-minutes between views, into a tuple of visit datetimes visit_datetimes = (self.test_start_datetime + datetime.timedelta(minutes=int(m)) for m in visit_event_times) # Create the series of visits, spaced apart by the event times for dt in visit_datetimes: visit = PageVisitFactory(lms_user=lms_user, page=page, visited_at=dt) # Run the session calculator importer.calculate_session_for_user(lms_user) # Analyse the sessions created by the calculator, and turn the start time, duration and pageviews into # tuples for comparison against the expected result actual_outputs = [] for session in LMSSession.objects.all(): session_start_timedelta = session.first_visit.visited_at - self.test_start_datetime session_start_time_in_mins = int( session_start_timedelta.total_seconds() / 60) actual_outputs.append( (session_start_time_in_mins, session.session_length_in_mins, session.pageviews)) # Now that we've assembled tuples of session starts, durations and pageviews, do they match what we expect? self.assertEqual(expected_outputs, actual_outputs)