From b224f4e8cc44407b814da6cad078b687806ccd55 Mon Sep 17 00:00:00 2001 From: Brian Wilson Date: Tue, 11 Jun 2013 00:51:20 -0400 Subject: [PATCH] move test_tasks to test_integration. --- .../0010_add_courseware_coursetasklog.py | 164 ------------------ lms/djangoapps/courseware/tests/factories.py | 15 -- lms/djangoapps/instructor/views.py | 64 +++---- .../{test_tasks.py => test_integration.py} | 103 +++++------ .../courseware/instructor_dashboard.html | 60 +++---- 5 files changed, 107 insertions(+), 299 deletions(-) delete mode 100644 lms/djangoapps/courseware/migrations/0010_add_courseware_coursetasklog.py rename lms/djangoapps/instructor_task/tests/{test_tasks.py => test_integration.py} (89%) diff --git a/lms/djangoapps/courseware/migrations/0010_add_courseware_coursetasklog.py b/lms/djangoapps/courseware/migrations/0010_add_courseware_coursetasklog.py deleted file mode 100644 index ac933b140a..0000000000 --- a/lms/djangoapps/courseware/migrations/0010_add_courseware_coursetasklog.py +++ /dev/null @@ -1,164 +0,0 @@ -# -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'CourseTask' - db.create_table('courseware_coursetask', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('task_type', self.gf('django.db.models.fields.CharField')(max_length=50, db_index=True)), - ('course_id', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), - ('task_key', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), - ('task_input', self.gf('django.db.models.fields.CharField')(max_length=255)), - ('task_id', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), - ('task_state', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, db_index=True)), - ('task_output', self.gf('django.db.models.fields.CharField')(max_length=1024, null=True)), - ('requester', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), - ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, null=True, blank=True)), - ('updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), - )) - db.send_create_signal('courseware', ['CourseTask']) - - - def backwards(self, orm): - # Deleting model 'CourseTask' - db.delete_table('courseware_coursetask') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'courseware.coursetask': { - 'Meta': {'object_name': 'CourseTask'}, - 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'requester': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'task_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'task_input': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'task_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'task_output': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}), - 'task_state': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'db_index': 'True'}), - 'task_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}), - 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) - }, - 'courseware.offlinecomputedgrade': { - 'Meta': {'unique_together': "(('user', 'course_id'),)", 'object_name': 'OfflineComputedGrade'}, - 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), - 'gradeset': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - }, - 'courseware.offlinecomputedgradelog': { - 'Meta': {'ordering': "['-created']", 'object_name': 'OfflineComputedGradeLog'}, - 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'nstudents': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'seconds': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'courseware.studentmodule': { - 'Meta': {'unique_together': "(('student', 'module_state_key', 'course_id'),)", 'object_name': 'StudentModule'}, - 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'done': ('django.db.models.fields.CharField', [], {'default': "'na'", 'max_length': '8', 'db_index': 'True'}), - 'grade': ('django.db.models.fields.FloatField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'max_grade': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'module_state_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'module_id'", 'db_index': 'True'}), - 'module_type': ('django.db.models.fields.CharField', [], {'default': "'problem'", 'max_length': '32', 'db_index': 'True'}), - 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - }, - 'courseware.studentmodulehistory': { - 'Meta': {'object_name': 'StudentModuleHistory'}, - 'created': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), - 'grade': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'max_grade': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'state': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'student_module': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['courseware.StudentModule']"}), - 'version': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'}) - }, - 'courseware.xmodulecontentfield': { - 'Meta': {'unique_together': "(('definition_id', 'field_name'),)", 'object_name': 'XModuleContentField'}, - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'definition_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'field_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'value': ('django.db.models.fields.TextField', [], {'default': "'null'"}) - }, - 'courseware.xmodulesettingsfield': { - 'Meta': {'unique_together': "(('usage_id', 'field_name'),)", 'object_name': 'XModuleSettingsField'}, - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'field_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'usage_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), - 'value': ('django.db.models.fields.TextField', [], {'default': "'null'"}) - }, - 'courseware.xmodulestudentinfofield': { - 'Meta': {'unique_together': "(('student', 'field_name'),)", 'object_name': 'XModuleStudentInfoField'}, - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'field_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'value': ('django.db.models.fields.TextField', [], {'default': "'null'"}) - }, - 'courseware.xmodulestudentprefsfield': { - 'Meta': {'unique_together': "(('student', 'module_type', 'field_name'),)", 'object_name': 'XModuleStudentPrefsField'}, - 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), - 'field_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}), - 'module_type': ('django.db.models.fields.CharField', [], {'max_length': '64', 'db_index': 'True'}), - 'student': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'value': ('django.db.models.fields.TextField', [], {'default': "'null'"}) - } - } - - complete_apps = ['courseware'] diff --git a/lms/djangoapps/courseware/tests/factories.py b/lms/djangoapps/courseware/tests/factories.py index 75be060366..26df68ca7e 100644 --- a/lms/djangoapps/courseware/tests/factories.py +++ b/lms/djangoapps/courseware/tests/factories.py @@ -10,8 +10,6 @@ from student.tests.factories import CourseEnrollmentAllowedFactory as StudentCou from student.tests.factories import RegistrationFactory as StudentRegistrationFactory from courseware.models import StudentModule, XModuleContentField, XModuleSettingsField from courseware.models import XModuleStudentInfoField, XModuleStudentPrefsField -from courseware.models import CourseTask -from celery.states import PENDING from xmodule.modulestore import Location from pytz import UTC @@ -86,16 +84,3 @@ class StudentInfoFactory(DjangoModelFactory): field_name = 'existing_field' value = json.dumps('old_value') student = SubFactory(UserFactory) - - -class CourseTaskFactory(DjangoModelFactory): - FACTORY_FOR = CourseTask - - task_type = 'rescore_problem' - course_id = "MITx/999/Robot_Super_Course" - task_input = json.dumps({}) - task_key = None - task_id = None - task_state = PENDING - task_output = None - requester = SubFactory(UserFactory) diff --git a/lms/djangoapps/instructor/views.py b/lms/djangoapps/instructor/views.py index d94d31700b..0f9c7e9593 100644 --- a/lms/djangoapps/instructor/views.py +++ b/lms/djangoapps/instructor/views.py @@ -25,7 +25,6 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError from courseware import grades -from instructor_task import api as task_api from courseware.access import (has_access, get_access_group_name, course_beta_test_group_name) from courseware.courses import get_course_with_access @@ -36,6 +35,13 @@ from django_comment_common.models import (Role, FORUM_ROLE_COMMUNITY_TA) from django_comment_client.utils import has_forum_access from instructor.offline_gradecalc import student_grades, offline_grades_available +from instructor_task.api import (get_running_instructor_tasks, + get_instructor_task_history, + submit_rescore_problem_for_all_students, + submit_rescore_problem_for_student, + submit_reset_problem_attempts_for_all_students, + submit_delete_problem_state_for_all_students) +from instructor_task.views import get_task_completion_info from mitxmako.shortcuts import render_to_response from psychometrics import psychoanalyze from student.models import CourseEnrollment, CourseEnrollmentAllowed @@ -69,7 +75,7 @@ def instructor_dashboard(request, course_id): msg = '' problems = [] plots = [] - datatable = None + datatable = {} # the instructor dashboard page is modal: grades, psychometrics, admin # keep that state in request.session (defaults to grades mode) @@ -250,8 +256,8 @@ def instructor_dashboard(request, course_id): problem_urlname = request.POST.get('problem_for_all_students', '') problem_url = get_module_url(problem_urlname) try: - course_task = task_api.submit_rescore_problem_for_all_students(request, course_id, problem_url) - if course_task is None: + instructor_task = submit_rescore_problem_for_all_students(request, course_id, problem_url) + if instructor_task is None: msg += 'Failed to create a background task for rescoring "{0}".'.format(problem_url) else: track_msg = 'rescore problem {problem} for all students in {course}'.format(problem=problem_url, course=course_id) @@ -266,8 +272,8 @@ def instructor_dashboard(request, course_id): problem_urlname = request.POST.get('problem_for_all_students', '') problem_url = get_module_url(problem_urlname) try: - course_task = task_api.submit_reset_problem_attempts_for_all_students(request, course_id, problem_url) - if course_task is None: + instructor_task = submit_reset_problem_attempts_for_all_students(request, course_id, problem_url) + if instructor_task is None: msg += 'Failed to create a background task for resetting "{0}".'.format(problem_url) else: track_msg = 'reset problem {problem} for all students in {course}'.format(problem=problem_url, course=course_id) @@ -288,18 +294,14 @@ def instructor_dashboard(request, course_id): else: problem_urlname = request.POST.get('problem_for_student', '') problem_url = get_module_url(problem_urlname) - message, task_datatable = get_background_task_table(course_id, problem_url, student) + message, datatable = get_background_task_table(course_id, problem_url, student) msg += message - if task_datatable is not None: - datatable = task_datatable elif "Show Background Task History" in action: problem_urlname = request.POST.get('problem_for_all_students', '') problem_url = get_module_url(problem_urlname) - message, task_datatable = get_background_task_table(course_id, problem_url) + message, datatable = get_background_task_table(course_id, problem_url) msg += message - if task_datatable is not None: - datatable = task_datatable elif ("Reset student's attempts" in action or "Delete student state for module" in action or @@ -357,8 +359,8 @@ def instructor_dashboard(request, course_id): else: # "Rescore student's problem submission" case try: - course_task = task_api.submit_rescore_problem_for_student(request, course_id, module_state_key, student) - if course_task is None: + instructor_task = submit_rescore_problem_for_student(request, course_id, module_state_key, student) + if instructor_task is None: msg += 'Failed to create a background task for rescoring "{0}" for student {1}.'.format(module_state_key, unique_student_identifier) else: track_msg = 'rescore problem {problem} for student {student} in {course}'.format(problem=module_state_key, student=unique_student_identifier, course=course_id) @@ -721,13 +723,14 @@ def instructor_dashboard(request, course_id): msg += "
Grades from %s" % offline_grades_available(course_id) # generate list of pending background tasks - if settings.MITX_FEATURES.get('ENABLE_COURSE_BACKGROUND_TASKS'): - course_tasks = task_api.get_running_course_tasks(course_id) + if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'): + instructor_tasks = get_running_instructor_tasks(course_id) else: - course_tasks = None + instructor_tasks = None + # display course stats only if there is no other table to display: course_stats = None - if datatable is None: + if not datatable: course_stats = get_course_stats_table() #---------------------------------------- # context for rendering @@ -744,7 +747,7 @@ def instructor_dashboard(request, course_id): 'problems': problems, # psychometrics 'plots': plots, # psychometrics 'course_errors': modulestore().get_item_errors(course.location), - 'course_tasks': course_tasks, + 'instructor_tasks': instructor_tasks, 'djangopid': os.getpid(), 'mitx_version': getattr(settings, 'MITX_VERSION_STRING', ''), 'offline_grade_log': offline_grades_available(course_id), @@ -1299,8 +1302,8 @@ def get_background_task_table(course_id, problem_url, student=None): Returns a tuple of (msg, datatable), where the msg is a possible error message, and the datatable is the datatable to be used for display. """ - history_entries = task_api.get_instructor_task_history(course_id, problem_url, student) - datatable = None + history_entries = get_instructor_task_history(course_id, problem_url, student) + datatable = {} msg = "" # first check to see if there is any history at all # (note that we don't have to check that the arguments are valid; it @@ -1312,7 +1315,6 @@ def get_background_task_table(course_id, problem_url, student=None): else: msg += 'Failed to find any background tasks for course "{course}" and module "{problem}".'.format(course=course_id, problem=problem_url) else: - datatable = {} datatable['header'] = ["Task Type", "Task Id", "Requester", @@ -1323,23 +1325,23 @@ def get_background_task_table(course_id, problem_url, student=None): "Task Output"] datatable['data'] = [] - for course_task in history_entries: + for instructor_task in history_entries: # get duration info, if known: duration_ms = 'unknown' - if hasattr(course_task, 'task_output'): - task_output = json.loads(course_task.task_output) + if hasattr(instructor_task, 'task_output'): + task_output = json.loads(instructor_task.task_output) if 'duration_ms' in task_output: duration_ms = task_output['duration_ms'] # get progress status message: - success, task_message = task_submit.get_task_completion_info(course_task) + success, task_message = get_task_completion_info(instructor_task) status = "Complete" if success else "Incomplete" # generate row for this task: - row = [str(course_task.task_type), - str(course_task.task_id), - str(course_task.requester), - course_task.created.isoformat(' '), + row = [str(instructor_task.task_type), + str(instructor_task.task_id), + str(instructor_task.requester), + instructor_task.created.isoformat(' '), duration_ms, - str(course_task.task_state), + str(instructor_task.task_state), status, task_message] datatable['data'].append(row) diff --git a/lms/djangoapps/instructor_task/tests/test_tasks.py b/lms/djangoapps/instructor_task/tests/test_integration.py similarity index 89% rename from lms/djangoapps/instructor_task/tests/test_tasks.py rename to lms/djangoapps/instructor_task/tests/test_integration.py index b3552f0239..704cc265a8 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks.py +++ b/lms/djangoapps/instructor_task/tests/test_integration.py @@ -1,5 +1,9 @@ """ -Test for LMS courseware background tasks +Integration Test for LMS instructor-initiated background tasks + +Runs tasks on answers to course problems to validate that code +paths actually work. + """ import logging import json @@ -197,22 +201,8 @@ class TestRescoringBase(LoginEnrollmentTestCase, ModuleStoreTestCase): TestRescoringBase.problem_location(problem_url_name), student) - def _create_course_task(self, task_state="QUEUED", task_input=None, student=None): - """Creates a InstructorTask entry for testing.""" - task_id = str(uuid4()) - task_key = "dummy value" - course_task = InstructorTaskFactory.create(requester=self.instructor, - task_input=json.dumps(task_input), - task_key=task_key, - task_id=task_id, - task_state=task_state) - return course_task - def rescore_all_student_answers(self, instructor, problem_url_name): """Runs the task to rescore the current problem""" -#TODO: fix this... -# task_input = {'problem_url': TestRescoringBase.problem_location(problem_url_name)} -# rescore_problem(entry_id, self.course_id, task_input, xmodule_instance_args) return submit_rescore_problem_for_all_students(self.create_task_request(instructor), self.course.id, TestRescoringBase.problem_location(problem_url_name)) @@ -244,6 +234,13 @@ class TestRescoringBase(LoginEnrollmentTestCase, ModuleStoreTestCase): self.assertGreater(len(state['correct_map']), 0) self.assertGreater(len(state['student_answers']), 0) + def get_task_status(self, task_id): + mock_request = Mock() + mock_request.REQUEST = {'task_id': task_id} + response = instructor_task_status(mock_request) + status = json.loads(response.content) + return status + class TestRescoring(TestRescoringBase): """Test rescoring problems in a background task.""" @@ -306,24 +303,21 @@ class TestRescoring(TestRescoringBase): expected_message = "bad things happened" with patch('capa.capa_problem.LoncapaProblem.rescore_existing_answers') as mock_rescore: mock_rescore.side_effect = ZeroDivisionError(expected_message) - course_task = self.submit_rescore_all_student_answers('instructor', problem_url_name) + instructor_task = self.submit_rescore_all_student_answers('instructor', problem_url_name) - # check task_log returned - self.assertEqual(course_task.task_state, 'FAILURE') - self.assertEqual(course_task.requester.username, 'instructor') - self.assertEqual(course_task.task_type, 'rescore_problem') - task_input = json.loads(course_task.task_input) + # check instructor_task returned + self.assertEqual(instructor_task.task_state, 'FAILURE') + self.assertEqual(instructor_task.requester.username, 'instructor') + self.assertEqual(instructor_task.task_type, 'rescore_problem') + task_input = json.loads(instructor_task.task_input) self.assertFalse('student' in task_input) self.assertEqual(task_input['problem_url'], TestRescoring.problem_location(problem_url_name)) - status = json.loads(course_task.task_output) + status = json.loads(instructor_task.task_output) self.assertEqual(status['exception'], 'ZeroDivisionError') self.assertEqual(status['message'], expected_message) # check status returned: - mock_request = Mock() - mock_request.REQUEST = {'task_id': course_task.task_id} - response = instructor_task_status(mock_request) - status = json.loads(response.content) + status = self.get_task_status(instructor_task.task_id) self.assertEqual(status['message'], expected_message) def test_rescoring_non_problem(self): @@ -364,16 +358,13 @@ class TestRescoring(TestRescoringBase): mock_send_to_queue.return_value = (0, "Successfully queued") self.submit_student_answer('u1', problem_url_name, ["answer1", "answer2"]) - course_task = self.submit_rescore_all_student_answers('instructor', problem_url_name) - self.assertEqual(course_task.task_state, FAILURE) - status = json.loads(course_task.task_output) + instructor_task = self.submit_rescore_all_student_answers('instructor', problem_url_name) + self.assertEqual(instructor_task.task_state, FAILURE) + status = json.loads(instructor_task.task_output) self.assertEqual(status['exception'], 'NotImplementedError') self.assertEqual(status['message'], "Problem's definition does not support rescoring") - mock_request = Mock() - mock_request.REQUEST = {'task_id': course_task.task_id} - response = instructor_task_status(mock_request) - status = json.loads(response.content) + status = self.get_task_status(instructor_task.task_id) self.assertEqual(status['message'], "Problem's definition does not support rescoring") def define_randomized_custom_response_problem(self, problem_url_name, redefine=False): @@ -517,31 +508,28 @@ class TestResetAttempts(TestRescoringBase): expected_message = "bad things happened" with patch('courseware.models.StudentModule.save') as mock_save: mock_save.side_effect = ZeroDivisionError(expected_message) - course_task = self.reset_problem_attempts('instructor', problem_url_name) + instructor_task = self.reset_problem_attempts('instructor', problem_url_name) - # check task_log returned - self.assertEqual(course_task.task_state, FAILURE) - self.assertEqual(course_task.requester.username, 'instructor') - self.assertEqual(course_task.task_type, 'reset_problem_attempts') - task_input = json.loads(course_task.task_input) + # check instructor_task returned + self.assertEqual(instructor_task.task_state, FAILURE) + self.assertEqual(instructor_task.requester.username, 'instructor') + self.assertEqual(instructor_task.task_type, 'reset_problem_attempts') + task_input = json.loads(instructor_task.task_input) self.assertFalse('student' in task_input) self.assertEqual(task_input['problem_url'], TestRescoring.problem_location(problem_url_name)) - status = json.loads(course_task.task_output) + status = json.loads(instructor_task.task_output) self.assertEqual(status['exception'], 'ZeroDivisionError') self.assertEqual(status['message'], expected_message) # check status returned: - mock_request = Mock() - mock_request.REQUEST = {'task_id': course_task.task_id} - response = instructor_task_status(mock_request) - status = json.loads(response.content) + status = self.get_task_status(instructor_task.task_id) self.assertEqual(status['message'], expected_message) def test_reset_non_problem(self): """confirm that a non-problem can still be successfully reset""" problem_url_name = self.problem_section.location.url() - course_task = self.reset_problem_attempts('instructor', problem_url_name) - self.assertEqual(course_task.task_state, SUCCESS) + instructor_task = self.reset_problem_attempts('instructor', problem_url_name) + self.assertEqual(instructor_task.task_state, SUCCESS) def test_reset_nonexistent_problem(self): """confirm that a non-existent problem will not submit""" @@ -595,31 +583,28 @@ class TestDeleteProblem(TestRescoringBase): expected_message = "bad things happened" with patch('courseware.models.StudentModule.delete') as mock_delete: mock_delete.side_effect = ZeroDivisionError(expected_message) - course_task = self.delete_problem_state('instructor', problem_url_name) + instructor_task = self.delete_problem_state('instructor', problem_url_name) - # check task_log returned - self.assertEqual(course_task.task_state, FAILURE) - self.assertEqual(course_task.requester.username, 'instructor') - self.assertEqual(course_task.task_type, 'delete_problem_state') - task_input = json.loads(course_task.task_input) + # check instructor_task returned + self.assertEqual(instructor_task.task_state, FAILURE) + self.assertEqual(instructor_task.requester.username, 'instructor') + self.assertEqual(instructor_task.task_type, 'delete_problem_state') + task_input = json.loads(instructor_task.task_input) self.assertFalse('student' in task_input) self.assertEqual(task_input['problem_url'], TestRescoring.problem_location(problem_url_name)) - status = json.loads(course_task.task_output) + status = json.loads(instructor_task.task_output) self.assertEqual(status['exception'], 'ZeroDivisionError') self.assertEqual(status['message'], expected_message) # check status returned: - mock_request = Mock() - mock_request.REQUEST = {'task_id': course_task.task_id} - response = instructor_task_status(mock_request) - status = json.loads(response.content) + status = self.get_task_status(instructor_task.task_id) self.assertEqual(status['message'], expected_message) def test_delete_non_problem(self): """confirm that a non-problem can still be successfully deleted""" problem_url_name = self.problem_section.location.url() - course_task = self.delete_problem_state('instructor', problem_url_name) - self.assertEqual(course_task.task_state, SUCCESS) + instructor_task = self.delete_problem_state('instructor', problem_url_name) + self.assertEqual(instructor_task.task_state, SUCCESS) def test_delete_nonexistent_module(self): """confirm that a non-existent module will not submit""" diff --git a/lms/templates/courseware/instructor_dashboard.html b/lms/templates/courseware/instructor_dashboard.html index 10b902b904..4c9b4200a2 100644 --- a/lms/templates/courseware/instructor_dashboard.html +++ b/lms/templates/courseware/instructor_dashboard.html @@ -10,13 +10,13 @@ -%if course_tasks is not None: +%if instructor_tasks is not None: @@ -302,7 +302,7 @@ function goto( mode)
%endif - %if settings.MITX_FEATURES.get('ENABLE_COURSE_BACKGROUND_TASKS'): + %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):

Course-specific grade adjustment

@@ -713,13 +713,13 @@ function goto( mode) %for hname in datatable['header']: - + %endfor %for row in datatable['data']: %for value in row: - + %endfor %endfor @@ -729,9 +729,9 @@ function goto( mode) ## Output tasks in progress -%if course_tasks is not None and len(course_tasks) > 0: +%if instructor_tasks is not None and len(instructor_tasks) > 0:
-

Pending Course Tasks

+

Pending Instructor Tasks

${hname}${hname | h}
${value}${value | h}
@@ -744,16 +744,16 @@ function goto( mode) - %for tasknum, course_task in enumerate(course_tasks): + %for tasknum, instructor_task in enumerate(instructor_tasks): - - - - - - + + + + + + @@ -772,11 +772,11 @@ function goto( mode)


-

${course_stats['title']}

+

${course_stats['title'] | h}

Duration (ms) Task Progress
${course_task.task_type}${course_task.task_input}${course_task.task_id}${course_task.requester}${course_task.created}${course_task.task_state}${instructor_task.task_type}${instructor_task.task_input}${instructor_task.task_id}${instructor_task.requester}${instructor_task.created}${instructor_task.task_state} unknown unknown
%for hname in course_stats['header']: - + %endfor %for row in course_stats['data']:
${hname}${hname | h}