diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index 293c49c556..9d80d29bd1 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -3,6 +3,7 @@ Modulestore configuration for test cases. """ import datetime +import functools import pytz from uuid import uuid4 @@ -220,7 +221,8 @@ class SharedModuleStoreTestCase(TestCase): Subclass for any test case that uses a ModuleStore that can be shared between individual tests. This class ensures that the ModuleStore is cleaned before/after the entire test case has run. Use this class if your tests - set up one or a small number of courses that individual tests do not modify. + set up one or a small number of courses that individual tests do not modify + (or modify extermely rarely -- see @modifies_courseware). If your tests modify contents in the ModuleStore, you should use ModuleStoreTestCase instead. @@ -279,6 +281,52 @@ class SharedModuleStoreTestCase(TestCase): OverrideFieldData.provider_classes = None super(SharedModuleStoreTestCase, self).setUp() + def reset(self): + """ + Manually run tearDownClass/setUpClass again. + + This is so that if you have a mostly read-only course that you're just + modifying in one test, you can write `self.reset()` at the + end of that test and reset the state of the world for other tests in + the class. + """ + self.tearDownClass() + self.setUpClass() + + @staticmethod + def modifies_courseware(f): + """ + Decorator to place around tests that modify course content. + + For performance reasons, SharedModuleStoreTestCase intentionally does + not reset the modulestore between individual tests. However, sometimes + you might have a test case where the vast majority of tests treat a + course as read-only, but one or two want to modify it. In that case, you + can do this: + + class MyTestCase(SharedModuleStoreTestCase): + # ... + @SharedModuleStoreTestCase.modifies_courseware + def test_that_edits_modulestore(self): + do_something() + + This is equivalent to calling `self.reset()` at the end of + your test. + + If you find yourself using this functionality a lot, it might indicate + that you should be using ModuleStoreTestCase instead, or that you should + break up your tests into different TestCases. + """ + @functools.wraps(f) + def wrapper(*args, **kwargs): + """Call the object method, and reset the test case afterwards.""" + return_val = f(*args, **kwargs) + obj = args[0] + obj.reset() + return return_val + + return wrapper + class ModuleStoreTestCase(TestCase): """ diff --git a/lms/djangoapps/instructor/tests/test_access.py b/lms/djangoapps/instructor/tests/test_access.py index 7ddbd7233e..f66d3957a0 100644 --- a/lms/djangoapps/instructor/tests/test_access.py +++ b/lms/djangoapps/instructor/tests/test_access.py @@ -6,7 +6,7 @@ from nose.tools import raises from nose.plugins.attrib import attr from student.tests.factories import UserFactory from xmodule.modulestore.tests.factories import CourseFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from student.roles import CourseBetaTesterRole, CourseStaffRole @@ -19,13 +19,15 @@ from instructor.access import (allow_access, @attr('shard_1') -class TestInstructorAccessList(ModuleStoreTestCase): +class TestInstructorAccessList(SharedModuleStoreTestCase): """ Test access listings. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAccessList, cls).setUpClass() + cls.course = CourseFactory.create() + def setUp(self): super(TestInstructorAccessList, self).setUp() - - self.course = CourseFactory.create() - self.instructors = [UserFactory.create() for _ in xrange(4)] for user in self.instructors: allow_access(self.course, user, 'instructor') @@ -43,8 +45,13 @@ class TestInstructorAccessList(ModuleStoreTestCase): @attr('shard_1') -class TestInstructorAccessAllow(ModuleStoreTestCase): +class TestInstructorAccessAllow(SharedModuleStoreTestCase): """ Test access allow. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAccessAllow, cls).setUpClass() + cls.course = CourseFactory.create() + def setUp(self): super(TestInstructorAccessAllow, self).setUp() @@ -79,13 +86,15 @@ class TestInstructorAccessAllow(ModuleStoreTestCase): @attr('shard_1') -class TestInstructorAccessRevoke(ModuleStoreTestCase): +class TestInstructorAccessRevoke(SharedModuleStoreTestCase): """ Test access revoke. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAccessRevoke, cls).setUpClass() + cls.course = CourseFactory.create() + def setUp(self): super(TestInstructorAccessRevoke, self).setUp() - - self.course = CourseFactory.create() - self.staff = [UserFactory.create() for _ in xrange(4)] for user in self.staff: allow_access(self.course, user, 'staff') @@ -115,15 +124,17 @@ class TestInstructorAccessRevoke(ModuleStoreTestCase): @attr('shard_1') -class TestInstructorAccessForum(ModuleStoreTestCase): +class TestInstructorAccessForum(SharedModuleStoreTestCase): """ Test forum access control. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAccessForum, cls).setUpClass() + cls.course = CourseFactory.create() + def setUp(self): super(TestInstructorAccessForum, self).setUp() - - self.course = CourseFactory.create() - self.mod_role = Role.objects.create( course_id=self.course.id, name=FORUM_ROLE_MODERATOR diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 1703ae7960..9dfc50f26e 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -51,7 +51,7 @@ from student.tests.factories import UserFactory, CourseModeFactory, AdminFactory from student.roles import CourseBetaTesterRole, CourseSalesAdminRole, CourseFinanceAdminRole, CourseInstructorRole from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.fields import Date @@ -184,22 +184,26 @@ class TestCommonExceptions400(TestCase): @attr('shard_1') @patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message')) @patch.dict(settings.FEATURES, {'ENABLE_INSTRUCTOR_EMAIL': True, 'REQUIRE_COURSE_EMAIL_AUTH': False}) -class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPIDenyLevels(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Ensure that users cannot access endpoints they shouldn't be able to. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPIDenyLevels, cls).setUpClass() + cls.course = CourseFactory.create() + cls.problem_location = msk_from_problem_urlname( + cls.course.id, + 'robot-some-problem-urlname' + ) + cls.problem_urlname = cls.problem_location.to_deprecated_string() + def setUp(self): super(TestInstructorAPIDenyLevels, self).setUp() - self.course = CourseFactory.create() self.user = UserFactory.create() CourseEnrollment.enroll(self.user, self.course.id) - self.problem_location = msk_from_problem_urlname( - self.course.id, - 'robot-some-problem-urlname' - ) - self.problem_urlname = self.problem_location.to_deprecated_string() _module = StudentModule.objects.create( student=self.user, course_id=self.course.id, @@ -347,18 +351,22 @@ class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase): @attr('shard_1') @patch.dict(settings.FEATURES, {'ALLOW_AUTOMATED_SIGNUPS': True}) -class TestInstructorAPIBulkAccountCreationAndEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPIBulkAccountCreationAndEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test Bulk account creation and enrollment from csv file """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPIBulkAccountCreationAndEnrollment, cls).setUpClass() + cls.course = CourseFactory.create() + cls.url = reverse('register_and_enroll_students', kwargs={'course_id': cls.course.id.to_deprecated_string()}) + def setUp(self): super(TestInstructorAPIBulkAccountCreationAndEnrollment, self).setUp() self.request = RequestFactory().request() - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') - self.url = reverse('register_and_enroll_students', kwargs={'course_id': self.course.id.to_deprecated_string()}) self.not_enrolled_student = UserFactory( username='NotEnrolledStudent', @@ -647,7 +655,7 @@ class TestInstructorAPIBulkAccountCreationAndEnrollment(ModuleStoreTestCase, Log @attr('shard_1') @ddt.ddt -class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPIEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test enrollment modification endpoint. @@ -655,11 +663,23 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): job of test_enrollment. This tests the response and action switch. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPIEnrollment, cls).setUpClass() + cls.course = CourseFactory.create() + + # Email URL values + cls.site_name = microsite.get_value( + 'SITE_NAME', + settings.SITE_NAME + ) + cls.about_path = '/courses/{}/about'.format(cls.course.id) + cls.course_path = '/courses/{}/'.format(cls.course.id) + def setUp(self): super(TestInstructorAPIEnrollment, self).setUp() self.request = RequestFactory().request() - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') @@ -679,14 +699,6 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): self.notregistered_email = 'robot-not-an-email-yet@robot.org' self.assertEqual(User.objects.filter(email=self.notregistered_email).count(), 0) - # Email URL values - self.site_name = microsite.get_value( - 'SITE_NAME', - settings.SITE_NAME - ) - self.about_path = '/courses/{}/about'.format(self.course.id) - self.course_path = '/courses/{}/'.format(self.course.id) - # uncomment to enable enable printing of large diffs # from failed assertions in the event of a test failure. # (comment because pylint C0103(invalid-name)) @@ -1399,15 +1411,25 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): @attr('shard_1') @ddt.ddt -class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test bulk beta modify access endpoint. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPIBulkBetaEnrollment, cls).setUpClass() + cls.course = CourseFactory.create() + # Email URL values + cls.site_name = microsite.get_value( + 'SITE_NAME', + settings.SITE_NAME + ) + cls.about_path = '/courses/{}/about'.format(cls.course.id) + cls.course_path = '/courses/{}/'.format(cls.course.id) def setUp(self): super(TestInstructorAPIBulkBetaEnrollment, self).setUp() - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') @@ -1425,14 +1447,6 @@ class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTe self.request = RequestFactory().request() - # Email URL values - self.site_name = microsite.get_value( - 'SITE_NAME', - settings.SITE_NAME - ) - self.about_path = '/courses/{}/about'.format(self.course.id) - self.course_path = '/courses/{}/'.format(self.course.id) - # uncomment to enable enable printing of large diffs # from failed assertions in the event of a test failure. # (comment because pylint C0103(invalid-name)) @@ -1720,7 +1734,7 @@ class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTe @attr('shard_1') -class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPILevelsAccess(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints whereby instructors can change permissions of other users. @@ -1731,11 +1745,14 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase Actually, modify_access does not have a very meaningful response yet, so only the status code is tested. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPILevelsAccess, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(TestInstructorAPILevelsAccess, self).setUp() - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') @@ -1961,14 +1978,17 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase @attr('shard_1') @ddt.ddt @patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True}) -class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints that show data without side effects. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPILevelsDataDump, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(TestInstructorAPILevelsDataDump, self).setUp() - self.course = CourseFactory.create() self.course_mode = CourseMode(course_id=self.course.id, mode_slug="honor", mode_display_name="honor cert", @@ -2539,9 +2559,11 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa body = response.content.replace('\r', '') self.assertTrue(body.startswith( '"User ID","Anonymized User ID","Course Specific Anonymized User ID"' - '\n"3","41","42"\n' + '\n"{user_id}","41","42"\n'.format(user_id=self.students[0].id) )) - self.assertTrue(body.endswith('"8","41","42"\n')) + self.assertTrue( + body.endswith('"{user_id}","41","42"\n'.format(user_id=self.students[-1].id)) + ) def test_list_report_downloads(self): url = reverse('list_report_downloads', kwargs={'course_id': self.course.id.to_deprecated_string()}) @@ -2664,7 +2686,7 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa @attr('shard_1') -class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints whereby instructors can change student grades. This includes resetting attempts and starting rescore tasks. @@ -2672,23 +2694,24 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) This test does NOT test whether the actions had an effect on the database, that is the job of task tests and test_enrollment. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPIRegradeTask, cls).setUpClass() + cls.course = CourseFactory.create() + cls.problem_location = msk_from_problem_urlname( + cls.course.id, + 'robot-some-problem-urlname' + ) + cls.problem_urlname = cls.problem_location.to_deprecated_string() def setUp(self): super(TestInstructorAPIRegradeTask, self).setUp() - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') self.student = UserFactory() CourseEnrollment.enroll(self.student, self.course.id) - self.problem_location = msk_from_problem_urlname( - self.course.id, - 'robot-some-problem-urlname' - ) - - self.problem_urlname = self.problem_location.to_deprecated_string() - self.module_to_reset = StudentModule.objects.create( student=self.student, course_id=self.course.id, @@ -2827,21 +2850,51 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) @attr('shard_1') @patch.dict(settings.FEATURES, {'ENTRANCE_EXAMS': True}) -class TestEntranceExamInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestEntranceExamInstructorAPIRegradeTask(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints whereby instructors can rescore student grades, reset student attempts and delete state for entrance exam. """ - - def setUp(self): - super(TestEntranceExamInstructorAPIRegradeTask, self).setUp() - self.course = CourseFactory.create( + @classmethod + def setUpClass(cls): + super(TestEntranceExamInstructorAPIRegradeTask, cls).setUpClass() + cls.course = CourseFactory.create( org='test_org', course='test_course', run='test_run', entrance_exam_id='i4x://{}/{}/chapter/Entrance_exam'.format('test_org', 'test_course') ) - self.course_with_invalid_ee = CourseFactory.create(entrance_exam_id='invalid_exam') + cls.course_with_invalid_ee = CourseFactory.create(entrance_exam_id='invalid_exam') + + with cls.store.bulk_operations(cls.course.id, emit_signals=False): + cls.entrance_exam = ItemFactory.create( + parent=cls.course, + category='chapter', + display_name='Entrance exam' + ) + subsection = ItemFactory.create( + parent=cls.entrance_exam, + category='sequential', + display_name='Subsection 1' + ) + vertical = ItemFactory.create( + parent=subsection, + category='vertical', + display_name='Vertical 1' + ) + cls.ee_problem_1 = ItemFactory.create( + parent=vertical, + category="problem", + display_name="Exam Problem - Problem 1" + ) + cls.ee_problem_2 = ItemFactory.create( + parent=vertical, + category="problem", + display_name="Exam Problem - Problem 2" + ) + + def setUp(self): + super(TestEntranceExamInstructorAPIRegradeTask, self).setUp() self.instructor = InstructorFactory(course_key=self.course.id) # Add instructor to invalid ee course @@ -2851,32 +2904,6 @@ class TestEntranceExamInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollm self.student = UserFactory() CourseEnrollment.enroll(self.student, self.course.id) - self.entrance_exam = ItemFactory.create( - parent=self.course, - category='chapter', - display_name='Entrance exam' - ) - subsection = ItemFactory.create( - parent=self.entrance_exam, - category='sequential', - display_name='Subsection 1' - ) - vertical = ItemFactory.create( - parent=subsection, - category='vertical', - display_name='Vertical 1' - ) - self.ee_problem_1 = ItemFactory.create( - parent=vertical, - category="problem", - display_name="Exam Problem - Problem 1" - ) - self.ee_problem_2 = ItemFactory.create( - parent=vertical, - category="problem", - display_name="Exam Problem - Problem 2" - ) - ee_module_to_reset1 = StudentModule.objects.create( student=self.student, course_id=self.course.id, @@ -3073,27 +3100,30 @@ class TestEntranceExamInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollm @attr('shard_1') @patch('bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message')) @patch.dict(settings.FEATURES, {'ENABLE_INSTRUCTOR_EMAIL': True, 'REQUIRE_COURSE_EMAIL_AUTH': False}) -class TestInstructorSendEmail(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorSendEmail(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Checks that only instructors have access to email endpoints, and that these endpoints are only accessible with courses that actually exist, only with valid email messages. """ - - def setUp(self): - super(TestInstructorSendEmail, self).setUp() - - self.course = CourseFactory.create() - self.instructor = InstructorFactory(course_key=self.course.id) - self.client.login(username=self.instructor.username, password='test') + @classmethod + def setUpClass(cls): + super(TestInstructorSendEmail, cls).setUpClass() + cls.course = CourseFactory.create() test_subject = u'\u1234 test subject' test_message = u'\u6824 test message' - self.full_test_message = { + cls.full_test_message = { 'send_to': 'staff', 'subject': test_subject, 'message': test_message, } + def setUp(self): + super(TestInstructorSendEmail, self).setUp() + + self.instructor = InstructorFactory(course_key=self.course.id) + self.client.login(username=self.instructor.username, password='test') + def test_send_email_as_logged_in_instructor(self): url = reverse('send_email', kwargs={'course_id': self.course.id.to_deprecated_string()}) response = self.client.post(url, self.full_test_message) @@ -3156,7 +3186,7 @@ class MockCompletionInfo(object): @attr('shard_1') -class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorAPITaskLists(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test instructor task list endpoint. """ @@ -3204,23 +3234,26 @@ class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase): attr_dict['created'] = attr_dict['created'].isoformat() return attr_dict - def setUp(self): - super(TestInstructorAPITaskLists, self).setUp() - self.course = CourseFactory.create( + @classmethod + def setUpClass(cls): + super(TestInstructorAPITaskLists, cls).setUpClass() + cls.course = CourseFactory.create( entrance_exam_id='i4x://{}/{}/chapter/Entrance_exam'.format('test_org', 'test_course') ) + cls.problem_location = msk_from_problem_urlname( + cls.course.id, + 'robot-some-problem-urlname' + ) + cls.problem_urlname = cls.problem_location.to_deprecated_string() + + def setUp(self): + super(TestInstructorAPITaskLists, self).setUp() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') self.student = UserFactory() CourseEnrollment.enroll(self.student, self.course.id) - self.problem_location = msk_from_problem_urlname( - self.course.id, - 'robot-some-problem-urlname' - ) - self.problem_urlname = self.problem_location.to_deprecated_string() - self.module = StudentModule.objects.create( student=self.student, course_id=self.course.id, @@ -3316,15 +3349,18 @@ class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase): @attr('shard_1') @patch.object(instructor_task.api, 'get_instructor_task_history') -class TestInstructorEmailContentList(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorEmailContentList(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test the instructor email content history endpoint. """ + @classmethod + def setUpClass(cls): + super(TestInstructorEmailContentList, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(TestInstructorEmailContentList, self).setUp() - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') self.tasks = {} @@ -3500,10 +3536,30 @@ def get_extended_due(course, unit, user): @attr('shard_1') -class TestDueDateExtensions(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestDueDateExtensions(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Test data dumps for reporting. """ + @classmethod + def setUpClass(cls): + super(TestDueDateExtensions, cls).setUpClass() + cls.course = CourseFactory.create() + cls.due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) + + with cls.store.bulk_operations(cls.course.id, emit_signals=False): + cls.week1 = ItemFactory.create(due=cls.due) + cls.week2 = ItemFactory.create(due=cls.due) + cls.week3 = ItemFactory.create() # No due date + cls.course.children = [ + cls.week1.location.to_deprecated_string(), + cls.week2.location.to_deprecated_string(), + cls.week3.location.to_deprecated_string() + ] + cls.homework = ItemFactory.create( + parent_location=cls.week1.location, + due=cls.due + ) + cls.week1.children = [cls.homework.location.to_deprecated_string()] def setUp(self): """ @@ -3511,75 +3567,55 @@ class TestDueDateExtensions(ModuleStoreTestCase, LoginEnrollmentTestCase): """ super(TestDueDateExtensions, self).setUp() - due = datetime.datetime(2010, 5, 12, 2, 42, tzinfo=utc) - course = CourseFactory.create() - week1 = ItemFactory.create(due=due) - week2 = ItemFactory.create(due=due) - week3 = ItemFactory.create() # No due date - course.children = [week1.location.to_deprecated_string(), week2.location.to_deprecated_string(), - week3.location.to_deprecated_string()] - - homework = ItemFactory.create( - parent_location=week1.location, - due=due - ) - week1.children = [homework.location.to_deprecated_string()] - user1 = UserFactory.create() StudentModule( state='{}', student_id=user1.id, - course_id=course.id, - module_state_key=week1.location).save() + course_id=self.course.id, + module_state_key=self.week1.location).save() StudentModule( state='{}', student_id=user1.id, - course_id=course.id, - module_state_key=week2.location).save() + course_id=self.course.id, + module_state_key=self.week2.location).save() StudentModule( state='{}', student_id=user1.id, - course_id=course.id, - module_state_key=week3.location).save() + course_id=self.course.id, + module_state_key=self.week3.location).save() StudentModule( state='{}', student_id=user1.id, - course_id=course.id, - module_state_key=homework.location).save() + course_id=self.course.id, + module_state_key=self.homework.location).save() user2 = UserFactory.create() StudentModule( state='{}', student_id=user2.id, - course_id=course.id, - module_state_key=week1.location).save() + course_id=self.course.id, + module_state_key=self.week1.location).save() StudentModule( state='{}', student_id=user2.id, - course_id=course.id, - module_state_key=homework.location).save() + course_id=self.course.id, + module_state_key=self.homework.location).save() user3 = UserFactory.create() StudentModule( state='{}', student_id=user3.id, - course_id=course.id, - module_state_key=week1.location).save() + course_id=self.course.id, + module_state_key=self.week1.location).save() StudentModule( state='{}', student_id=user3.id, - course_id=course.id, - module_state_key=homework.location).save() + course_id=self.course.id, + module_state_key=self.homework.location).save() - self.course = course - self.week1 = week1 - self.homework = homework - self.week2 = week2 - self.week3 = week3 self.user1 = user1 self.user2 = user2 - - self.instructor = InstructorFactory(course_key=course.id) + self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') def test_change_due_date(self): @@ -3640,6 +3676,7 @@ class TestDueDateExtensions(ModuleStoreTestCase, LoginEnrollmentTestCase): }) self.assertEqual(response.status_code, 400, response.content) + @SharedModuleStoreTestCase.modifies_courseware def test_reset_extension_to_deleted_date(self): """ Test that we can delete a due date extension after deleting the normal @@ -3690,10 +3727,18 @@ class TestDueDateExtensions(ModuleStoreTestCase, LoginEnrollmentTestCase): @attr('shard_1') @override_settings(REGISTRATION_CODE_LENGTH=8) -class TestCourseRegistrationCodes(ModuleStoreTestCase): +class TestCourseRegistrationCodes(SharedModuleStoreTestCase): """ Test data dumps for E-commerce Course Registration Codes. """ + @classmethod + def setUpClass(cls): + super(TestCourseRegistrationCodes, cls).setUpClass() + cls.course = CourseFactory.create() + cls.url = reverse( + 'generate_registration_codes', + kwargs={'course_id': cls.course.id.to_deprecated_string()} + ) def setUp(self): """ @@ -3701,15 +3746,11 @@ class TestCourseRegistrationCodes(ModuleStoreTestCase): """ super(TestCourseRegistrationCodes, self).setUp() - self.course = CourseFactory.create() CourseModeFactory.create(course_id=self.course.id, min_price=50) self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') CourseSalesAdminRole(self.course.id).add_users(self.instructor) - url = reverse('generate_registration_codes', - kwargs={'course_id': self.course.id.to_deprecated_string()}) - data = { 'total_registration_codes': 12, 'company_name': 'Test Group', 'company_contact_name': 'Test@company.com', 'company_contact_email': 'Test@company.com', 'unit_price': 122.45, 'recipient_name': 'Test123', @@ -3718,7 +3759,7 @@ class TestCourseRegistrationCodes(ModuleStoreTestCase): 'customer_reference_number': '123A23F', 'internal_reference': '', 'invoice': '' } - response = self.client.post(url, data, **{'HTTP_HOST': 'localhost'}) + response = self.client.post(self.url, data, **{'HTTP_HOST': 'localhost'}) self.assertEqual(response.status_code, 200, response.content) for i in range(5): order = Order(user=self.instructor, status='purchased') @@ -4148,13 +4189,17 @@ class TestCourseRegistrationCodes(ModuleStoreTestCase): @attr('shard_1') -class TestBulkCohorting(ModuleStoreTestCase): +class TestBulkCohorting(SharedModuleStoreTestCase): """ Test adding users to cohorts in bulk via CSV upload. """ + @classmethod + def setUpClass(cls): + super(TestBulkCohorting, cls).setUpClass() + cls.course = CourseFactory.create() + def setUp(self): super(TestBulkCohorting, self).setUp() - self.course = CourseFactory.create() self.staff_user = StaffFactory(course_key=self.course.id) self.non_staff_user = UserFactory.create() self.tempdir = tempfile.mkdtemp() diff --git a/lms/djangoapps/instructor/tests/test_api_email_localization.py b/lms/djangoapps/instructor/tests/test_api_email_localization.py index d9fd87df93..ca0fd14ff7 100644 --- a/lms/djangoapps/instructor/tests/test_api_email_localization.py +++ b/lms/djangoapps/instructor/tests/test_api_email_localization.py @@ -13,15 +13,19 @@ from student.models import CourseEnrollment from student.tests.factories import UserFactory from openedx.core.djangoapps.user_api.preferences.api import set_user_preference from xmodule.modulestore.tests.factories import CourseFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase @attr('shard_1') -class TestInstructorAPIEnrollmentEmailLocalization(ModuleStoreTestCase): +class TestInstructorAPIEnrollmentEmailLocalization(SharedModuleStoreTestCase): """ Test whether the enroll, unenroll and beta role emails are sent in the proper language, i.e: the student's language. """ + @classmethod + def setUpClass(cls): + super(TestInstructorAPIEnrollmentEmailLocalization, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(TestInstructorAPIEnrollmentEmailLocalization, self).setUp() @@ -29,7 +33,6 @@ class TestInstructorAPIEnrollmentEmailLocalization(ModuleStoreTestCase): # Platform language is English, instructor's language is Chinese, # student's language is French, so the emails should all be sent in # French. - self.course = CourseFactory.create() self.instructor = InstructorFactory(course_key=self.course.id) set_user_preference(self.instructor, LANGUAGE_KEY, 'zh-cn') self.client.login(username=self.instructor.username, password='test') diff --git a/lms/djangoapps/instructor/tests/test_certificates.py b/lms/djangoapps/instructor/tests/test_certificates.py index 7bf5b7fd3b..027c15671d 100644 --- a/lms/djangoapps/instructor/tests/test_certificates.py +++ b/lms/djangoapps/instructor/tests/test_certificates.py @@ -8,7 +8,7 @@ from nose.plugins.attrib import attr from django.core.urlresolvers import reverse from django.test.utils import override_settings from django.conf import settings -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from config_models.models import cache from courseware.tests.factories import GlobalStaffFactory, InstructorFactory, UserFactory @@ -18,19 +18,23 @@ from certificates import api as certs_api @attr('shard_1') @ddt.ddt -class CertificatesInstructorDashTest(ModuleStoreTestCase): +class CertificatesInstructorDashTest(SharedModuleStoreTestCase): """Tests for the certificate panel of the instructor dash. """ ERROR_REASON = "An error occurred!" DOWNLOAD_URL = "http://www.example.com/abcd123/cert.pdf" + @classmethod + def setUpClass(cls): + super(CertificatesInstructorDashTest, cls).setUpClass() + cls.course = CourseFactory.create() + cls.url = reverse( + 'instructor_dashboard', + kwargs={'course_id': unicode(cls.course.id)} + ) + def setUp(self): super(CertificatesInstructorDashTest, self).setUp() - self.course = CourseFactory.create() - self.url = reverse( - 'instructor_dashboard', - kwargs={'course_id': unicode(self.course.id)} - ) self.global_staff = GlobalStaffFactory() self.instructor = InstructorFactory(course_key=self.course.id) @@ -189,12 +193,15 @@ class CertificatesInstructorDashTest(ModuleStoreTestCase): @attr('shard_1') @override_settings(CERT_QUEUE='certificates') @ddt.ddt -class CertificatesInstructorApiTest(ModuleStoreTestCase): +class CertificatesInstructorApiTest(SharedModuleStoreTestCase): """Tests for the certificates end-points in the instructor dash API. """ + @classmethod + def setUpClass(cls): + super(CertificatesInstructorApiTest, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(CertificatesInstructorApiTest, self).setUp() - self.course = CourseFactory.create() self.global_staff = GlobalStaffFactory() self.instructor = InstructorFactory(course_key=self.course.id) diff --git a/lms/djangoapps/instructor/tests/test_ecommerce.py b/lms/djangoapps/instructor/tests/test_ecommerce.py index 7fb4f895ac..4297d09cad 100644 --- a/lms/djangoapps/instructor/tests/test_ecommerce.py +++ b/lms/djangoapps/instructor/tests/test_ecommerce.py @@ -13,18 +13,26 @@ from course_modes.models import CourseMode from student.roles import CourseFinanceAdminRole from shoppingcart.models import Coupon, CourseRegistrationCode from student.tests.factories import AdminFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @attr('shard_1') -class TestECommerceDashboardViews(ModuleStoreTestCase): +class TestECommerceDashboardViews(SharedModuleStoreTestCase): """ Check for E-commerce view on the new instructor dashboard """ + @classmethod + def setUpClass(cls): + super(TestECommerceDashboardViews, cls).setUpClass() + cls.course = CourseFactory.create() + + # URL for instructor dash + cls.url = reverse('instructor_dashboard', kwargs={'course_id': cls.course.id.to_deprecated_string()}) + cls.e_commerce_link = 'E-Commerce' + def setUp(self): super(TestECommerceDashboardViews, self).setUp() - self.course = CourseFactory.create() # Create instructor account self.instructor = AdminFactory.create() @@ -34,9 +42,6 @@ class TestECommerceDashboardViews(ModuleStoreTestCase): mode_display_name='honor', min_price=10, currency='usd' ) mode.save() - # URL for instructor dash - self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()}) - self.e_commerce_link = 'E-Commerce' CourseFinanceAdminRole(self.course.id).add_users(self.instructor) def test_pass_e_commerce_tab_in_instructor_dashboard(self): diff --git a/lms/djangoapps/instructor/tests/test_email.py b/lms/djangoapps/instructor/tests/test_email.py index d18e9f403a..7f1bc0633f 100644 --- a/lms/djangoapps/instructor/tests/test_email.py +++ b/lms/djangoapps/instructor/tests/test_email.py @@ -11,30 +11,36 @@ from nose.plugins.attrib import attr from opaque_keys.edx.locations import SlashSeparatedCourseKey from bulk_email.models import CourseAuthorization -from xmodule.modulestore.tests.django_utils import TEST_DATA_MIXED_TOY_MODULESTORE, ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ( + TEST_DATA_MIXED_TOY_MODULESTORE, SharedModuleStoreTestCase +) from student.tests.factories import AdminFactory from xmodule.modulestore.tests.factories import CourseFactory @attr('shard_1') -class TestNewInstructorDashboardEmailViewMongoBacked(ModuleStoreTestCase): +class TestNewInstructorDashboardEmailViewMongoBacked(SharedModuleStoreTestCase): """ Check for email view on the new instructor dashboard for Mongo-backed courses """ + @classmethod + def setUpClass(cls): + super(TestNewInstructorDashboardEmailViewMongoBacked, cls).setUpClass() + cls.course = CourseFactory.create() + + # URL for instructor dash + cls.url = reverse('instructor_dashboard', kwargs={'course_id': cls.course.id.to_deprecated_string()}) + # URL for email view + cls.email_link = 'Email' + def setUp(self): super(TestNewInstructorDashboardEmailViewMongoBacked, self).setUp() - self.course = CourseFactory.create() # Create instructor account instructor = AdminFactory.create() self.client.login(username=instructor.username, password="test") - # URL for instructor dash - self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()}) - # URL for email view - self.email_link = 'Email' - # In order for bulk email to work, we must have both the ENABLE_INSTRUCTOR_EMAIL_FLAG # set to True and for the course to be Mongo-backed. # The flag is enabled and the course is Mongo-backed (should work) @@ -101,16 +107,25 @@ class TestNewInstructorDashboardEmailViewMongoBacked(ModuleStoreTestCase): @attr('shard_1') -class TestNewInstructorDashboardEmailViewXMLBacked(ModuleStoreTestCase): +class TestNewInstructorDashboardEmailViewXMLBacked(SharedModuleStoreTestCase): """ Check for email view on the new instructor dashboard """ MODULESTORE = TEST_DATA_MIXED_TOY_MODULESTORE + @classmethod + def setUpClass(cls): + super(TestNewInstructorDashboardEmailViewXMLBacked, cls).setUpClass() + cls.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall') + + # URL for instructor dash + cls.url = reverse('instructor_dashboard', kwargs={'course_id': cls.course_key.to_deprecated_string()}) + # URL for email view + cls.email_link = 'Email' + def setUp(self): super(TestNewInstructorDashboardEmailViewXMLBacked, self).setUp() - self.course_key = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall') # Create instructor account instructor = AdminFactory.create() diff --git a/lms/djangoapps/instructor/tests/test_enrollment.py b/lms/djangoapps/instructor/tests/test_enrollment.py index 1a6e3d268e..c20bc98777 100644 --- a/lms/djangoapps/instructor/tests/test_enrollment.py +++ b/lms/djangoapps/instructor/tests/test_enrollment.py @@ -30,7 +30,7 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey from submissions import api as sub_api from student.models import anonymous_id_for_user -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase @attr('shard_1') @@ -296,40 +296,40 @@ class TestInstructorUnenrollDB(TestEnrollmentChangeBase): @attr('shard_1') -class TestInstructorEnrollmentStudentModule(ModuleStoreTestCase): +class TestInstructorEnrollmentStudentModule(SharedModuleStoreTestCase): """ Test student module manipulations. """ - def setUp(self): - super(TestInstructorEnrollmentStudentModule, self).setUp() - store = modulestore() - self.user = UserFactory() - self.course = CourseFactory( + @classmethod + def setUpClass(cls): + super(TestInstructorEnrollmentStudentModule, cls).setUpClass() + cls.course = CourseFactory( name='fake', org='course', run='id', ) # pylint: disable=no-member - self.course_key = self.course.location.course_key - self.parent = ItemFactory( - category="library_content", - user_id=self.user.id, - parent=self.course, - publish_item=True, - modulestore=store, - ) - self.child = ItemFactory( - category="html", - user_id=self.user.id, - parent=self.parent, - publish_item=True, - modulestore=store, - ) - self.unrelated = ItemFactory( - category="html", - user_id=self.user.id, - parent=self.course, - publish_item=True, - modulestore=store, - ) + cls.course_key = cls.course.location.course_key + with cls.store.bulk_operations(cls.course.id, emit_signals=False): + cls.parent = ItemFactory( + category="library_content", + parent=cls.course, + publish_item=True, + ) + cls.child = ItemFactory( + category="html", + parent=cls.parent, + publish_item=True, + ) + cls.unrelated = ItemFactory( + category="html", + parent=cls.course, + publish_item=True, + ) + + def setUp(self): + super(TestInstructorEnrollmentStudentModule, self).setUp() + + self.user = UserFactory() + parent_state = json.dumps({'attempts': 32, 'otherstuff': 'alsorobots'}) child_state = json.dumps({'attempts': 10, 'whatever': 'things'}) unrelated_state = json.dumps({'attempts': 12, 'brains': 'zombie'}) @@ -567,26 +567,27 @@ class TestSendBetaRoleEmail(TestCase): @attr('shard_1') -class TestGetEmailParams(ModuleStoreTestCase): +class TestGetEmailParams(SharedModuleStoreTestCase): """ Test what URLs the function get_email_params returns under different production-like conditions. """ - def setUp(self): - super(TestGetEmailParams, self).setUp() - - self.course = CourseFactory.create() + @classmethod + def setUpClass(cls): + super(TestGetEmailParams, cls).setUpClass() + cls.course = CourseFactory.create() # Explicitly construct what we expect the course URLs to be site = settings.SITE_NAME - self.course_url = u'https://{}/courses/{}/'.format( - site, - self.course.id.to_deprecated_string() - ) - self.course_about_url = self.course_url + 'about' - self.registration_url = u'https://{}/register'.format( + cls.course_url = u'https://{}/courses/{}/'.format( site, + cls.course.id.to_deprecated_string() ) + cls.course_about_url = cls.course_url + 'about' + cls.registration_url = u'https://{}/register'.format(site) + + def setUp(self): + super(TestGetEmailParams, self).setUp() def test_normal_params(self): # For a normal site, what do we expect to get for the URLs? @@ -612,16 +613,19 @@ class TestGetEmailParams(ModuleStoreTestCase): @attr('shard_1') -class TestRenderMessageToString(ModuleStoreTestCase): +class TestRenderMessageToString(SharedModuleStoreTestCase): """ Test that email templates can be rendered in a language chosen manually. """ + @classmethod + def setUpClass(cls): + super(TestRenderMessageToString, cls).setUpClass() + cls.course = CourseFactory.create() + cls.subject_template = 'emails/enroll_email_allowedsubject.txt' + cls.message_template = 'emails/enroll_email_allowedmessage.txt' def setUp(self): super(TestRenderMessageToString, self).setUp() - self.subject_template = 'emails/enroll_email_allowedsubject.txt' - self.message_template = 'emails/enroll_email_allowedmessage.txt' - self.course = CourseFactory.create() def get_email_params(self): """ diff --git a/lms/djangoapps/instructor/tests/test_hint_manager.py b/lms/djangoapps/instructor/tests/test_hint_manager.py index 5ce0e7e325..39e9dbc06c 100644 --- a/lms/djangoapps/instructor/tests/test_hint_manager.py +++ b/lms/djangoapps/instructor/tests/test_hint_manager.py @@ -8,14 +8,21 @@ from courseware.models import XModuleUserStateSummaryField from courseware.tests.factories import UserStateSummaryFactory import instructor.hint_manager as view from student.tests.factories import UserFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory # pylint: disable=missing-docstring @attr('shard_1') -class HintManagerTest(ModuleStoreTestCase): +class HintManagerTest(SharedModuleStoreTestCase): + @classmethod + def setUpClass(cls): + super(HintManagerTest, cls).setUpClass() + cls.course = CourseFactory.create(org='Me', number='19.002', display_name='test_course') + cls.url = '/courses/Me/19.002/test_course/hint_manager' + cls.course_id = cls.course.id + cls.problem_id = cls.course_id.make_usage_key('crowdsource_hinter', 'crowdsource_hinter_001') def setUp(self): """ @@ -24,13 +31,9 @@ class HintManagerTest(ModuleStoreTestCase): """ super(HintManagerTest, self).setUp() - self.course = CourseFactory.create(org='Me', number='19.002', display_name='test_course') - self.url = '/courses/Me/19.002/test_course/hint_manager' self.user = UserFactory.create(username='robot', email='robot@edx.org', password='test', is_staff=True) self.c = Client() self.c.login(username='robot', password='test') - self.course_id = self.course.id - self.problem_id = self.course_id.make_usage_key('crowdsource_hinter', 'crowdsource_hinter_001') UserStateSummaryFactory.create( field_name='hints', usage_id=self.problem_id, diff --git a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py index 314185bcdd..e7ed19ae73 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py +++ b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py @@ -12,7 +12,7 @@ from django.core.urlresolvers import reverse from courseware.tests.helpers import LoginEnrollmentTestCase from xmodule.modulestore.tests.factories import CourseFactory from student.tests.factories import UserFactory, CourseEnrollmentFactory, AdminFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from student.models import CourseEnrollment, CourseEnrollmentAllowed from instructor.views.legacy import get_and_clean_student_list, send_mail_to_student from django.core import mail @@ -22,10 +22,14 @@ USER_COUNT = 4 @attr('shard_1') @ddt.ddt -class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase): +class TestInstructorEnrollsStudent(SharedModuleStoreTestCase, LoginEnrollmentTestCase): """ Check Enrollment/Unenrollment with/without auto-enrollment on activation and with/without email notification """ + @classmethod + def setUpClass(cls): + super(TestInstructorEnrollsStudent, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(TestInstructorEnrollsStudent, self).setUp() @@ -33,8 +37,6 @@ class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase) instructor = AdminFactory.create() self.client.login(username=instructor.username, password='test') - self.course = CourseFactory.create() - self.users = [ UserFactory.create(username="student%d" % i, email="student%d@test.com" % i) for i in xrange(USER_COUNT) diff --git a/lms/djangoapps/instructor/tests/test_legacy_xss.py b/lms/djangoapps/instructor/tests/test_legacy_xss.py index ff541ff69c..919c512dcd 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_xss.py +++ b/lms/djangoapps/instructor/tests/test_legacy_xss.py @@ -9,7 +9,7 @@ from nose.plugins.attrib import attr from student.tests.factories import UserFactory, CourseEnrollmentFactory from edxmako.tests import mako_middleware_process_request -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from instructor.views import legacy @@ -18,12 +18,16 @@ from instructor.views import legacy @attr('shard_1') -class TestXss(ModuleStoreTestCase): +class TestXss(SharedModuleStoreTestCase): + @classmethod + def setUpClass(cls): + super(TestXss, cls).setUpClass() + cls._course = CourseFactory.create() + def setUp(self): super(TestXss, self).setUp() self._request_factory = RequestFactory() - self._course = CourseFactory.create() self._evil_student = UserFactory.create( email="robot+evil@edx.org", username="evil-robot", diff --git a/lms/djangoapps/instructor/tests/test_proctoring.py b/lms/djangoapps/instructor/tests/test_proctoring.py index 7bac68a0ee..12bc0eb257 100644 --- a/lms/djangoapps/instructor/tests/test_proctoring.py +++ b/lms/djangoapps/instructor/tests/test_proctoring.py @@ -10,29 +10,32 @@ from nose.plugins.attrib import attr from student.roles import CourseFinanceAdminRole from student.tests.factories import AdminFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @attr('shard_1') @patch.dict(settings.FEATURES, {'ENABLE_PROCTORED_EXAMS': True}) -class TestProctoringDashboardViews(ModuleStoreTestCase): +class TestProctoringDashboardViews(SharedModuleStoreTestCase): """ Check for Proctoring view on the new instructor dashboard """ + @classmethod + def setUpClass(cls): + super(TestProctoringDashboardViews, cls).setUpClass() + cls.course = CourseFactory.create(enable_proctored_exams=True) + + # URL for instructor dash + cls.url = reverse('instructor_dashboard', kwargs={'course_id': cls.course.id.to_deprecated_string()}) + cls.proctoring_link = 'Proctoring' + def setUp(self): super(TestProctoringDashboardViews, self).setUp() - self.course = CourseFactory.create() - self.course.enable_proctored_exams = True # Create instructor account self.instructor = AdminFactory.create() self.client.login(username=self.instructor.username, password="test") - self.course = self.update_course(self.course, self.instructor.id) - # URL for instructor dash - self.url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id.to_deprecated_string()}) - self.proctoring_link = 'Proctoring' CourseFinanceAdminRole(self.course.id).add_users(self.instructor) def test_pass_proctoring_tab_in_instructor_dashboard(self): diff --git a/lms/djangoapps/instructor/tests/test_registration_codes.py b/lms/djangoapps/instructor/tests/test_registration_codes.py index 2812fdfd9c..30cc2fbb7a 100644 --- a/lms/djangoapps/instructor/tests/test_registration_codes.py +++ b/lms/djangoapps/instructor/tests/test_registration_codes.py @@ -15,19 +15,22 @@ import json from student.tests.factories import UserFactory, CourseModeFactory from django.core.urlresolvers import reverse from django.test.utils import override_settings -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase @attr('shard_1') @override_settings(REGISTRATION_CODE_LENGTH=8) -class TestCourseRegistrationCodeStatus(ModuleStoreTestCase): +class TestCourseRegistrationCodeStatus(SharedModuleStoreTestCase): """ Test registration code status. """ + @classmethod + def setUpClass(cls): + super(TestCourseRegistrationCodeStatus, cls).setUpClass() + cls.course = CourseFactory.create() def setUp(self): super(TestCourseRegistrationCodeStatus, self).setUp() - self.course = CourseFactory.create() CourseModeFactory.create(course_id=self.course.id, min_price=50) self.instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=self.instructor.username, password='test') diff --git a/lms/djangoapps/instructor/tests/test_services.py b/lms/djangoapps/instructor/tests/test_services.py index 9137a9cee7..aaaae3ec36 100644 --- a/lms/djangoapps/instructor/tests/test_services.py +++ b/lms/djangoapps/instructor/tests/test_services.py @@ -3,7 +3,7 @@ Tests for the InstructorService """ import json -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from courseware.models import StudentModule from instructor.services import InstructorService @@ -15,31 +15,31 @@ from student.tests.factories import UserFactory @attr('shard_1') -class InstructorServiceTests(ModuleStoreTestCase): +class InstructorServiceTests(SharedModuleStoreTestCase): """ Tests for the InstructorService """ + @classmethod + def setUpClass(cls): + super(InstructorServiceTests, cls).setUpClass() + cls.course = CourseFactory.create() + cls.problem_location = msk_from_problem_urlname( + cls.course.id, + 'robot-some-problem-urlname' + ) + cls.other_problem_location = msk_from_problem_urlname( + cls.course.id, + 'robot-some-other_problem-urlname' + ) + cls.problem_urlname = unicode(cls.problem_location) + cls.other_problem_urlname = unicode(cls.other_problem_location) def setUp(self): super(InstructorServiceTests, self).setUp() - self.course = CourseFactory.create() self.student = UserFactory() CourseEnrollment.enroll(self.student, self.course.id) - self.problem_location = msk_from_problem_urlname( - self.course.id, - 'robot-some-problem-urlname' - ) - - self.other_problem_location = msk_from_problem_urlname( - self.course.id, - 'robot-some-other_problem-urlname' - ) - - self.problem_urlname = unicode(self.problem_location) - self.other_problem_urlname = unicode(self.other_problem_location) - self.service = InstructorService() self.module_to_reset = StudentModule.objects.create( student=self.student, diff --git a/lms/djangoapps/instructor/tests/test_spoc_gradebook.py b/lms/djangoapps/instructor/tests/test_spoc_gradebook.py index 2e0ca99a73..8da7e4d835 100644 --- a/lms/djangoapps/instructor/tests/test_spoc_gradebook.py +++ b/lms/djangoapps/instructor/tests/test_spoc_gradebook.py @@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse from nose.plugins.attrib import attr from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from student.tests.factories import UserFactory, CourseEnrollmentFactory, AdminFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from capa.tests.response_xml_factory import StringResponseXMLFactory from courseware.tests.factories import StudentModuleFactory from xmodule.modulestore.django import modulestore @@ -16,7 +16,7 @@ USER_COUNT = 11 @attr('shard_1') -class TestGradebook(ModuleStoreTestCase): +class TestGradebook(SharedModuleStoreTestCase): """ Test functionality of the spoc gradebook. Sets up a course with assignments and students who've scored various scores on these assignments. Base class for further @@ -24,45 +24,48 @@ class TestGradebook(ModuleStoreTestCase): """ grading_policy = None + @classmethod + def setUpClass(cls): + super(TestGradebook, cls).setUpClass() + + # Create a course with the desired grading policy (from our class attribute) + kwargs = {} + if cls.grading_policy is not None: + kwargs['grading_policy'] = cls.grading_policy + cls.course = CourseFactory.create(**kwargs) + + # Now give it some content + with cls.store.bulk_operations(cls.course.id, emit_signals=False): + chapter = ItemFactory.create( + parent_location=cls.course.location, + category="sequential", + ) + section = ItemFactory.create( + parent_location=chapter.location, + category="sequential", + metadata={'graded': True, 'format': 'Homework'} + ) + cls.items = [ + ItemFactory.create( + parent_location=section.location, + category="problem", + data=StringResponseXMLFactory().build_xml(answer='foo'), + metadata={'rerandomize': 'always'} + ) + for __ in xrange(USER_COUNT - 1) + ] + def setUp(self): super(TestGradebook, self).setUp() instructor = AdminFactory.create() self.client.login(username=instructor.username, password='test') - - # remove the caches - modulestore().request_cache = None - modulestore().metadata_inheritance_cache_subsystem = None - - kwargs = {} - if self.grading_policy is not None: - kwargs['grading_policy'] = self.grading_policy - - self.course = CourseFactory.create(**kwargs) - chapter = ItemFactory.create( - parent_location=self.course.location, - category="sequential", - ) - section = ItemFactory.create( - parent_location=chapter.location, - category="sequential", - metadata={'graded': True, 'format': 'Homework'} - ) - self.users = [UserFactory.create() for _ in xrange(USER_COUNT)] for user in self.users: CourseEnrollmentFactory.create(user=user, course_id=self.course.id) - for i in xrange(USER_COUNT - 1): - category = "problem" - item = ItemFactory.create( - parent_location=section.location, - category=category, - data=StringResponseXMLFactory().build_xml(answer='foo'), - metadata={'rerandomize': 'always'} - ) - + for i, item in enumerate(self.items): for j, user in enumerate(self.users): StudentModuleFactory.create( grade=1 if i < j else 0, diff --git a/lms/djangoapps/instructor/tests/test_tools.py b/lms/djangoapps/instructor/tests/test_tools.py index 5378aa5330..54068d4ce2 100644 --- a/lms/djangoapps/instructor/tests/test_tools.py +++ b/lms/djangoapps/instructor/tests/test_tools.py @@ -14,7 +14,7 @@ from nose.plugins.attrib import attr from courseware.field_overrides import OverrideFieldData # pylint: disable=import-error from student.tests.factories import UserFactory # pylint: disable=import-error from xmodule.fields import Date -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from opaque_keys.edx.keys import CourseKey @@ -102,23 +102,17 @@ class TestParseDatetime(unittest.TestCase): @attr('shard_1') -class TestFindUnit(ModuleStoreTestCase): +class TestFindUnit(SharedModuleStoreTestCase): """ Test the find_unit function. """ - - def setUp(self): - """ - Fixtures. - """ - super(TestFindUnit, self).setUp() - - course = CourseFactory.create() - week1 = ItemFactory.create(parent=course) - homework = ItemFactory.create(parent=week1) - - self.course = course - self.homework = homework + @classmethod + def setUpClass(cls): + super(TestFindUnit, cls).setUpClass() + cls.course = CourseFactory.create() + with cls.store.bulk_operations(cls.course.id, emit_signals=False): + week1 = ItemFactory.create(parent=cls.course) + cls.homework = ItemFactory.create(parent=week1) def test_find_unit_success(self): """