Asynchronous download button for ORA2 data

Conflicts:
	lms/djangoapps/instructor/tests/test_api.py
	lms/djangoapps/instructor/utils.py
	lms/djangoapps/instructor/views/api.py
	lms/djangoapps/instructor/views/api_urls.py
	lms/djangoapps/instructor/views/instructor_dashboard.py
	lms/djangoapps/instructor_task/api.py
	lms/djangoapps/instructor_task/tasks.py
	lms/djangoapps/instructor_task/tasks_helper.py
	lms/djangoapps/instructor_task/tests/test_api.py
	lms/djangoapps/instructor_task/tests/test_tasks.py
	lms/djangoapps/instructor_task/tests/test_tasks_helper.py
	lms/envs/aws.py
	lms/envs/common.py
	lms/static/coffee/src/instructor_dashboard/data_download.coffee
	lms/templates/instructor/instructor_dashboard_2/data_download.html
This commit is contained in:
dylanrhodes
2014-11-18 16:13:40 -08:00
committed by Eric Fischer
parent 2c3b728c08
commit 2b1a7eece2
17 changed files with 351 additions and 65 deletions

View File

@@ -1,7 +1,7 @@
"""
Test for LMS instructor background task queue management
"""
from mock import patch, Mock
from mock import patch, Mock, MagicMock
from bulk_email.models import CourseEmail, SEND_TO_ALL
from courseware.tests.factories import UserFactory
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -22,16 +22,20 @@ from instructor_task.api import (
submit_executive_summary_report,
submit_course_survey_report,
generate_certificates_for_students,
regenerate_certificates
regenerate_certificates,
submit_export_ora2_data,
)
from instructor_task.api_helper import AlreadyRunningError
from instructor_task.models import InstructorTask, PROGRESS
from instructor_task.tests.test_base import (InstructorTaskTestCase,
InstructorTaskCourseTestCase,
InstructorTaskModuleTestCase,
TestReportMixin,
TEST_COURSE_KEY)
from instructor_task.tasks import export_ora2_data
from instructor_task.tests.test_base import (
InstructorTaskTestCase,
InstructorTaskCourseTestCase,
InstructorTaskModuleTestCase,
TestReportMixin,
TEST_COURSE_KEY,
)
from certificates.models import CertificateStatuses, CertificateGenerationHistory
@@ -256,6 +260,16 @@ class InstructorTaskCourseSubmitTest(TestReportMixin, InstructorTaskCourseTestCa
)
self._test_resubmission(api_call)
def test_submit_ora2_request_task(self):
request = self.create_task_request(self.instructor)
with patch('instructor_task.api.submit_task') as mock_submit_task:
mock_submit_task.return_value = MagicMock()
submit_export_ora2_data(request, self.course.id)
mock_submit_task.assert_called_once_with(
request, 'export_ora2_data', export_ora2_data, self.course.id, {}, '')
def test_submit_generate_certs_students(self):
"""
Tests certificates generation task submission api

View File

@@ -11,6 +11,8 @@ from uuid import uuid4
from mock import Mock, MagicMock, patch
from celery.states import SUCCESS, FAILURE
from django.utils.translation import ugettext_noop
from functools import partial
from xmodule.modulestore.exceptions import ItemNotFoundError
from opaque_keys.edx.locations import i4xEncoder
@@ -27,8 +29,12 @@ from instructor_task.tasks import (
reset_problem_attempts,
delete_problem_state,
generate_certificates,
export_ora2_data,
)
from instructor_task.tasks_helper import (
UpdateProblemModuleStateError,
upload_ora2_data,
)
from instructor_task.tasks_helper import UpdateProblemModuleStateError
PROBLEM_URL_NAME = "test_urlname"
@@ -471,3 +477,31 @@ class TestCertificateGenerationnstructorTask(TestInstructorTasks):
expected_attempted=1,
expected_total=1
)
class TestOra2ResponsesInstructorTask(TestInstructorTasks):
"""Tests instructor task that fetches ora2 response data."""
def test_ora2_missing_current_task(self):
self._test_missing_current_task(export_ora2_data)
def test_ora2_with_failure(self):
self._test_run_with_failure(export_ora2_data, 'We expected this to fail')
def test_ora2_with_long_error_msg(self):
self._test_run_with_long_error_msg(export_ora2_data)
def test_ora2_with_short_error_msg(self):
self._test_run_with_short_error_msg(export_ora2_data)
def test_ora2_runs_task(self):
task_entry = self._create_input_entry()
task_xmodule_args = self._get_xmodule_instance_args()
with patch('instructor_task.tasks.run_main_task') as mock_main_task:
export_ora2_data(task_entry.id, task_xmodule_args)
action_name = ugettext_noop('generated')
task_fn = partial(upload_ora2_data, task_xmodule_args)
mock_main_task.assert_called_once_with_args(task_entry.id, task_fn, action_name)

View File

@@ -3,10 +3,18 @@
"""
Unit tests for LMS instructor-initiated background tasks helper functions.
Tests that CSV grade report generation works with unicode emails.
- Tests that CSV grade report generation works with unicode emails.
- Tests all of the existing reports.
"""
import os
import shutil
from datetime import datetime
import urllib
import ddt
from freezegun import freeze_time
from mock import Mock, patch
import tempfile
import json
@@ -22,6 +30,15 @@ from course_modes.models import CourseMode
from courseware.tests.factories import InstructorFactory
from instructor_task.tests.test_base import InstructorTaskCourseTestCase, TestReportMixin, InstructorTaskModuleTestCase
from openedx.core.djangoapps.course_groups.models import CourseUserGroupPartitionGroup, CohortMembership
from django.conf import settings
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from pytz import UTC
from xmodule.modulestore.tests.factories import CourseFactory
from student.tests.factories import UserFactory
from student.models import CourseEnrollment
from xmodule.partitions.partitions import Group, UserPartition
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
import openedx.core.djangoapps.user_api.course_tag.api as course_tag_api
from openedx.core.djangoapps.user_api.partition_schemes import RandomUserPartitionScheme
@@ -45,6 +62,9 @@ from instructor_task.tasks_helper import (
upload_exec_summary_report,
upload_course_survey_report,
generate_students_certificates,
upload_ora2_data,
UPDATE_STATUS_FAILED,
UPDATE_STATUS_SUCCEEDED,
)
from instructor_analytics.basic import UNAVAILABLE
from openedx.core.djangoapps.util.testing import ContentGroupTestCase, TestConditionalContent
@@ -2012,3 +2032,56 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
},
result
)
class TestInstructorOra2Report(SharedModuleStoreTestCase):
"""
Tests that ORA2 response report generation works.
"""
@classmethod
def setUpClass(cls):
super(TestInstructorOra2Report, cls).setUpClass()
cls.course = CourseFactory.create()
def setUp(self):
super(TestInstructorOra2Report, self).setUp()
self.current_task = Mock()
self.current_task.update_state = Mock()
def tearDown(self):
super(TestInstructorOra2Report, self).tearDown()
if os.path.exists(settings.GRADES_DOWNLOAD['ROOT_PATH']):
shutil.rmtree(settings.GRADES_DOWNLOAD['ROOT_PATH'])
def test_report_fails_if_error(self):
with patch('instructor_task.tasks_helper.OraAggregateData.collect_ora2_data') as mock_collect_data:
mock_collect_data.side_effect = KeyError
with patch('instructor_task.tasks_helper._get_current_task') as mock_current_task:
mock_current_task.return_value = self.current_task
response = upload_ora2_data(None, None, self.course.id, None, 'generated')
self.assertEqual(response, UPDATE_STATUS_FAILED)
@freeze_time('2001-01-01 00:00:00')
def test_report_stores_results(self):
test_header = ['field1', 'field2']
test_rows = [['row1_field1', 'row1_field2'], ['row2_field1', 'row2_field2']]
with patch('instructor_task.tasks_helper._get_current_task') as mock_current_task:
mock_current_task.return_value = self.current_task
with patch('instructor_task.tasks_helper.OraAggregateData.collect_ora2_data') as mock_collect_data:
mock_collect_data.return_value = (test_header, test_rows)
with patch('instructor_task.models.LocalFSReportStore.store_rows') as mock_store_rows:
return_val = upload_ora2_data(None, None, self.course.id, None, 'generated')
# pylint: disable=maybe-no-member
timestamp_str = datetime.now(UTC).strftime('%Y-%m-%d-%H%M')
course_id_string = urllib.quote(self.course.id.to_deprecated_string().replace('/', '_'))
filename = u'{}_ORA_data_{}.csv'.format(course_id_string, timestamp_str)
self.assertEqual(return_val, UPDATE_STATUS_SUCCEEDED)
mock_store_rows.assert_called_once_with(self.course.id, filename, [test_header] + test_rows)