diff --git a/cms/djangoapps/contentstore/tests/test_assets.py b/cms/djangoapps/contentstore/tests/test_assets.py index b627237729..2f158cfda6 100644 --- a/cms/djangoapps/contentstore/tests/test_assets.py +++ b/cms/djangoapps/contentstore/tests/test_assets.py @@ -60,11 +60,11 @@ class UploadTestCase(CourseTestCase): f = BytesIO("sample content") f.name = "sample.txt" resp = self.client.post(self.url, {"name": "my-name", "file": f}) - self.assert2XX(resp.status_code) + self.assertEquals(resp.status_code, 200) def test_no_file(self): resp = self.client.post(self.url, {"name": "file.txt"}) - self.assert4XX(resp.status_code) + self.assertEquals(resp.status_code, 400) def test_get(self): resp = self.client.get(self.url) diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index f03ee3b81a..14e54f6f56 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -1408,7 +1408,7 @@ class ContentStoreTest(ModuleStoreTestCase): 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) self.assertContains(resp, 'Chapter 2') # go to various pages @@ -1418,92 +1418,92 @@ class ContentStoreTest(ModuleStoreTestCase): kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # export page resp = self.client.get(reverse('export_course', kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # manage users resp = self.client.get(reverse('manage_users', kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # course info resp = self.client.get(reverse('course_info', kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # settings_details resp = self.client.get(reverse('settings_details', kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # settings_details resp = self.client.get(reverse('settings_grading', kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # static_pages resp = self.client.get(reverse('static_pages', kwargs={'org': loc.org, 'course': loc.course, 'coursename': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # static_pages resp = self.client.get(reverse('asset_index', kwargs={'org': loc.org, 'course': loc.course, 'name': loc.name})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # go look at a subsection page subsection_location = loc.replace(category='sequential', name='test_sequence') resp = self.client.get(reverse('edit_subsection', kwargs={'location': subsection_location.url()})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # go look at the Edit page unit_location = loc.replace(category='vertical', name='test_vertical') resp = self.client.get(reverse('edit_unit', kwargs={'location': unit_location.url()})) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # delete a component del_loc = loc.replace(category='html', name='test_html') resp = self.client.post(reverse('delete_item'), json.dumps({'id': del_loc.url()}), "application/json") - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # delete a unit del_loc = loc.replace(category='vertical', name='test_vertical') resp = self.client.post(reverse('delete_item'), json.dumps({'id': del_loc.url()}), "application/json") - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # delete a unit del_loc = loc.replace(category='sequential', name='test_sequence') resp = self.client.post(reverse('delete_item'), json.dumps({'id': del_loc.url()}), "application/json") - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # delete a chapter del_loc = loc.replace(category='chapter', name='chapter_2') resp = self.client.post(reverse('delete_item'), json.dumps({'id': del_loc.url()}), "application/json") - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) def test_import_into_new_course_id(self): module_store = modulestore('direct') diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index dbdf8b3f6e..524dde07e5 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -439,12 +439,12 @@ class CourseGraderUpdatesTest(CourseTestCase): def test_get(self): resp = self.client.get(self.url) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) obj = json.loads(resp.content) def test_delete(self): resp = self.client.delete(self.url) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) def test_post(self): grader = { @@ -455,5 +455,5 @@ class CourseGraderUpdatesTest(CourseTestCase): "weight": 17.3, } resp = self.client.post(self.url, grader) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) obj = json.loads(resp.content) diff --git a/cms/djangoapps/contentstore/tests/test_item.py b/cms/djangoapps/contentstore/tests/test_item.py index 260444a8f7..e5ff992cb8 100644 --- a/cms/djangoapps/contentstore/tests/test_item.py +++ b/cms/djangoapps/contentstore/tests/test_item.py @@ -34,7 +34,7 @@ class DeleteItem(CourseTestCase): resp.content, "application/json" ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) class TestCreateItem(CourseTestCase): diff --git a/cms/djangoapps/contentstore/tests/test_textbooks.py b/cms/djangoapps/contentstore/tests/test_textbooks.py index a21a1b1023..950d0f780e 100644 --- a/cms/djangoapps/contentstore/tests/test_textbooks.py +++ b/cms/djangoapps/contentstore/tests/test_textbooks.py @@ -23,7 +23,7 @@ class TextbookIndexTestCase(CourseTestCase): def test_view_index(self): "Basic check that the textbook index page responds correctly" resp = self.client.get(self.url) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # we don't have resp.context right now, # due to bugs in our testing harness :( if resp.context: @@ -36,7 +36,7 @@ class TextbookIndexTestCase(CourseTestCase): HTTP_ACCEPT="application/json", HTTP_X_REQUESTED_WITH='XMLHttpRequest' ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) obj = json.loads(resp.content) self.assertEqual(self.course.pdf_textbooks, obj) @@ -73,7 +73,7 @@ class TextbookIndexTestCase(CourseTestCase): HTTP_ACCEPT="application/json", HTTP_X_REQUESTED_WITH='XMLHttpRequest' ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) obj = json.loads(resp.content) self.assertEqual(content, obj) @@ -90,7 +90,7 @@ class TextbookIndexTestCase(CourseTestCase): HTTP_ACCEPT="application/json", HTTP_X_REQUESTED_WITH='XMLHttpRequest' ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) # reload course store = get_modulestore(self.course.location) @@ -111,7 +111,7 @@ class TextbookIndexTestCase(CourseTestCase): HTTP_ACCEPT="application/json", HTTP_X_REQUESTED_WITH='XMLHttpRequest' ) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) obj = json.loads(resp.content) self.assertIn("error", obj) @@ -184,7 +184,7 @@ class TextbookCreateTestCase(CourseTestCase): HTTP_ACCEPT="application/json", HTTP_X_REQUESTED_WITH="XMLHttpRequest", ) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) self.assertNotIn("Location", resp) @@ -238,14 +238,14 @@ class TextbookByIdTestCase(CourseTestCase): def test_get_1(self): "Get the first textbook" resp = self.client.get(self.url1) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) compare = json.loads(resp.content) self.assertEqual(compare, self.textbook1) def test_get_2(self): "Get the second textbook" resp = self.client.get(self.url2) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) compare = json.loads(resp.content) self.assertEqual(compare, self.textbook2) @@ -257,7 +257,7 @@ class TextbookByIdTestCase(CourseTestCase): def test_delete(self): "Delete a textbook by ID" resp = self.client.delete(self.url1) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) course = self.store.get_item(self.course.location) self.assertEqual(course.pdf_textbooks, [self.textbook2]) @@ -288,7 +288,7 @@ class TextbookByIdTestCase(CourseTestCase): ) self.assertEqual(resp.status_code, 201) resp2 = self.client.get(url) - self.assert2XX(resp2.status_code) + self.assertEqual(resp2.status_code, 200) compare = json.loads(resp2.content) self.assertEqual(compare, textbook) course = self.store.get_item(self.course.location) @@ -311,7 +311,7 @@ class TextbookByIdTestCase(CourseTestCase): ) self.assertEqual(resp.status_code, 201) resp2 = self.client.get(self.url2) - self.assert2XX(resp2.status_code) + self.assertEqual(resp2.status_code, 200) compare = json.loads(resp2.content) self.assertEqual(compare, replacement) course = self.store.get_item(self.course.location) diff --git a/cms/djangoapps/contentstore/tests/test_users.py b/cms/djangoapps/contentstore/tests/test_users.py index cbb8aa8b01..80b2364c43 100644 --- a/cms/djangoapps/contentstore/tests/test_users.py +++ b/cms/djangoapps/contentstore/tests/test_users.py @@ -72,13 +72,13 @@ class UsersTestCase(CourseTestCase): def test_detail_inactive(self): resp = self.client.get(self.inactive_detail_url) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 200) result = json.loads(resp.content) self.assertFalse(result["active"]) def test_detail_invalid(self): resp = self.client.get(self.invalid_detail_url) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 404) result = json.loads(resp.content) self.assertIn("error", result) @@ -87,7 +87,7 @@ class UsersTestCase(CourseTestCase): self.detail_url, data={"role": None}, ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -103,7 +103,7 @@ class UsersTestCase(CourseTestCase): content_type="application/json", HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -122,7 +122,7 @@ class UsersTestCase(CourseTestCase): content_type="application/json", HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -142,7 +142,7 @@ class UsersTestCase(CourseTestCase): content_type="application/json", HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -157,7 +157,7 @@ class UsersTestCase(CourseTestCase): content_type="application/json", HTTP_ACCEPT="application/json", ) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) result = json.loads(resp.content) self.assertIn("error", result) self.assert_not_enrolled() @@ -169,7 +169,7 @@ class UsersTestCase(CourseTestCase): content_type="application/json", HTTP_ACCEPT="application/json", ) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) result = json.loads(resp.content) self.assertIn("error", result) self.assert_not_enrolled() @@ -180,7 +180,7 @@ class UsersTestCase(CourseTestCase): data={"role": "staff"}, HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -197,7 +197,7 @@ class UsersTestCase(CourseTestCase): self.detail_url, HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -214,7 +214,7 @@ class UsersTestCase(CourseTestCase): self.detail_url, HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB ext_user = User.objects.get(email=self.ext_user.email) groups = [g.name for g in ext_user.groups.all()] @@ -273,7 +273,7 @@ class UsersTestCase(CourseTestCase): data={"role": "instructor"}, HTTP_ACCEPT="application/json", ) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) result = json.loads(resp.content) self.assertIn("error", result) @@ -288,7 +288,7 @@ class UsersTestCase(CourseTestCase): data={"role": "instructor"}, HTTP_ACCEPT="application/json", ) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) result = json.loads(resp.content) self.assertIn("error", result) @@ -306,7 +306,7 @@ class UsersTestCase(CourseTestCase): }) resp = self.client.delete(self_url) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) # reload user from DB user = User.objects.get(email=self.user.email) groups = [g.name for g in user.groups.all()] @@ -321,7 +321,7 @@ class UsersTestCase(CourseTestCase): self.ext_user.save() resp = self.client.delete(self.detail_url) - self.assert4XX(resp.status_code) + self.assertEqual(resp.status_code, 400) result = json.loads(resp.content) self.assertIn("error", result) # reload user from DB @@ -347,7 +347,7 @@ class UsersTestCase(CourseTestCase): self.detail_url, HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) self.assert_enrolled() def test_staff_to_instructor_still_enrolled(self): @@ -366,7 +366,7 @@ class UsersTestCase(CourseTestCase): content_type="application/json", HTTP_ACCEPT="application/json", ) - self.assert2XX(resp.status_code) + self.assertEqual(resp.status_code, 204) self.assert_enrolled() def assert_not_enrolled(self): diff --git a/common/djangoapps/course_groups/tests/tests.py b/common/djangoapps/course_groups/tests/tests.py index 2e519edb30..a17df56a71 100644 --- a/common/djangoapps/course_groups/tests/tests.py +++ b/common/djangoapps/course_groups/tests/tests.py @@ -8,19 +8,20 @@ from course_groups.models import CourseUserGroup from course_groups.cohorts import (get_cohort, get_course_cohorts, is_commentable_cohorted, get_cohort_by_name) -from xmodule.modulestore.django import modulestore, _MODULESTORES +from xmodule.modulestore.django import modulestore, clear_existing_modulestores -from xmodule.modulestore.tests.django_utils import xml_store_config +from xmodule.modulestore.tests.django_utils import mixed_store_config # NOTE: running this with the lms.envs.test config works without # manually overriding the modulestore. However, running with # cms.envs.test doesn't. TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT -TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR) +TEST_MAPPING = {'edX/toy/2012_Fall': 'xml'} +TEST_DATA_MIXED_MODULESTORE = mixed_store_config(TEST_DATA_DIR, TEST_MAPPING) -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestCohorts(django.test.TestCase): @staticmethod @@ -82,9 +83,7 @@ class TestCohorts(django.test.TestCase): """ Make sure that course is reloaded every time--clear out the modulestore. """ - # don't like this, but don't know a better way to undo all changes made - # to course. We don't have a course.clone() method. - _MODULESTORES.clear() + clear_existing_modulestores() def test_get_cohort(self): """ diff --git a/common/djangoapps/external_auth/tests/test_shib.py b/common/djangoapps/external_auth/tests/test_shib.py index 6bb9c38e6f..0355730256 100644 --- a/common/djangoapps/external_auth/tests/test_shib.py +++ b/common/djangoapps/external_auth/tests/test_shib.py @@ -14,11 +14,9 @@ from django.contrib.auth.models import AnonymousUser, User from django.utils.importlib import import_module from xmodule.modulestore.tests.factories import CourseFactory -from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, mixed_store_config from xmodule.modulestore.inheritance import own_metadata -from xmodule.modulestore.django import modulestore - -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from xmodule.modulestore.django import editable_modulestore from external_auth.models import ExternalAuthMap from external_auth.views import shib_login, course_specific_login, course_specific_register @@ -27,6 +25,8 @@ from student.views import create_account, change_enrollment from student.models import UserProfile, Registration, CourseEnrollment from student.tests.factories import UserFactory +TEST_DATA_MIXED_MODULESTORE = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}) + # Shib is supposed to provide 'REMOTE_USER', 'givenName', 'sn', 'mail', 'Shib-Identity-Provider' # attributes via request.META. We can count on 'Shib-Identity-Provider', and 'REMOTE_USER' being present # b/c of how mod_shib works but should test the behavior with the rest of the attributes present/missing @@ -64,7 +64,7 @@ def gen_all_identities(): yield _build_identity_dict(mail, given_name, surname) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE, SESSION_ENGINE='django.contrib.sessions.backends.cache') +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE, SESSION_ENGINE='django.contrib.sessions.backends.cache') class ShibSPTest(ModuleStoreTestCase): """ Tests for the Shibboleth SP, which communicates via request.META @@ -73,7 +73,7 @@ class ShibSPTest(ModuleStoreTestCase): request_factory = RequestFactory() def setUp(self): - self.store = modulestore() + self.store = editable_modulestore() @unittest.skipUnless(settings.MITX_FEATURES.get('AUTH_USE_SHIB'), True) def test_exception_shib_login(self): diff --git a/common/djangoapps/terrain/browser.py b/common/djangoapps/terrain/browser.py index cf53aa4f69..4bf1aea40c 100644 --- a/common/djangoapps/terrain/browser.py +++ b/common/djangoapps/terrain/browser.py @@ -161,9 +161,10 @@ def reset_databases(scenario): mongo = MongoClient() mongo.drop_database(settings.CONTENTSTORE['OPTIONS']['db']) _CONTENTSTORE.clear() - modulestore = xmodule.modulestore.django.modulestore() + + modulestore = xmodule.modulestore.django.editable_modulestore() modulestore.collection.drop() - xmodule.modulestore.django._MODULESTORES.clear() + xmodule.modulestore.django.clear_existing_modulestores() # Uncomment below to trigger a screenshot on error diff --git a/common/djangoapps/terrain/course_helpers.py b/common/djangoapps/terrain/course_helpers.py index eca3290080..fc01d25d66 100644 --- a/common/djangoapps/terrain/course_helpers.py +++ b/common/djangoapps/terrain/course_helpers.py @@ -10,7 +10,7 @@ from django.contrib.auth import authenticate, login from django.contrib.auth.middleware import AuthenticationMiddleware from django.contrib.sessions.middleware import SessionMiddleware from student.models import CourseEnrollment -from xmodule.modulestore.django import modulestore +from xmodule.modulestore.django import editable_modulestore from xmodule.contentstore.django import contentstore from urllib import quote_plus @@ -60,11 +60,9 @@ def register_by_course_id(course_id, is_staff=False): @world.absorb def clear_courses(): # Flush and initialize the module store - # It needs the templates because it creates new records - # by cloning from the template. # Note that if your test module gets in some weird state # (though it shouldn't), do this manually # from the bash shell to drop it: # $ mongo test_xmodule --eval "db.dropDatabase()" - modulestore().collection.drop() + editable_modulestore().collection.drop() contentstore().fs_files.drop() diff --git a/common/lib/xmodule/xmodule/js/libpeerconnection.log b/common/lib/xmodule/xmodule/js/libpeerconnection.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py index fb427f49ec..b239e5f1d4 100644 --- a/common/lib/xmodule/xmodule/modulestore/django.py +++ b/common/lib/xmodule/xmodule/modulestore/django.py @@ -55,6 +55,7 @@ def modulestore(name='default'): return _MODULESTORES[name] + _loc_singleton = None def loc_mapper(): """ @@ -69,3 +70,42 @@ def loc_mapper(): _loc_singleton = LocMapperStore(settings.modulestore_options) return _loc_singleton + +def clear_existing_modulestores(): + """ + Clear the existing modulestore instances, causing + them to be re-created when accessed again. + + This is useful for flushing state between unit tests. + """ + _MODULESTORES.clear() + + +def editable_modulestore(name='default'): + """ + Retrieve a modulestore that we can modify. + This is useful for tests that need to insert test + data into the modulestore. + + Currently, only Mongo-backed modulestores can be modified. + Returns `None` if no editable modulestore is available. + """ + + # Try to retrieve the ModuleStore + # Depending on the settings, this may or may not + # be editable. + store = modulestore(name) + + # If this is a `MixedModuleStore`, then we will need + # to retrieve the actual Mongo instance. + # We assume that the default is Mongo. + if hasattr(store, 'modulestores'): + store = store.modulestores['default'] + + # At this point, we either have the ability to create + # items in the store, or we do not. + if hasattr(store, 'create_xmodule'): + return store + + else: + return None diff --git a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py index 4f998d57fb..1f856d7eba 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/django_utils.py @@ -1,11 +1,46 @@ +""" +Modulestore configuration for test cases. +""" -import copy from uuid import uuid4 from django.test import TestCase +from xmodule.modulestore.django import editable_modulestore, \ + clear_existing_modulestores -from django.conf import settings -import xmodule.modulestore.django -from unittest.util import safe_repr + +def mixed_store_config(data_dir, mappings): + """ + Return a `MixedModuleStore` configuration, which provides + access to both Mongo- and XML-backed courses. + + `data_dir` is the directory from which to load XML-backed courses. + `mappings` is a dictionary mapping course IDs to modulestores, for example: + + { + 'MITx/2.01x/2013_Spring': 'xml', + 'edx/999/2013_Spring': 'default' + } + + where 'xml' and 'default' are the two options provided by this configuration, + mapping (respectively) to XML-backed and Mongo-backed modulestores.. + """ + mongo_config = mongo_store_config(data_dir) + xml_config = xml_store_config(data_dir) + + store = { + 'default': { + 'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore', + 'OPTIONS': { + 'mappings': mappings, + 'stores': { + 'default': mongo_config['default'], + 'xml': xml_config['default'] + } + } + } + } + store['direct'] = store['default'] + return store def mongo_store_config(data_dir): @@ -27,6 +62,7 @@ def mongo_store_config(data_dir): } } } + store['direct'] = store['default'] return store @@ -45,23 +81,22 @@ def draft_mongo_store_config(data_dir): 'render_template': 'mitxmako.shortcuts.render_to_string' } - return { + store = { 'default': { 'ENGINE': 'xmodule.modulestore.mongo.draft.DraftModuleStore', 'OPTIONS': modulestore_options - }, - 'direct': { - 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', - 'OPTIONS': modulestore_options } } + store['direct'] = store['default'] + return store + def xml_store_config(data_dir): """ Defines default module store using XMLModuleStore. """ - return { + store = { 'default': { 'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore', 'OPTIONS': { @@ -71,12 +106,48 @@ def xml_store_config(data_dir): } } + store['direct'] = store['default'] + return store + class ModuleStoreTestCase(TestCase): - """ Subclass for any test case that uses the mongodb - module store. This populates a uniquely named modulestore - collection with templates before running the TestCase - and drops it they are finished. """ + """ + Subclass for any test case that uses a ModuleStore. + Ensures that the ModuleStore is cleaned before/after each test. + + Usage: + + 1. Create a subclass of `ModuleStoreTestCase` + 2. Use Django's @override_settings decorator to use + the desired modulestore configuration. + + For example: + + MIXED_CONFIG = mixed_store_config(data_dir, mappings) + + @override_settings(MODULESTORE=MIXED_CONFIG) + class FooTest(ModuleStoreTestCase): + # ... + + 3. Use factories (e.g. `CourseFactory`, `ItemFactory`) to populate + the modulestore with test data. + + NOTE: + * For Mongo-backed courses (created with `CourseFactory`), + the state of the course will be reset before/after each + test method executes. + + * For XML-backed courses, the course state will NOT + reset between test methods (although it will reset + between test classes) + + The reason is: XML courses are not editable, so to reset + a course you have to reload it from disk, which is slow. + + If you do need to reset an XML course, use + `clear_existing_modulestores()` directly in + your `setUp()` method. + """ @staticmethod def update_course(course, data): @@ -89,107 +160,68 @@ class ModuleStoreTestCase(TestCase): 'data' is a dictionary with an entry for each CourseField we want to update. """ - store = xmodule.modulestore.django.modulestore() + store = editable_modulestore('direct') store.update_metadata(course.location, data) updated_course = store.get_instance(course.id, course.location) return updated_course @staticmethod - def flush_mongo_except_templates(): + def drop_mongo_collection(): """ - Delete everything in the module store except templates. + If using a Mongo-backed modulestore, drop the collection. """ - modulestore = xmodule.modulestore.django.modulestore() - # This query means: every item in the collection - # that is not a template - query = {"_id.course": {"$ne": "templates"}} + # This will return the mongo-backed modulestore + # even if we're using a mixed modulestore + store = editable_modulestore() - # Remove everything except templates - modulestore.collection.remove(query) - modulestore.collection.drop() + if hasattr(store, 'collection'): + store.collection.drop() @classmethod def setUpClass(cls): """ - Flush the mongo store and set up templates. + Delete the existing modulestores, causing them to be reloaded. """ - - # Use a uuid to differentiate - # the mongo collections on jenkins. - cls.orig_modulestore = copy.deepcopy(settings.MODULESTORE) - if 'direct' not in settings.MODULESTORE: - settings.MODULESTORE['direct'] = settings.MODULESTORE['default'] - - settings.MODULESTORE['default']['OPTIONS']['collection'] = 'modulestore_%s' % uuid4().hex - settings.MODULESTORE['direct']['OPTIONS']['collection'] = 'modulestore_%s' % uuid4().hex - xmodule.modulestore.django._MODULESTORES.clear() - - print settings.MODULESTORE - + # Clear out any existing modulestores, + # which will cause them to be re-created + # the next time they are accessed. + clear_existing_modulestores() TestCase.setUpClass() @classmethod def tearDownClass(cls): """ - Revert to the old modulestore settings. + Drop the existing modulestores, causing them to be reloaded. + Clean up any data stored in Mongo. """ + # Clean up by flushing the Mongo modulestore + cls.drop_mongo_collection() - # Clean up by dropping the collection - modulestore = xmodule.modulestore.django.modulestore() - modulestore.collection.drop() + # Clear out the existing modulestores, + # which will cause them to be re-created + # the next time they are accessed. + # We do this at *both* setup and teardown just to be safe. + clear_existing_modulestores() - xmodule.modulestore.django._MODULESTORES.clear() - - # Restore the original modulestore settings - settings.MODULESTORE = cls.orig_modulestore + TestCase.tearDownClass() def _pre_setup(self): """ - Remove everything but the templates before each test. + Flush the ModuleStore before each test. """ - # Flush anything that is not a template - ModuleStoreTestCase.flush_mongo_except_templates() + # Flush the Mongo modulestore + ModuleStoreTestCase.drop_mongo_collection() # Call superclass implementation super(ModuleStoreTestCase, self)._pre_setup() def _post_teardown(self): """ - Flush everything we created except the templates. + Flush the ModuleStore after each test. """ - # Flush anything that is not a template - ModuleStoreTestCase.flush_mongo_except_templates() + ModuleStoreTestCase.drop_mongo_collection() # Call superclass implementation super(ModuleStoreTestCase, self)._post_teardown() - - - def assert2XX(self, status_code, msg=None): - """ - Assert that the given value is a success status (between 200 and 299) - """ - msg = self._formatMessage(msg, "%s is not a success status" % safe_repr(status_code)) - self.assertTrue(status_code >= 200 and status_code < 300, msg=msg) - - def assert3XX(self, status_code, msg=None): - """ - Assert that the given value is a redirection status (between 300 and 399) - """ - msg = self._formatMessage(msg, "%s is not a redirection status" % safe_repr(status_code)) - self.assertTrue(status_code >= 300 and status_code < 400, msg=msg) - - def assert4XX(self, status_code, msg=None): - """ - Assert that the given value is a client error status (between 400 and 499) - """ - msg = self._formatMessage(msg, "%s is not a client error status" % safe_repr(status_code)) - self.assertTrue(status_code >= 400 and status_code < 500, msg=msg) - - def assert5XX(self, status_code, msg=None): - """ - Assert that the given value is a server error status (between 500 and 599) - """ - msg = self._formatMessage(msg, "%s is not a server error status" % safe_repr(status_code)) - self.assertTrue(status_code >= 500 and status_code < 600, msg=msg) diff --git a/common/lib/xmodule/xmodule/modulestore/tests/factories.py b/common/lib/xmodule/xmodule/modulestore/tests/factories.py index f2e4017114..7913434086 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/factories.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/factories.py @@ -5,11 +5,12 @@ from uuid import uuid4 from pytz import UTC from xmodule.modulestore import Location -from xmodule.modulestore.django import modulestore +from xmodule.modulestore.django import editable_modulestore from xmodule.course_module import CourseDescriptor from xblock.core import Scope from xmodule.x_module import XModuleDescriptor + class XModuleCourseFactory(Factory): """ Factory for XModule courses. @@ -25,10 +26,7 @@ class XModuleCourseFactory(Factory): display_name = kwargs.pop('display_name', None) location = Location('i4x', org, number, 'course', Location.clean(display_name)) - try: - store = modulestore('direct') - except KeyError: - store = modulestore() + store = editable_modulestore('direct') # Write the data to the mongo datastore new_course = store.create_xmodule(location) @@ -117,7 +115,7 @@ class XModuleItemFactory(Factory): if not isinstance(data, basestring): data.update(template.get('data')) - store = modulestore('direct') + store = editable_modulestore('direct') # This code was based off that in cms/djangoapps/contentstore/views.py parent = store.get_item(parent_location) diff --git a/lms/djangoapps/course_wiki/tests/tests.py b/lms/djangoapps/course_wiki/tests/tests.py index 6bbd8011d6..93954dab61 100644 --- a/lms/djangoapps/course_wiki/tests/tests.py +++ b/lms/djangoapps/course_wiki/tests/tests.py @@ -3,21 +3,18 @@ from django.test.utils import override_settings import xmodule.modulestore.django -from courseware.tests.tests import LoginEnrollmentTestCase, TEST_DATA_XML_MODULESTORE +from courseware.tests.tests import LoginEnrollmentTestCase +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from xmodule.modulestore.django import modulestore -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class WikiRedirectTestCase(LoginEnrollmentTestCase): + def setUp(self): - xmodule.modulestore.django._MODULESTORES = {} - courses = modulestore().get_courses() - def find_course(name): - """Assumes the course is present""" - return [c for c in courses if c.location.course == name][0] - - self.toy = find_course("toy") + # Load the toy course + self.toy = modulestore().get_course('edX/toy/2012_Fall') # Create two accounts self.student = 'view@test.com' diff --git a/lms/djangoapps/courseware/tests/__init__.py b/lms/djangoapps/courseware/tests/__init__.py index 9d1b549b9f..4b93e804bf 100644 --- a/lms/djangoapps/courseware/tests/__init__.py +++ b/lms/djangoapps/courseware/tests/__init__.py @@ -12,7 +12,7 @@ from django.core.urlresolvers import reverse from django.test.client import Client from student.tests.factories import UserFactory, CourseEnrollmentFactory -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from xmodule.tests import get_test_system from xmodule.modulestore import Location from xmodule.modulestore.django import modulestore @@ -20,7 +20,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class BaseTestXmodule(ModuleStoreTestCase): """Base class for testing Xmodules with mongo store. diff --git a/lms/djangoapps/courseware/tests/modulestore_config.py b/lms/djangoapps/courseware/tests/modulestore_config.py index 80a7b0a7c1..74fd3da57f 100644 --- a/lms/djangoapps/courseware/tests/modulestore_config.py +++ b/lms/djangoapps/courseware/tests/modulestore_config.py @@ -1,4 +1,10 @@ -from xmodule.modulestore.tests.django_utils import xml_store_config, mongo_store_config, draft_mongo_store_config +""" +Define test configuration for modulestores. +""" + +from xmodule.modulestore.tests.django_utils import xml_store_config, \ + mongo_store_config, draft_mongo_store_config,\ + mixed_store_config from django.conf import settings @@ -6,3 +12,15 @@ TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR) TEST_DATA_MONGO_MODULESTORE = mongo_store_config(TEST_DATA_DIR) TEST_DATA_DRAFT_MONGO_MODULESTORE = draft_mongo_store_config(TEST_DATA_DIR) + +# Map all XML course fixtures so they are accessible through +# the MixedModuleStore +MAPPINGS = { + 'edX/toy/2012_Fall': 'xml', + 'edX/toy/TT_2012_Fall': 'xml', + 'edX/test_end/2012_Fall': 'xml', + 'edX/test_about_blob_end_date/2012_Fall': 'xml', + 'edX/graded/2012_Fall': 'xml', + 'edX/open_ended/2012_Fall': 'xml', +} +TEST_DATA_MIXED_MODULESTORE = mixed_store_config(TEST_DATA_DIR, MAPPINGS) diff --git a/lms/djangoapps/courseware/tests/test_masquerade.py b/lms/djangoapps/courseware/tests/test_masquerade.py index 0fc4eae242..0ec320b605 100644 --- a/lms/djangoapps/courseware/tests/test_masquerade.py +++ b/lms/djangoapps/courseware/tests/test_masquerade.py @@ -15,23 +15,23 @@ from django.core.urlresolvers import reverse from django.contrib.auth.models import Group, User from courseware.access import _course_staff_group_name from courseware.tests.helpers import LoginEnrollmentTestCase -from modulestore_config import TEST_DATA_XML_MODULESTORE -from xmodule.modulestore.django import modulestore -import xmodule.modulestore.django +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.django import modulestore, clear_existing_modulestores import json -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase): - ''' - Check for staff being able to masquerade as student - ''' +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestStaffMasqueradeAsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase): + """ + Check for staff being able to masquerade as student. + """ def setUp(self): - xmodule.modulestore.django._MODULESTORES = {} - #self.full = modulestore().get_course("edX/full/6.002_Spring_2012") - #self.toy = modulestore().get_course("edX/toy/2012_Fall") + # Clear out the modulestores, causing them to reload + clear_existing_modulestores() + self.graded_course = modulestore().get_course("edX/graded/2012_Fall") # Create staff account @@ -50,7 +50,6 @@ class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase): self.logout() self.login(self.instructor, self.password) self.enroll(self.graded_course) - # self.factory = RequestFactory() def get_cw_section(self): url = reverse('courseware_section', @@ -70,9 +69,9 @@ class TestStaffMasqueradeAsStudent(LoginEnrollmentTestCase): self.assertTrue(sdebug in resp.content) def toggle_masquerade(self): - ''' - Toggle masquerade state - ''' + """ + Toggle masquerade state. + """ masq_url = reverse('masquerade-switch', kwargs={'marg': 'toggle'}) print "masq_url ", masq_url resp = self.client.get(masq_url) diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index 56659b7c2b..911136da77 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -15,22 +15,17 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.factories import ItemFactory, CourseFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase import courseware.module_render as render -from courseware.tests.tests import LoginEnrollmentTestCase, TEST_DATA_MONGO_MODULESTORE +from courseware.tests.tests import LoginEnrollmentTestCase from courseware.model_data import ModelDataCache -from modulestore_config import TEST_DATA_XML_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from courseware.courses import get_course_with_access, course_image_url, get_course_info_section from .factories import UserFactory -class Stub: - def __init__(self): - pass - - -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class ModuleRenderTestCase(LoginEnrollmentTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class ModuleRenderTestCase(ModuleStoreTestCase, LoginEnrollmentTestCase): def setUp(self): self.location = ['i4x', 'edX', 'toy', 'chapter', 'Overview'] self.course_id = 'edX/toy/2012_Fall' @@ -96,7 +91,7 @@ class ModuleRenderTestCase(LoginEnrollmentTestCase): settings.MAX_FILEUPLOADS_PER_INPUT})) mock_request_2 = MagicMock() mock_request_2.FILES.keys.return_value = ['file_id'] - inputfile = Stub() + inputfile = MagicMock() inputfile.size = 1 + settings.STUDENT_FILEUPLOAD_MAX_SIZE inputfile.name = 'name' filelist = [inputfile] @@ -109,7 +104,7 @@ class ModuleRenderTestCase(LoginEnrollmentTestCase): mock_request_3.POST.copy.return_value = {'position': 1} mock_request_3.FILES = False mock_request_3.user = self.mock_user - inputfile_2 = Stub() + inputfile_2 = MagicMock() inputfile_2.size = 1 inputfile_2.name = 'name' self.assertIsInstance(render.modx_dispatch(mock_request_3, 'goto_position', @@ -200,7 +195,7 @@ class ModuleRenderTestCase(LoginEnrollmentTestCase): self.assertEquals(403, response.status_code) -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestTOC(TestCase): """Check the Table of Contents for a course""" def setUp(self): @@ -266,7 +261,7 @@ class TestTOC(TestCase): self.assertIn(toc_section, actual) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestHtmlModifiers(ModuleStoreTestCase): """ Tests to verify that standard modifications to the output of XModule/XBlock diff --git a/lms/djangoapps/courseware/tests/test_navigation.py b/lms/djangoapps/courseware/tests/test_navigation.py index dd1f00711c..2b416b16de 100644 --- a/lms/djangoapps/courseware/tests/test_navigation.py +++ b/lms/djangoapps/courseware/tests/test_navigation.py @@ -6,10 +6,10 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from helpers import LoginEnrollmentTestCase, check_for_get_code -from modulestore_config import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestNavigation(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Check that navigation state is saved properly. diff --git a/lms/djangoapps/courseware/tests/test_submitting_problems.py b/lms/djangoapps/courseware/tests/test_submitting_problems.py index 9081a910c9..f8cfaefd75 100644 --- a/lms/djangoapps/courseware/tests/test_submitting_problems.py +++ b/lms/djangoapps/courseware/tests/test_submitting_problems.py @@ -13,17 +13,17 @@ from django.test.utils import override_settings from courseware import grades from courseware.model_data import ModelDataCache -from xmodule.modulestore.django import modulestore +from xmodule.modulestore.django import modulestore, editable_modulestore #import factories and parent testcase modules from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from capa.tests.response_xml_factory import OptionResponseXMLFactory, CustomResponseXMLFactory, SchematicResponseXMLFactory from courseware.tests.helpers import LoginEnrollmentTestCase -from courseware.tests.modulestore_config import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Check that a course gets graded properly. @@ -217,7 +217,8 @@ class TestCourseGrader(TestSubmittingProblems): """ course_data = {'grading_policy': grading_policy} - modulestore().update_item(self.course.location, course_data) + store = editable_modulestore('direct') + store.update_item(self.course.location, course_data) self.refresh_course() def get_grade_summary(self): diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 4435b5c951..5de7a39f63 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -7,9 +7,9 @@ import courseware.tabs as tabs from django.test.utils import override_settings from django.core.urlresolvers import reverse -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE class ProgressTestCase(TestCase): @@ -261,7 +261,7 @@ class ValidateTabsTestCase(TestCase): self.assertRaises(tabs.InvalidTabsException, tabs.validate_tabs, self.courses[4]) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class DiscussionLinkTestCase(ModuleStoreTestCase): def setUp(self): diff --git a/lms/djangoapps/courseware/tests/test_view_authentication.py b/lms/djangoapps/courseware/tests/test_view_authentication.py index 055c860fcc..849e5fdc45 100644 --- a/lms/djangoapps/courseware/tests/test_view_authentication.py +++ b/lms/djangoapps/courseware/tests/test_view_authentication.py @@ -16,10 +16,10 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from helpers import LoginEnrollmentTestCase, check_for_get_code -from modulestore_config import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Check that view authentication works properly. diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 377ada11f5..c6c382c8e4 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -18,23 +18,21 @@ from xmodule.modulestore.django import modulestore import courseware.views as views from xmodule.modulestore import Location from pytz import UTC -from modulestore_config import TEST_DATA_XML_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from course_modes.models import CourseMode -class Stub(): - pass - - -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestJumpTo(TestCase): - """Check the jumpto link for a course""" - def setUp(self): - self._MODULESTORES = {} + """ + Check the jumpto link for a course. + """ - # Toy courses should be loaded + def setUp(self): + + # Load toy course from XML self.course_name = 'edX/toy/2012_Fall' - self.toy_course = modulestore().get_course('edX/toy/2012_Fall') + self.toy_course = modulestore().get_course(self.course_name) def test_jumpto_invalid_location(self): location = Location('i4x', 'edX', 'toy', 'NoSuchPlace', None) @@ -73,7 +71,7 @@ class ViewsTestCase(TestCase): self.enrollment.created = self.date self.enrollment.save() self.location = ['tag', 'org', 'course', 'category', 'name'] - self._MODULESTORES = {} + # This is a CourseDescriptor object self.toy_course = modulestore().get_course('edX/toy/2012_Fall') self.request_factory = RequestFactory() @@ -87,7 +85,7 @@ class ViewsTestCase(TestCase): self.assertEquals(views.user_groups(mock_user), []) def test_get_current_child(self): - self.assertIsNone(views.get_current_child(Stub())) + self.assertIsNone(views.get_current_child(MagicMock())) mock_xmodule = MagicMock() mock_xmodule.position = -1 mock_xmodule.get_display_items.return_value = ['one', 'two'] diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py index 68b06a1ba8..98bcba4ed0 100644 --- a/lms/djangoapps/courseware/tests/tests.py +++ b/lms/djangoapps/courseware/tests/tests.py @@ -1,25 +1,20 @@ -''' -Test for lms courseware app -''' -import random - -from django.test import TestCase +""" +Test for LMS courseware app. +""" from django.core.urlresolvers import reverse from django.test.utils import override_settings -import xmodule.modulestore.django from xmodule.error_module import ErrorDescriptor from xmodule.modulestore.django import modulestore from xmodule.modulestore import Location from xmodule.modulestore.xml_importer import import_from_xml -from xmodule.modulestore.xml import XMLModuleStore +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase -from helpers import LoginEnrollmentTestCase -from modulestore_config import TEST_DATA_DIR, \ - TEST_DATA_XML_MODULESTORE, \ +from courseware.tests.helpers import LoginEnrollmentTestCase +from courseware.tests.modulestore_config import TEST_DATA_DIR, \ TEST_DATA_MONGO_MODULESTORE, \ - TEST_DATA_DRAFT_MONGO_MODULESTORE -import xmodule + TEST_DATA_DRAFT_MONGO_MODULESTORE, \ + TEST_DATA_MIXED_MODULESTORE class ActivateLoginTest(LoginEnrollmentTestCase): @@ -47,57 +42,60 @@ class PageLoaderTestCase(LoginEnrollmentTestCase): Base class that adds a function to load all pages in a modulestore. """ - def check_random_page_loads(self, module_store): + def check_all_pages_load(self, course_id): """ - Choose a page in the course randomly, and assert that it loads. + Assert that all pages in the course load correctly. + `course_id` is the ID of the course to check. """ - # enroll in the course before trying to access pages - courses = module_store.get_courses() - self.assertEqual(len(courses), 1) - course = courses[0] + + store = modulestore() + + # Enroll in the course before trying to access pages + course = store.get_course(course_id) self.enroll(course, True) - course_id = course.id # Search for items in the course # None is treated as a wildcard course_loc = course.location - location_query = Location(course_loc.tag, course_loc.org, - course_loc.course, None, None, None) + location_query = Location( + course_loc.tag, course_loc.org, + course_loc.course, None, None, None + ) - items = module_store.get_items(location_query, course_id=course_id) + items = store.get_items( + location_query, + course_id=course_id, + depth=2 + ) if len(items) < 1: self.fail('Could not retrieve any items from course') - else: - descriptor = random.choice(items) - # We have ancillary course information now as modules - # and we can't simply use 'jump_to' to view them - if descriptor.location.category == 'about': - self._assert_loads('about_course', - {'course_id': course_id}, - descriptor) + # Try to load each item in the course + for descriptor in items: - elif descriptor.location.category == 'static_tab': - kwargs = {'course_id': course_id, - 'tab_slug': descriptor.location.name} - self._assert_loads('static_tab', kwargs, descriptor) + if descriptor.location.category == 'about': + self._assert_loads('about_course', + {'course_id': course_id}, + descriptor) - elif descriptor.location.category == 'course_info': - self._assert_loads('info', {'course_id': course_id}, - descriptor) + elif descriptor.location.category == 'static_tab': + kwargs = {'course_id': course_id, + 'tab_slug': descriptor.location.name} + self._assert_loads('static_tab', kwargs, descriptor) - elif descriptor.location.category == 'custom_tag_template': - pass + elif descriptor.location.category == 'course_info': + self._assert_loads('info', {'course_id': course_id}, + descriptor) - else: + else: - kwargs = {'course_id': course_id, - 'location': descriptor.location.url()} + kwargs = {'course_id': course_id, + 'location': descriptor.location.url()} - self._assert_loads('jump_to', kwargs, descriptor, - expect_redirect=True, - check_content=True) + self._assert_loads('jump_to', kwargs, descriptor, + expect_redirect=True, + check_content=True) def _assert_loads(self, django_url, kwargs, descriptor, expect_redirect=False, @@ -124,54 +122,51 @@ class PageLoaderTestCase(LoginEnrollmentTestCase): self.assertNotIsInstance(descriptor, ErrorDescriptor) -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestCoursesLoadTestCase_XmlModulestore(PageLoaderTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestXmlCoursesLoad(ModuleStoreTestCase, PageLoaderTestCase): """ Check that all pages in test courses load properly from XML. """ def setUp(self): - super(TestCoursesLoadTestCase_XmlModulestore, self).setUp() + super(TestXmlCoursesLoad, self).setUp() self.setup_user() - xmodule.modulestore.django._MODULESTORES.clear() def test_toy_course_loads(self): - module_class = 'xmodule.hidden_module.HiddenDescriptor' - module_store = XMLModuleStore(TEST_DATA_DIR, - default_class=module_class, - course_dirs=['toy'], - load_error_modules=True) - self.check_random_page_loads(module_store) + # Load one of the XML based courses + # Our test mapping rules allow the MixedModuleStore + # to load this course from XML, not Mongo. + self.check_all_pages_load('edX/toy/2012_Fall') +# Importing XML courses isn't possible with MixedModuleStore, +# so we use a Mongo modulestore directly (as we would in Studio) @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) -class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase): +class TestMongoCoursesLoad(ModuleStoreTestCase, PageLoaderTestCase): """ Check that all pages in test courses load properly from Mongo. """ def setUp(self): - super(TestCoursesLoadTestCase_MongoModulestore, self).setUp() + super(TestMongoCoursesLoad, self).setUp() self.setup_user() - xmodule.modulestore.django._MODULESTORES.clear() - modulestore().collection.drop() + + # Import the toy course into a Mongo-backed modulestore + self.store = modulestore() + import_from_xml(self.store, TEST_DATA_DIR, ['toy']) def test_toy_course_loads(self): - module_store = modulestore() - import_from_xml(module_store, TEST_DATA_DIR, ['toy']) - self.check_random_page_loads(module_store) + self.check_all_pages_load('edX/toy/2012_Fall') def test_toy_textbooks_loads(self): - module_store = modulestore() - import_from_xml(module_store, TEST_DATA_DIR, ['toy']) - - course = module_store.get_item(Location(['i4x', 'edX', 'toy', 'course', '2012_Fall', None])) - + location = Location(['i4x', 'edX', 'toy', 'course', '2012_Fall', None]) + course = self.store.get_item(location) self.assertGreater(len(course.textbooks), 0) + @override_settings(MODULESTORE=TEST_DATA_DRAFT_MONGO_MODULESTORE) -class TestDraftModuleStore(TestCase): +class TestDraftModuleStore(ModuleStoreTestCase): def test_get_items_with_course_items(self): store = modulestore() diff --git a/lms/djangoapps/django_comment_client/base/tests.py b/lms/djangoapps/django_comment_client/base/tests.py index 434d4d616b..e6ce3b2d25 100644 --- a/lms/djangoapps/django_comment_client/base/tests.py +++ b/lms/djangoapps/django_comment_client/base/tests.py @@ -10,14 +10,14 @@ from django.core.urlresolvers import reverse from django.core.management import call_command from util.testing import UrlResetMixin -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from nose.tools import assert_true, assert_equal from mock import patch log = logging.getLogger(__name__) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) @patch('comment_client.utils.requests.request') class ViewsTestCase(UrlResetMixin, ModuleStoreTestCase): diff --git a/lms/djangoapps/django_comment_client/forum/tests.py b/lms/djangoapps/django_comment_client/forum/tests.py index bd18ab80d6..2d889722a4 100644 --- a/lms/djangoapps/django_comment_client/forum/tests.py +++ b/lms/djangoapps/django_comment_client/forum/tests.py @@ -6,7 +6,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from django.core.urlresolvers import reverse from util.testing import UrlResetMixin -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from nose.tools import assert_true from mock import patch, Mock @@ -15,7 +15,7 @@ import logging log = logging.getLogger(__name__) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): @patch.dict("django.conf.settings.MITX_FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) diff --git a/lms/djangoapps/instructor/tests/test_access.py b/lms/djangoapps/instructor/tests/test_access.py index 688ed89dad..1874e88f22 100644 --- a/lms/djangoapps/instructor/tests/test_access.py +++ b/lms/djangoapps/instructor/tests/test_access.py @@ -9,7 +9,7 @@ from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from django.test.utils import override_settings -from courseware.tests.modulestore_config import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from courseware.access import get_access_group_name from django_comment_common.models import (Role, @@ -20,7 +20,7 @@ from instructor.access import (allow_access, update_forum_role_membership) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAccessList(ModuleStoreTestCase): """ Test access listings. """ def setUp(self): @@ -42,7 +42,7 @@ class TestInstructorAccessList(ModuleStoreTestCase): self.assertEqual(set(beta_testers), set(self.beta_testers)) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAccessAllow(ModuleStoreTestCase): """ Test access allow. """ def setUp(self): @@ -85,7 +85,8 @@ class TestInstructorAccessAllow(ModuleStoreTestCase): group = Group.objects.get(name=get_access_group_name(self.course, 'staff')) self.assertIn(user, group.user_set.all()) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) + +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAccessRevoke(ModuleStoreTestCase): """ Test access revoke. """ def setUp(self): @@ -129,7 +130,7 @@ class TestInstructorAccessRevoke(ModuleStoreTestCase): self.assertNotIn(user, group.user_set.all()) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAccessForum(ModuleStoreTestCase): """ Test forum access control. diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 155a8a2c9f..7d55b001d0 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -14,7 +14,7 @@ from django.core.urlresolvers import reverse from django.http import HttpRequest, HttpResponse from django.contrib.auth.models import User -from courseware.tests.modulestore_config import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from courseware.tests.helpers import LoginEnrollmentTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -90,7 +90,7 @@ class TestCommonExceptions400(unittest.TestCase): self.assertIn("Task is already running", result["error"]) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Ensure that users cannot access endpoints they shouldn't be able to. @@ -147,7 +147,7 @@ class TestInstructorAPIDenyLevels(ModuleStoreTestCase, LoginEnrollmentTestCase): self.assertEqual(response.status_code, 403) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Test enrollment modification endpoint. @@ -270,7 +270,7 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): self.assertEqual(res_json, expected) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints whereby instructors can change permissions @@ -414,7 +414,7 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase self.assertEqual(res_json, expected) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints that show data without side effects. @@ -521,7 +521,7 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa self.assertEqual(response.status_code, 400) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Test endpoints whereby instructors can change student grades. @@ -655,7 +655,7 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) self.assertTrue(act.called) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Test instructor task list endpoint. @@ -745,7 +745,7 @@ class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase): self.assertEqual(json.loads(response.content), expected_res) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) @override_settings(ANALYTICS_SERVER_URL="http://robotanalyticsserver.netbot:900/") @override_settings(ANALYTICS_API_KEY="robot_api_key") class TestInstructorAPIAnalyticsProxy(ModuleStoreTestCase, LoginEnrollmentTestCase): diff --git a/lms/djangoapps/instructor/tests/test_hint_manager.py b/lms/djangoapps/instructor/tests/test_hint_manager.py index 8e394d6e54..456f8e0ed8 100644 --- a/lms/djangoapps/instructor/tests/test_hint_manager.py +++ b/lms/djangoapps/instructor/tests/test_hint_manager.py @@ -5,14 +5,14 @@ from django.test.utils import override_settings from courseware.models import XModuleContentField from courseware.tests.factories import ContentFactory -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE import instructor.hint_manager as view from student.tests.factories import UserFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class HintManagerTest(ModuleStoreTestCase): def setUp(self): diff --git a/lms/djangoapps/instructor/tests/test_legacy_download_csv.py b/lms/djangoapps/instructor/tests/test_legacy_download_csv.py index b05746f015..c65547e408 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_download_csv.py +++ b/lms/djangoapps/instructor/tests/test_legacy_download_csv.py @@ -17,21 +17,20 @@ from django.core.urlresolvers import reverse from courseware.access import _course_staff_group_name from courseware.tests.helpers import LoginEnrollmentTestCase -from courseware.tests.modulestore_config import TEST_DATA_XML_MODULESTORE -from xmodule.modulestore.django import modulestore +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase +from xmodule.modulestore.django import modulestore, clear_existing_modulestores import xmodule.modulestore.django -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestInstructorDashboardGradeDownloadCSV(LoginEnrollmentTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestInstructorDashboardGradeDownloadCSV(ModuleStoreTestCase, LoginEnrollmentTestCase): ''' Check for download of csv ''' def setUp(self): - xmodule.modulestore.django._MODULESTORES = {} - - self.full = modulestore().get_course("edX/full/6.002_Spring_2012") + clear_existing_modulestores() self.toy = modulestore().get_course("edX/toy/2012_Fall") # Create two accounts diff --git a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py index 1f5ea8ad56..4c1c252891 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_enrollment.py +++ b/lms/djangoapps/instructor/tests/test_legacy_enrollment.py @@ -7,7 +7,7 @@ from django.test.utils import override_settings from django.contrib.auth.models import User from django.core.urlresolvers import reverse from courseware.tests.helpers import LoginEnrollmentTestCase -from courseware.tests.modulestore_config import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from xmodule.modulestore.tests.factories import CourseFactory from student.tests.factories import UserFactory, CourseEnrollmentFactory, AdminFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -18,7 +18,7 @@ from django.core import mail USER_COUNT = 4 -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestInstructorEnrollsStudent(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Check Enrollment/Unenrollment with/without auto-enrollment on activation and with/without email notification diff --git a/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py b/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py index 90dadd569e..29046b151f 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py +++ b/lms/djangoapps/instructor/tests/test_legacy_forum_admin.py @@ -15,9 +15,9 @@ from django_comment_client.utils import has_forum_access from courseware.access import _course_staff_group_name from courseware.tests.helpers import LoginEnrollmentTestCase -from courseware.tests.modulestore_config import TEST_DATA_XML_MODULESTORE -from xmodule.modulestore.django import modulestore -import xmodule.modulestore.django +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE +from xmodule.modulestore.django import modulestore, clear_existing_modulestores +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase FORUM_ROLES = [FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA] @@ -32,14 +32,14 @@ def action_name(operation, rolename): return '{0} forum {1}'.format(operation, FORUM_ADMIN_ACTION_SUFFIX[rolename]) -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestInstructorDashboardForumAdmin(LoginEnrollmentTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestInstructorDashboardForumAdmin(ModuleStoreTestCase, LoginEnrollmentTestCase): ''' Check for change in forum admin role memberships ''' def setUp(self): - xmodule.modulestore.django._MODULESTORES = {} + clear_existing_modulestores() courses = modulestore().get_courses() self.course_id = "edX/toy/2012_Fall" diff --git a/lms/djangoapps/instructor/tests/test_legacy_gradebook.py b/lms/djangoapps/instructor/tests/test_legacy_gradebook.py index aaf03deb8c..fd285d2e3f 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_gradebook.py +++ b/lms/djangoapps/instructor/tests/test_legacy_gradebook.py @@ -7,7 +7,7 @@ from django.core.urlresolvers import reverse 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 courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.tests import TEST_DATA_MIXED_MODULESTORE from capa.tests.response_xml_factory import StringResponseXMLFactory from courseware.tests.factories import StudentModuleFactory from xmodule.modulestore import Location @@ -17,7 +17,7 @@ from xmodule.modulestore.django import modulestore USER_COUNT = 11 -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestGradebook(ModuleStoreTestCase): grading_policy = None diff --git a/lms/djangoapps/instructor/tests/test_legacy_xss.py b/lms/djangoapps/instructor/tests/test_legacy_xss.py index 7df6511b3c..d748876032 100644 --- a/lms/djangoapps/instructor/tests/test_legacy_xss.py +++ b/lms/djangoapps/instructor/tests/test_legacy_xss.py @@ -7,14 +7,15 @@ from django.test.client import RequestFactory from django.test.utils import override_settings from markupsafe import escape -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.tests import TEST_DATA_MIXED_MODULESTORE from student.tests.factories import UserFactory, CourseEnrollmentFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from instructor.views import legacy -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) + +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class TestXss(ModuleStoreTestCase): def setUp(self): self._request_factory = RequestFactory() diff --git a/lms/djangoapps/instructor_task/tests/test_base.py b/lms/djangoapps/instructor_task/tests/test_base.py index b67453e997..2c1fe02bd8 100644 --- a/lms/djangoapps/instructor_task/tests/test_base.py +++ b/lms/djangoapps/instructor_task/tests/test_base.py @@ -13,13 +13,13 @@ from django.contrib.auth.models import User from django.test.utils import override_settings from capa.tests.response_xml_factory import OptionResponseXMLFactory -from xmodule.modulestore.django import modulestore +from xmodule.modulestore.django import editable_modulestore from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from student.tests.factories import CourseEnrollmentFactory, UserFactory from courseware.model_data import StudentModule -from courseware.tests.tests import LoginEnrollmentTestCase, TEST_DATA_MONGO_MODULESTORE +from courseware.tests.tests import LoginEnrollmentTestCase, TEST_DATA_MIXED_MODULESTORE from instructor_task.api_helper import encode_problem_and_student_input from instructor_task.models import PROGRESS, QUEUING @@ -95,7 +95,7 @@ class InstructorTaskTestCase(TestCase): return self._create_entry(task_state=task_state, task_output=progress, student=student) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class InstructorTaskModuleTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase): """ Base test class for InstructorTask-related tests that require @@ -106,7 +106,7 @@ class InstructorTaskModuleTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase) def initialize_course(self): """Create a course in the store, with a chapter and section.""" - self.module_store = modulestore() + self.module_store = editable_modulestore() # Create the course self.course = CourseFactory.create(org=TEST_COURSE_ORG, diff --git a/lms/djangoapps/licenses/tests.py b/lms/djangoapps/licenses/tests.py index 151a0faa9d..a853955c83 100644 --- a/lms/djangoapps/licenses/tests.py +++ b/lms/djangoapps/licenses/tests.py @@ -14,7 +14,7 @@ from django.core.management import call_command from django.core.urlresolvers import reverse from nose.tools import assert_true -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from licenses.models import CourseSoftware, UserLicense from student.tests.factories import UserFactory @@ -143,7 +143,7 @@ class LicenseTestCase(TestCase): self.assertEqual(302, response.status_code) -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class CommandTest(ModuleStoreTestCase): '''Test management command for importing serial numbers''' def setUp(self): diff --git a/lms/djangoapps/open_ended_grading/tests.py b/lms/djangoapps/open_ended_grading/tests.py index 262124d667..7ae5994dc1 100644 --- a/lms/djangoapps/open_ended_grading/tests.py +++ b/lms/djangoapps/open_ended_grading/tests.py @@ -27,14 +27,15 @@ log = logging.getLogger(__name__) from django.test.utils import override_settings from xmodule.tests import test_util_open_ended +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from courseware.tests import factories -from courseware.tests.modulestore_config import TEST_DATA_XML_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from courseware.tests.helpers import LoginEnrollmentTestCase, check_for_get_code, check_for_post_code -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestStaffGradingService(LoginEnrollmentTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestStaffGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase): ''' Check that staff grading service proxy works. Basically just checking the access control and error handling logic -- all the actual work is on the @@ -42,8 +43,6 @@ class TestStaffGradingService(LoginEnrollmentTestCase): ''' def setUp(self): - xmodule.modulestore.django._MODULESTORES = {} - self.student = 'view@test.com' self.instructor = 'view2@test.com' self.password = 'foo' @@ -138,8 +137,8 @@ class TestStaffGradingService(LoginEnrollmentTestCase): self.assertIsNotNone(content['problem_list']) -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestPeerGradingService(LoginEnrollmentTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestPeerGradingService(ModuleStoreTestCase, LoginEnrollmentTestCase): ''' Check that staff grading service proxy works. Basically just checking the access control and error handling logic -- all the actual work is on the @@ -147,8 +146,6 @@ class TestPeerGradingService(LoginEnrollmentTestCase): ''' def setUp(self): - xmodule.modulestore.django._MODULESTORES = {} - self.student = 'view@test.com' self.instructor = 'view2@test.com' self.password = 'foo' @@ -293,8 +290,8 @@ class TestPeerGradingService(LoginEnrollmentTestCase): self.assertFalse('actual_score' in response) -@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) -class TestPanel(LoginEnrollmentTestCase): +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) +class TestPanel(ModuleStoreTestCase, LoginEnrollmentTestCase): """ Run tests on the open ended panel """ diff --git a/lms/djangoapps/staticbook/tests.py b/lms/djangoapps/staticbook/tests.py index deb13ffc9e..135150a2d1 100644 --- a/lms/djangoapps/staticbook/tests.py +++ b/lms/djangoapps/staticbook/tests.py @@ -10,7 +10,7 @@ import requests from django.test.utils import override_settings from django.core.urlresolvers import reverse, NoReverseMatch -from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE +from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from student.tests.factories import UserFactory, CourseEnrollmentFactory from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -36,7 +36,8 @@ HTML_BOOK = { ], } -@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) + +@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE) class StaticBookTest(ModuleStoreTestCase): """ Helpers for the static book tests. diff --git a/lms/envs/acceptance.py b/lms/envs/acceptance.py index cf64404161..e866a250d9 100644 --- a/lms/envs/acceptance.py +++ b/lms/envs/acceptance.py @@ -36,15 +36,21 @@ modulestore_options = { MODULESTORE = { 'default': { - 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', - 'OPTIONS': modulestore_options - }, - 'direct': { - 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', - 'OPTIONS': modulestore_options + 'ENGINE': 'xmodule.modulestore.mixed.MixedModuleStore', + 'OPTIONS': { + 'mappings': {}, + 'stores': { + 'default': { + 'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore', + 'OPTIONS': modulestore_options + } + } + } } } +MODULESTORE['direct'] = MODULESTORE['default'] + CONTENTSTORE = { 'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore', 'OPTIONS': {