def test_stale_completion_resolution(self): # Verify that all stale completions get resolved, even if the course # is not present in the modulestore course_key = CourseKey.from_string( 'course-v1:OpenCraft+Onboarding+2018') for user in self.users: StaleCompletion.objects.create(username=user.username, course_key=course_key, block_key='', force=False) StaleCompletion.objects.create(username=user.username, course_key='not/a/course', block_key='', force=False) assert not StaleCompletion.objects.filter(resolved=True).exists() assert StaleCompletion.objects.filter(resolved=False).exists() with compat_patch(course_key): perform_aggregation() assert StaleCompletion.objects.filter(resolved=True).exists() assert not StaleCompletion.objects.filter(resolved=False).exists() for user in self.users: StaleCompletion.objects.create(username=user.username, course_key=course_key, block_key=None, force=False) perform_cleanup() assert not StaleCompletion.objects.filter(resolved=True).exists() assert StaleCompletion.objects.filter(resolved=False).exists()
def test_with_multiple_batches(mock_task, users): course_key = CourseKey.from_string('course-v1:OpenCraft+Onboarding+2018') block_keys = [ course_key.make_usage_key('video', 'video-1'), course_key.make_usage_key('video', 'video-2'), ] for user in users: for block_key in block_keys: BlockCompletion.objects.create( user=user, course_key=course_key, block_key=block_key, completion=1.0, ) perform_aggregation(batch_size=1, limit=2) assert mock_task.call_count == 1 # Order of block_keys is not defined mock_task.call_args[1]['kwargs']['block_keys'] = set( mock_task.call_args[1]['kwargs']['block_keys']) assert mock_task.call_args[1]['kwargs'] == { 'username': users[1].username, 'course_key': six.text_type(course_key), 'block_keys': {six.text_type(key) for key in block_keys}, 'force': False, }
def test_with_no_blocks(mock_task, users): course_key = CourseKey.from_string('course-v1:OpenCraft+Onboarding+2018') StaleCompletion.objects.create(username=users[0].username, course_key=course_key, block_key=None, force=True) perform_aggregation() assert mock_task.call_count == 1
def test_lock(mock_task, users): """Ensure that only one batch aggregation is running at the moment.""" cache.add(settings.COMPLETION_AGGREGATOR_AGGREGATION_LOCK, True, settings.COMPLETION_AGGREGATOR_AGGREGATION_LOCK_TIMEOUT_SECONDS) course_key = CourseKey.from_string('course-v1:OpenCraft+Onboarding+2018') StaleCompletion.objects.create(username=users[0].username, course_key=course_key, block_key=None, force=True) perform_aggregation() cache.delete(settings.COMPLETION_AGGREGATOR_AGGREGATION_LOCK) assert mock_task.call_count == 0
def test_with_full_course_stale_completion(mock_task, users): course_key = CourseKey.from_string('course-v1:OpenCraft+Onboarding+2018') for user in users: StaleCompletion.objects.create( username=user.username, course_key=course_key, block_key=None, ) StaleCompletion.objects.create( username=user.username, course_key=course_key, block_key=course_key.make_usage_key('video', 'how-to-open-craft'), ) perform_aggregation() assert mock_task.call_count == 2 # Called once for each user
def test_basic(self, mock_task): course_key = CourseKey.from_string('edX/test/2018') block_key = UsageKey.from_string('i4x://edX/test/video/friday') completable = BlockCompletion(user=self.user, context_key=course_key, block_key=block_key, completion=1.0, modified=now()) mock_task.reset() completable.save() assert StaleCompletion.objects.filter(username=self.user.username, course_key=course_key, block_key=block_key).exists() mock_task.assert_not_called() perform_aggregation() mock_task.assert_called_once()
def test_with_stale_completions(mock_task, users): course_key = CourseKey.from_string('course-v1:OpenCraft+Onboarding+2018') for user in users: BlockCompletion.objects.create( user=user, course_key=course_key, block_key=course_key.make_usage_key('video', 'how-to-open-craft'), completion=0.75, ) BlockCompletion.objects.create( user=user, course_key=course_key, block_key=course_key.make_usage_key('video', 'how-not-to-open-craft'), completion=1.0, ) perform_aggregation() assert mock_task.call_count == 2 # Called once for each user
def test_stale_completion_resolution(self): course_key = CourseKey.from_string( 'course-v1:OpenCraft+Onboarding+2018') for user in self.users: StaleCompletion.objects.create(username=user.username, course_key=course_key, block_key=None, force=True) assert not StaleCompletion.objects.filter(resolved=True).exists() assert StaleCompletion.objects.filter(resolved=False).exists() with compat_patch(course_key): perform_aggregation() assert StaleCompletion.objects.filter(resolved=True).exists() assert not StaleCompletion.objects.filter(resolved=False).exists() for user in self.users: StaleCompletion.objects.create(username=user.username, course_key=course_key, block_key=None, force=False) perform_cleanup() assert not StaleCompletion.objects.filter(resolved=True).exists() assert StaleCompletion.objects.filter(resolved=False).exists()
def test_plethora_of_stale_completions(users): course_key = CourseKey.from_string('course-v1:OpenCraft+Onboarding+2018') with patch('completion_aggregator.batch.MAX_KEYS_PER_TASK', new=3) as max_keys: for i in range(max_keys + 1): StaleCompletion.objects.create( username=users[0].username, course_key=course_key, block_key=course_key.make_usage_key('chapter', 'chapter-{}'.format(i)), ) with patch( 'completion_aggregator.tasks.aggregation_tasks.update_aggregators.apply_async' ) as mock_task: perform_aggregation() mock_task.assert_called_once_with(kwargs={ 'username': users[0].username, 'course_key': six.text_type(course_key), 'block_keys': [], 'force': False, }, ) assert mock_task.call_count == 1
def test_with_no_completions(mock_task, users): # pylint: disable=unused-argument perform_aggregation() assert mock_task.call_count == 0