Commit 8d9e9076 by David Ormsbee

Merge pull request #9070 from edx/ormsbee/test_ms_class_setup_teardown

Modulestore test base class using setUpClass() and tearDownClass()
parents b40fa0a9 58f36d3e
...@@ -159,6 +159,23 @@ def xml_store_config(data_dir, source_dirs=None): ...@@ -159,6 +159,23 @@ def xml_store_config(data_dir, source_dirs=None):
return store return store
@patch('xmodule.modulestore.django.create_modulestore_instance')
def drop_mongo_collections(mock_create):
"""
If using a Mongo-backed modulestore & contentstore, drop the collections.
"""
# Do not create the modulestore if it does not exist.
mock_create.return_value = None
module_store = modulestore()
if hasattr(module_store, '_drop_database'):
module_store._drop_database() # pylint: disable=protected-access
_CONTENTSTORE.clear()
if hasattr(module_store, 'close_connections'):
module_store.close_connections()
TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
# This is an XML only modulestore with only the toy course loaded # This is an XML only modulestore with only the toy course loaded
...@@ -198,6 +215,71 @@ TEST_DATA_SPLIT_MODULESTORE = mixed_store_config( ...@@ -198,6 +215,71 @@ TEST_DATA_SPLIT_MODULESTORE = mixed_store_config(
) )
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.
If your tests modify contents in the ModuleStore, you should use
ModuleStoreTestCase instead.
How to use::
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from student.tests.factories import CourseEnrollmentFactory, UserFactory
class MyModuleStoreTestCase(SharedModuleStoreTestCase):
@classmethod
def setUpClass(cls):
super(MyModuleStoreTestCase, cls).setUpClass()
cls.course = CourseFactory.create()
def setUp(self):
super(MyModuleStoreTestCase, self).setUp()
self.user = UserFactory.create()
CourseEnrollmentFactory.create(
user=self.user, course_id=self.course.id
)
Important things to note:
1. You're creating the course in setUpClass(), *not* in setUp().
2. Any Django ORM operations should still happen in setUp(). Models created
in setUpClass() will *not* be cleaned up, and will leave side-effects
that can break other, completely unrelated test cases.
In Django 1.8, we will be able to use setUpTestData() to do class level init
for Django ORM models that will get cleaned up properly.
"""
MODULESTORE = mixed_store_config(mkdtemp_clean(), {}, include_xml=False)
@classmethod
def setUpClass(cls):
super(SharedModuleStoreTestCase, cls).setUpClass()
cls._settings_override = override_settings(MODULESTORE=cls.MODULESTORE)
cls._settings_override.__enter__()
XMODULE_FACTORY_LOCK.enable()
clear_existing_modulestores()
cls.store = modulestore()
@classmethod
def tearDownClass(cls):
drop_mongo_collections() # pylint: disable=no-value-for-parameter
RequestCache().clear_request_cache()
XMODULE_FACTORY_LOCK.disable()
cls._settings_override.__exit__(None, None, None)
super(SharedModuleStoreTestCase, cls).tearDownClass()
def setUp(self):
# OverrideFieldData.provider_classes is always reset to `None` so
# that they're recalculated for every test
OverrideFieldData.provider_classes = None
super(SharedModuleStoreTestCase, self).setUp()
class ModuleStoreTestCase(TestCase): class ModuleStoreTestCase(TestCase):
""" """
Subclass for any test case that uses a ModuleStore. Subclass for any test case that uses a ModuleStore.
...@@ -254,8 +336,7 @@ class ModuleStoreTestCase(TestCase): ...@@ -254,8 +336,7 @@ class ModuleStoreTestCase(TestCase):
# which will cause them to be re-created # which will cause them to be re-created
clear_existing_modulestores() clear_existing_modulestores()
self.addCleanup(self.drop_mongo_collections) self.addCleanup(drop_mongo_collections)
self.addCleanup(RequestCache().clear_request_cache) self.addCleanup(RequestCache().clear_request_cache)
# Enable XModuleFactories for the space of this test (and its setUp). # Enable XModuleFactories for the space of this test (and its setUp).
...@@ -317,22 +398,6 @@ class ModuleStoreTestCase(TestCase): ...@@ -317,22 +398,6 @@ class ModuleStoreTestCase(TestCase):
updated_course = self.store.get_course(course.id) updated_course = self.store.get_course(course.id)
return updated_course return updated_course
@staticmethod
@patch('xmodule.modulestore.django.create_modulestore_instance')
def drop_mongo_collections(mock_create):
"""
If using a Mongo-backed modulestore & contentstore, drop the collections.
"""
# Do not create the modulestore if it does not exist.
mock_create.return_value = None
module_store = modulestore()
if hasattr(module_store, '_drop_database'):
module_store._drop_database() # pylint: disable=protected-access
_CONTENTSTORE.clear()
if hasattr(module_store, 'close_connections'):
module_store.close_connections()
def create_sample_course(self, org, course, run, block_info_tree=None, course_fields=None): def create_sample_course(self, org, course, run, block_info_tree=None, course_fields=None):
""" """
create a course in the default modulestore from the collection of BlockInfo create a course in the default modulestore from the collection of BlockInfo
......
...@@ -8,57 +8,64 @@ from itertools import izip_longest, chain ...@@ -8,57 +8,64 @@ from itertools import izip_longest, chain
import pytz import pytz
from student.tests.factories import AdminFactory from student.tests.factories import AdminFactory
from xmodule.modulestore.tests.django_utils import ( from xmodule.modulestore.tests.django_utils import (
ModuleStoreTestCase, SharedModuleStoreTestCase,
TEST_DATA_SPLIT_MODULESTORE TEST_DATA_SPLIT_MODULESTORE
) )
from student.tests.factories import UserFactory
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from ..models import CustomCourseForEdX from ..models import CustomCourseForEdX
class TestCCXModulestoreWrapper(ModuleStoreTestCase): class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
"""tests for a modulestore wrapped by CCXModulestoreWrapper """tests for a modulestore wrapped by CCXModulestoreWrapper
""" """
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
def setUp(self): @classmethod
""" def setUpClass(cls):
Set up tests super(TestCCXModulestoreWrapper, cls).setUpClass()
""" cls.course = course = CourseFactory.create()
super(TestCCXModulestoreWrapper, self).setUp() cls.mooc_start = start = datetime.datetime(
self.course = course = CourseFactory.create() 2010, 5, 12, 2, 42, tzinfo=pytz.UTC
)
# Create instructor account cls.mooc_due = due = datetime.datetime(
coach = AdminFactory.create() 2010, 7, 7, 0, 0, tzinfo=pytz.UTC
)
# Create a course outline # Create a course outline
self.mooc_start = start = datetime.datetime( cls.chapters = chapters = [
2010, 5, 12, 2, 42, tzinfo=pytz.UTC)
self.mooc_due = due = datetime.datetime(
2010, 7, 7, 0, 0, tzinfo=pytz.UTC)
self.chapters = chapters = [
ItemFactory.create(start=start, parent=course) for _ in xrange(2) ItemFactory.create(start=start, parent=course) for _ in xrange(2)
] ]
self.sequentials = sequentials = [ cls.sequentials = sequentials = [
ItemFactory.create(parent=c) for _ in xrange(2) for c in chapters ItemFactory.create(parent=c) for _ in xrange(2) for c in chapters
] ]
self.verticals = verticals = [ cls.verticals = verticals = [
ItemFactory.create( ItemFactory.create(
due=due, parent=s, graded=True, format='Homework' due=due, parent=s, graded=True, format='Homework'
) for _ in xrange(2) for s in sequentials ) for _ in xrange(2) for s in sequentials
] ]
self.blocks = [ cls.blocks = [
ItemFactory.create(parent=v) for _ in xrange(2) for v in verticals ItemFactory.create(parent=v) for _ in xrange(2) for v in verticals
] ]
def setUp(self):
"""
Set up tests
"""
super(TestCCXModulestoreWrapper, self).setUp()
self.user = UserFactory.create()
# Create instructor account
coach = AdminFactory.create()
self.ccx = ccx = CustomCourseForEdX( self.ccx = ccx = CustomCourseForEdX(
course_id=course.id, course_id=self.course.id,
display_name='Test CCX', display_name='Test CCX',
coach=coach coach=coach
) )
ccx.save() ccx.save()
self.ccx_locator = CCXLocator.from_course_locator(course.id, ccx.id) # pylint: disable=no-member self.ccx_locator = CCXLocator.from_course_locator(self.course.id, ccx.id) # pylint: disable=no-member
def get_all_children_bf(self, block): def get_all_children_bf(self, block):
"""traverse the children of block in a breadth-first order""" """traverse the children of block in a breadth-first order"""
......
...@@ -49,7 +49,7 @@ from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory ...@@ -49,7 +49,7 @@ from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from student.tests.factories import CourseEnrollmentFactory, UserFactory from student.tests.factories import CourseEnrollmentFactory, UserFactory
from util.testing import UrlResetMixin from util.testing import UrlResetMixin
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
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 xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.partitions.partitions import Group, UserPartition from xmodule.partitions.partitions import Group, UserPartition
...@@ -64,18 +64,36 @@ def _remove_discussion_tab(course, user_id): ...@@ -64,18 +64,36 @@ def _remove_discussion_tab(course, user_id):
modulestore().update_item(course, user_id) modulestore().update_item(course, user_id)
def _discussion_disabled_course_for(user):
"""
Create and return a course with discussions disabled.
The user passed in will be enrolled in the course.
"""
course_with_disabled_forums = CourseFactory.create()
CourseEnrollmentFactory.create(user=user, course_id=course_with_disabled_forums.id)
_remove_discussion_tab(course_with_disabled_forums, user.id)
return course_with_disabled_forums
@ddt.ddt @ddt.ddt
class GetCourseTest(UrlResetMixin, ModuleStoreTestCase): class GetCourseTest(UrlResetMixin, SharedModuleStoreTestCase):
"""Test for get_course""" """Test for get_course"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(GetCourseTest, cls).setUpClass()
cls.course = CourseFactory.create(org="x", course="y", run="z")
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(GetCourseTest, self).setUp() super(GetCourseTest, self).setUp()
self.course = CourseFactory.create(org="x", course="y", run="z")
self.user = UserFactory.create() self.user = UserFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
self.request = RequestFactory().get("/dummy") self.request = RequestFactory().get("/dummy")
self.request.user = self.user self.request.user = self.user
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
def test_nonexistent_course(self): def test_nonexistent_course(self):
with self.assertRaises(Http404): with self.assertRaises(Http404):
...@@ -88,9 +106,8 @@ class GetCourseTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -88,9 +106,8 @@ class GetCourseTest(UrlResetMixin, ModuleStoreTestCase):
get_course(self.request, self.course.id) get_course(self.request, self.course.id)
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id)
with self.assertRaises(Http404): with self.assertRaises(Http404):
get_course(self.request, self.course.id) get_course(self.request, _discussion_disabled_course_for(self.user).id)
def test_basic(self): def test_basic(self):
self.assertEqual( self.assertEqual(
...@@ -248,16 +265,17 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -248,16 +265,17 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase):
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
def test_many(self): def test_many(self):
self.course.discussion_topics = { with self.store.bulk_operations(self.course.id, emit_signals=False):
"A": {"id": "non-courseware-1"}, self.course.discussion_topics = {
"B": {"id": "non-courseware-2"}, "A": {"id": "non-courseware-1"},
} "B": {"id": "non-courseware-2"},
modulestore().update_item(self.course, self.user.id) }
self.make_discussion_module("courseware-1", "A", "1") self.store.update_item(self.course, self.user.id)
self.make_discussion_module("courseware-2", "A", "2") self.make_discussion_module("courseware-1", "A", "1")
self.make_discussion_module("courseware-3", "B", "1") self.make_discussion_module("courseware-2", "A", "2")
self.make_discussion_module("courseware-4", "B", "2") self.make_discussion_module("courseware-3", "B", "1")
self.make_discussion_module("courseware-5", "C", "1") self.make_discussion_module("courseware-4", "B", "2")
self.make_discussion_module("courseware-5", "C", "1")
actual = self.get_course_topics() actual = self.get_course_topics()
expected = { expected = {
"courseware_topics": [ "courseware_topics": [
...@@ -291,20 +309,22 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -291,20 +309,22 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase):
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
def test_sort_key(self): def test_sort_key(self):
self.course.discussion_topics = { with self.store.bulk_operations(self.course.id, emit_signals=False):
"W": {"id": "non-courseware-1", "sort_key": "Z"}, self.course.discussion_topics = {
"X": {"id": "non-courseware-2"}, "W": {"id": "non-courseware-1", "sort_key": "Z"},
"Y": {"id": "non-courseware-3", "sort_key": "Y"}, "X": {"id": "non-courseware-2"},
"Z": {"id": "non-courseware-4", "sort_key": "W"}, "Y": {"id": "non-courseware-3", "sort_key": "Y"},
} "Z": {"id": "non-courseware-4", "sort_key": "W"},
modulestore().update_item(self.course, self.user.id) }
self.make_discussion_module("courseware-1", "First", "A", sort_key="D") self.store.update_item(self.course, self.user.id)
self.make_discussion_module("courseware-2", "First", "B", sort_key="B") self.make_discussion_module("courseware-1", "First", "A", sort_key="D")
self.make_discussion_module("courseware-3", "First", "C", sort_key="E") self.make_discussion_module("courseware-2", "First", "B", sort_key="B")
self.make_discussion_module("courseware-4", "Second", "A", sort_key="F") self.make_discussion_module("courseware-3", "First", "C", sort_key="E")
self.make_discussion_module("courseware-5", "Second", "B", sort_key="G") self.make_discussion_module("courseware-4", "Second", "A", sort_key="F")
self.make_discussion_module("courseware-6", "Second", "C") self.make_discussion_module("courseware-5", "Second", "B", sort_key="G")
self.make_discussion_module("courseware-7", "Second", "D", sort_key="A") self.make_discussion_module("courseware-6", "Second", "C")
self.make_discussion_module("courseware-7", "Second", "D", sort_key="A")
actual = self.get_course_topics() actual = self.get_course_topics()
expected = { expected = {
"courseware_topics": [ "courseware_topics": [
...@@ -364,26 +384,27 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -364,26 +384,27 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase):
group_id=self.partition.groups[group_idx].id group_id=self.partition.groups[group_idx].id
) )
self.make_discussion_module("courseware-1", "First", "Everybody") with self.store.bulk_operations(self.course.id, emit_signals=False):
self.make_discussion_module( self.make_discussion_module("courseware-1", "First", "Everybody")
"courseware-2", self.make_discussion_module(
"First", "courseware-2",
"Cohort A", "First",
group_access={self.partition.id: [self.partition.groups[0].id]} "Cohort A",
) group_access={self.partition.id: [self.partition.groups[0].id]}
self.make_discussion_module( )
"courseware-3", self.make_discussion_module(
"First", "courseware-3",
"Cohort B", "First",
group_access={self.partition.id: [self.partition.groups[1].id]} "Cohort B",
) group_access={self.partition.id: [self.partition.groups[1].id]}
self.make_discussion_module("courseware-4", "Second", "Staff Only", visible_to_staff_only=True) )
self.make_discussion_module( self.make_discussion_module("courseware-4", "Second", "Staff Only", visible_to_staff_only=True)
"courseware-5", self.make_discussion_module(
"Second", "courseware-5",
"Future Start Date", "Second",
start=datetime.now(UTC) + timedelta(days=1) "Future Start Date",
) start=datetime.now(UTC) + timedelta(days=1)
)
student_actual = self.get_course_topics() student_actual = self.get_course_topics()
student_expected = { student_expected = {
...@@ -456,8 +477,15 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase): ...@@ -456,8 +477,15 @@ class GetCourseTopicsTest(UrlResetMixin, ModuleStoreTestCase):
@ddt.ddt @ddt.ddt
class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Test for get_thread_list""" """Test for get_thread_list"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(GetThreadListTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(GetThreadListTest, self).setUp() super(GetThreadListTest, self).setUp()
...@@ -469,7 +497,6 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -469,7 +497,6 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
self.author = UserFactory.create() self.author = UserFactory.create()
self.cohort = CohortFactory.create(course_id=self.course.id) self.cohort = CohortFactory.create(course_id=self.course.id)
...@@ -502,9 +529,8 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -502,9 +529,8 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
self.get_thread_list([]) self.get_thread_list([])
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id)
with self.assertRaises(Http404): with self.assertRaises(Http404):
self.get_thread_list([]) self.get_thread_list([], course=_discussion_disabled_course_for(self.user))
def test_empty(self): def test_empty(self):
self.assertEqual( self.assertEqual(
...@@ -812,8 +838,15 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -812,8 +838,15 @@ class GetThreadListTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
@ddt.ddt @ddt.ddt
class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase): class GetCommentListTest(CommentsServiceMockMixin, SharedModuleStoreTestCase):
"""Test for get_comment_list""" """Test for get_comment_list"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(GetCommentListTest, cls).setUpClass()
cls.course = CourseFactory.create()
def setUp(self): def setUp(self):
super(GetCommentListTest, self).setUp() super(GetCommentListTest, self).setUp()
httpretty.reset() httpretty.reset()
...@@ -824,7 +857,6 @@ class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase): ...@@ -824,7 +857,6 @@ class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
self.author = UserFactory.create() self.author = UserFactory.create()
...@@ -861,9 +893,13 @@ class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase): ...@@ -861,9 +893,13 @@ class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
self.get_comment_list(self.make_minimal_cs_thread()) self.get_comment_list(self.make_minimal_cs_thread())
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id) disabled_course = _discussion_disabled_course_for(self.user)
with self.assertRaises(Http404): with self.assertRaises(Http404):
self.get_comment_list(self.make_minimal_cs_thread()) self.get_comment_list(
self.make_minimal_cs_thread(
overrides={"course_id": unicode(disabled_course.id)}
)
)
@ddt.data( @ddt.data(
*itertools.product( *itertools.product(
...@@ -1224,8 +1260,14 @@ class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase): ...@@ -1224,8 +1260,14 @@ class GetCommentListTest(CommentsServiceMockMixin, ModuleStoreTestCase):
@ddt.ddt @ddt.ddt
class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Tests for create_thread""" """Tests for create_thread"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(CreateThreadTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(CreateThreadTest, self).setUp() super(CreateThreadTest, self).setUp()
...@@ -1236,7 +1278,6 @@ class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -1236,7 +1278,6 @@ class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
self.minimal_data = { self.minimal_data = {
"course_id": unicode(self.course.id), "course_id": unicode(self.course.id),
...@@ -1447,7 +1488,8 @@ class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -1447,7 +1488,8 @@ class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
self.assertEqual(assertion.exception.message_dict, {"course_id": ["Invalid value."]}) self.assertEqual(assertion.exception.message_dict, {"course_id": ["Invalid value."]})
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id) disabled_course = _discussion_disabled_course_for(self.user)
self.minimal_data["course_id"] = unicode(disabled_course.id)
with self.assertRaises(ValidationError) as assertion: with self.assertRaises(ValidationError) as assertion:
create_thread(self.request, self.minimal_data) create_thread(self.request, self.minimal_data)
self.assertEqual(assertion.exception.message_dict, {"course_id": ["Invalid value."]}) self.assertEqual(assertion.exception.message_dict, {"course_id": ["Invalid value."]})
...@@ -1460,8 +1502,14 @@ class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -1460,8 +1502,14 @@ class CreateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
@ddt.ddt @ddt.ddt
class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Tests for create_comment""" """Tests for create_comment"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(CreateCommentTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(CreateCommentTest, self).setUp() super(CreateCommentTest, self).setUp()
...@@ -1472,7 +1520,6 @@ class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -1472,7 +1520,6 @@ class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
self.register_get_thread_response( self.register_get_thread_response(
make_minimal_cs_thread({ make_minimal_cs_thread({
...@@ -1654,7 +1701,14 @@ class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -1654,7 +1701,14 @@ class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
self.assertEqual(assertion.exception.message_dict, {"thread_id": ["Invalid value."]}) self.assertEqual(assertion.exception.message_dict, {"thread_id": ["Invalid value."]})
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id) disabled_course = _discussion_disabled_course_for(self.user)
self.register_get_thread_response(
make_minimal_cs_thread({
"id": "test_thread",
"course_id": unicode(disabled_course.id),
"commentable_id": "test_topic",
})
)
with self.assertRaises(ValidationError) as assertion: with self.assertRaises(ValidationError) as assertion:
create_comment(self.request, self.minimal_data) create_comment(self.request, self.minimal_data)
self.assertEqual(assertion.exception.message_dict, {"thread_id": ["Invalid value."]}) self.assertEqual(assertion.exception.message_dict, {"thread_id": ["Invalid value."]})
...@@ -1713,8 +1767,14 @@ class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -1713,8 +1767,14 @@ class CreateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
@ddt.ddt @ddt.ddt
class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Tests for update_thread""" """Tests for update_thread"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(UpdateThreadTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(UpdateThreadTest, self).setUp() super(UpdateThreadTest, self).setUp()
...@@ -1725,7 +1785,6 @@ class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -1725,7 +1785,6 @@ class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
def register_thread(self, overrides=None): def register_thread(self, overrides=None):
...@@ -1825,8 +1884,8 @@ class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -1825,8 +1884,8 @@ class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
update_thread(self.request, "test_thread", {}) update_thread(self.request, "test_thread", {})
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id) disabled_course = _discussion_disabled_course_for(self.user)
self.register_thread() self.register_thread(overrides={"course_id": unicode(disabled_course.id)})
with self.assertRaises(Http404): with self.assertRaises(Http404):
update_thread(self.request, "test_thread", {}) update_thread(self.request, "test_thread", {})
...@@ -2015,31 +2074,41 @@ class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -2015,31 +2074,41 @@ class UpdateThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
@ddt.ddt @ddt.ddt
class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Tests for update_comment""" """Tests for update_comment"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(UpdateCommentTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(UpdateCommentTest, self).setUp() super(UpdateCommentTest, self).setUp()
self.user = UserFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
httpretty.reset() httpretty.reset()
httpretty.enable() httpretty.enable()
self.addCleanup(httpretty.disable) self.addCleanup(httpretty.disable)
self.user = UserFactory.create()
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) def register_comment(self, overrides=None, thread_overrides=None, course=None):
def register_comment(self, overrides=None, thread_overrides=None):
""" """
Make a comment with appropriate data overridden by the overrides Make a comment with appropriate data overridden by the overrides
parameter and register mock responses for both GET and PUT on its parameter and register mock responses for both GET and PUT on its
endpoint. Also mock GET for the related thread with thread_overrides. endpoint. Also mock GET for the related thread with thread_overrides.
""" """
if course is None:
course = self.course
cs_thread_data = make_minimal_cs_thread({ cs_thread_data = make_minimal_cs_thread({
"id": "test_thread", "id": "test_thread",
"course_id": unicode(self.course.id) "course_id": unicode(course.id)
}) })
cs_thread_data.update(thread_overrides or {}) cs_thread_data.update(thread_overrides or {})
self.register_get_thread_response(cs_thread_data) self.register_get_thread_response(cs_thread_data)
...@@ -2057,6 +2126,7 @@ class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -2057,6 +2126,7 @@ class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
self.register_get_comment_response(cs_comment_data) self.register_get_comment_response(cs_comment_data)
self.register_put_comment_response(cs_comment_data) self.register_put_comment_response(cs_comment_data)
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def test_empty(self): def test_empty(self):
"""Check that an empty update does not make any modifying requests.""" """Check that an empty update does not make any modifying requests."""
self.register_comment() self.register_comment()
...@@ -2118,8 +2188,7 @@ class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -2118,8 +2188,7 @@ class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
update_comment(self.request, "test_comment", {}) update_comment(self.request, "test_comment", {})
def test_discussions_disabled(self): def test_discussions_disabled(self):
_remove_discussion_tab(self.course, self.user.id) self.register_comment(course=_discussion_disabled_course_for(self.user))
self.register_comment()
with self.assertRaises(Http404): with self.assertRaises(Http404):
update_comment(self.request, "test_comment", {}) update_comment(self.request, "test_comment", {})
...@@ -2309,8 +2378,14 @@ class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -2309,8 +2378,14 @@ class UpdateCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
@ddt.ddt @ddt.ddt
class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Tests for delete_thread""" """Tests for delete_thread"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(DeleteThreadTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(DeleteThreadTest, self).setUp() super(DeleteThreadTest, self).setUp()
...@@ -2321,7 +2396,6 @@ class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -2321,7 +2396,6 @@ class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
self.thread_id = "test_thread" self.thread_id = "test_thread"
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
...@@ -2366,8 +2440,8 @@ class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -2366,8 +2440,8 @@ class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
delete_thread(self.request, self.thread_id) delete_thread(self.request, self.thread_id)
def test_discussions_disabled(self): def test_discussions_disabled(self):
self.register_thread() disabled_course = _discussion_disabled_course_for(self.user)
_remove_discussion_tab(self.course, self.user.id) self.register_thread(overrides={"course_id": unicode(disabled_course.id)})
with self.assertRaises(Http404): with self.assertRaises(Http404):
delete_thread(self.request, self.thread_id) delete_thread(self.request, self.thread_id)
...@@ -2436,8 +2510,14 @@ class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC ...@@ -2436,8 +2510,14 @@ class DeleteThreadTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestC
@ddt.ddt @ddt.ddt
class DeleteCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTestCase): class DeleteCommentTest(CommentsServiceMockMixin, UrlResetMixin, SharedModuleStoreTestCase):
"""Tests for delete_comment""" """Tests for delete_comment"""
@classmethod
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUpClass(cls):
super(DeleteCommentTest, cls).setUpClass()
cls.course = CourseFactory.create()
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True})
def setUp(self): def setUp(self):
super(DeleteCommentTest, self).setUp() super(DeleteCommentTest, self).setUp()
...@@ -2448,7 +2528,6 @@ class DeleteCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -2448,7 +2528,6 @@ class DeleteCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
self.register_get_user_response(self.user) self.register_get_user_response(self.user)
self.request = RequestFactory().get("/test_path") self.request = RequestFactory().get("/test_path")
self.request.user = self.user self.request.user = self.user
self.course = CourseFactory.create()
self.thread_id = "test_thread" self.thread_id = "test_thread"
self.comment_id = "test_comment" self.comment_id = "test_comment"
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id)
...@@ -2504,8 +2583,11 @@ class DeleteCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest ...@@ -2504,8 +2583,11 @@ class DeleteCommentTest(CommentsServiceMockMixin, UrlResetMixin, ModuleStoreTest
delete_comment(self.request, self.comment_id) delete_comment(self.request, self.comment_id)
def test_discussions_disabled(self): def test_discussions_disabled(self):
self.register_comment_and_thread() disabled_course = _discussion_disabled_course_for(self.user)
_remove_discussion_tab(self.course, self.user.id) self.register_comment_and_thread(
thread_overrides={"course_id": unicode(disabled_course.id)},
overrides={"course_id": unicode(disabled_course.id)}
)
with self.assertRaises(Http404): with self.assertRaises(Http404):
delete_comment(self.request, self.comment_id) delete_comment(self.request, self.comment_id)
......
...@@ -15,22 +15,26 @@ from student.tests.factories import UserFactory, AdminFactory, CourseEnrollmentF ...@@ -15,22 +15,26 @@ from student.tests.factories import UserFactory, AdminFactory, CourseEnrollmentF
from student.models import CourseEnrollment from student.models import CourseEnrollment
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from .factories import CourseTeamFactory from .factories import CourseTeamFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
@attr('shard_1') @attr('shard_1')
class TestDashboard(ModuleStoreTestCase): class TestDashboard(SharedModuleStoreTestCase):
"""Tests for the Teams dashboard.""" """Tests for the Teams dashboard."""
test_password = "test" test_password = "test"
@classmethod
def setUpClass(cls):
super(TestDashboard, cls).setUpClass()
cls.course = CourseFactory.create(
teams_configuration={"max_team_size": 10, "topics": [{"name": "foo", "id": 0, "description": "test topic"}]}
)
def setUp(self): def setUp(self):
""" """
Set up tests Set up tests
""" """
super(TestDashboard, self).setUp() super(TestDashboard, self).setUp()
self.course = CourseFactory.create(
teams_configuration={"max_team_size": 10, "topics": [{"name": "foo", "id": 0, "description": "test topic"}]}
)
# will be assigned to self.client by default # will be assigned to self.client by default
self.user = UserFactory.create(password=self.test_password) self.user = UserFactory.create(password=self.test_password)
self.teams_url = reverse('teams_dashboard', args=[self.course.id]) self.teams_url = reverse('teams_dashboard', args=[self.course.id])
...@@ -96,14 +100,14 @@ class TestDashboard(ModuleStoreTestCase): ...@@ -96,14 +100,14 @@ class TestDashboard(ModuleStoreTestCase):
self.assertEqual(404, response.status_code) self.assertEqual(404, response.status_code)
class TeamAPITestCase(APITestCase, ModuleStoreTestCase): class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
"""Base class for Team API test cases.""" """Base class for Team API test cases."""
test_password = 'password' test_password = 'password'
def setUp(self): @classmethod
super(TeamAPITestCase, self).setUp() def setUpClass(cls):
super(TeamAPITestCase, cls).setUpClass()
teams_configuration = { teams_configuration = {
'topics': 'topics':
[ [
...@@ -114,16 +118,17 @@ class TeamAPITestCase(APITestCase, ModuleStoreTestCase): ...@@ -114,16 +118,17 @@ class TeamAPITestCase(APITestCase, ModuleStoreTestCase):
} for i, name in enumerate([u'sólar power', 'Wind Power', 'Nuclear Power', 'Coal Power']) } for i, name in enumerate([u'sólar power', 'Wind Power', 'Nuclear Power', 'Coal Power'])
] ]
} }
self.topics_count = 4 cls.test_course_1 = CourseFactory.create(
self.test_course_1 = CourseFactory.create(
org='TestX', org='TestX',
course='TS101', course='TS101',
display_name='Test Course', display_name='Test Course',
teams_configuration=teams_configuration teams_configuration=teams_configuration
) )
self.test_course_2 = CourseFactory.create(org='MIT', course='6.002x', display_name='Circuits') cls.test_course_2 = CourseFactory.create(org='MIT', course='6.002x', display_name='Circuits')
def setUp(self):
super(TeamAPITestCase, self).setUp()
self.topics_count = 4
self.users = { self.users = {
'student_unenrolled': UserFactory.create(password=self.test_password), 'student_unenrolled': UserFactory.create(password=self.test_password),
'student_enrolled': UserFactory.create(password=self.test_password), 'student_enrolled': UserFactory.create(password=self.test_password),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment