Commit fde6d1ba by Jay Zoldak

Refactor tests for cms contentstore.

parent 33246152
import json import json
import shutil import shutil
from django.test import TestCase
from django.test.client import Client from django.test.client import Client
from override_settings import override_settings from override_settings import override_settings
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from path import path from path import path
from tempfile import mkdtemp
import json import json
from fs.osfs import OSFS from fs.osfs import OSFS
import copy import copy
from mock import Mock from mock import Mock
import xmodule.modulestore.django from student.models import Registration
from factories import * from django.contrib.auth.models import User
from utils import CmsTestCase from cms.djangoapps.contentstore.utils import get_modulestore
from utils import ModuleStoreTestCase, parse_json
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore import Location
from xmodule.modulestore.store_utilities import clone_course
from xmodule.modulestore.store_utilities import delete_course
from xmodule.modulestore.django import modulestore, _MODULESTORES
from xmodule.contentstore.django import contentstore
from xmodule.templates import update_templates
from xmodule.modulestore.xml_exporter import export_to_xml
from xmodule.modulestore.xml_importer import import_from_xml
from xmodule.capa_module import CapaDescriptor
from xmodule.course_module import CourseDescriptor
from xmodule.seq_module import SequenceDescriptor
TEST_DATA_MODULESTORE = copy.deepcopy(settings.MODULESTORE) TEST_DATA_MODULESTORE = copy.deepcopy(settings.MODULESTORE)
TEST_DATA_MODULESTORE['default']['OPTIONS']['fs_root'] = path('common/test/data') TEST_DATA_MODULESTORE['default']['OPTIONS']['fs_root'] = path('common/test/data')
TEST_DATA_MODULESTORE['direct']['OPTIONS']['fs_root'] = path('common/test/data') TEST_DATA_MODULESTORE['direct']['OPTIONS']['fs_root'] = path('common/test/data')
@override_settings(MODULESTORE=TEST_DATA_MODULESTORE) @override_settings(MODULESTORE=TEST_DATA_MODULESTORE)
class ContentStoreTest(CmsTestCase): class ContentStoreToyCourseTest(ModuleStoreTestCase):
"""
Tests that rely on the toy courses.
TODO: refactor using CourseFactory so they do not.
"""
def setUp(self): def setUp(self):
uname = 'testuser' uname = 'testuser'
email = 'test+courses@edx.org' email = 'test+courses@edx.org'
...@@ -40,109 +59,6 @@ class ContentStoreTest(CmsTestCase): ...@@ -40,109 +59,6 @@ class ContentStoreTest(CmsTestCase):
self.client = Client() self.client = Client()
self.client.login(username=uname, password=password) self.client.login(username=uname, password=password)
self.course_data = {
'template': 'i4x://edx/templates/course/Empty',
'org': 'MITx',
'number': '999',
'display_name': 'Robot Super Course',
}
def test_create_course(self):
"""Test new course creation - happy path"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertEqual(data['id'], 'i4x://MITx/999/course/Robot_Super_Course')
def test_create_course_duplicate_course(self):
"""Test new course creation - error path"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
resp = self.client.post(reverse('create_new_course'), self.course_data)
data = parse_json(resp)
self.assertEqual(resp.status_code, 200)
self.assertEqual(data['ErrMsg'], 'There is already a course defined with this name.')
def test_create_course_duplicate_number(self):
"""Test new course creation - error path"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
self.course_data['display_name'] = 'Robot Super Course Two'
resp = self.client.post(reverse('create_new_course'), self.course_data)
data = parse_json(resp)
self.assertEqual(resp.status_code, 200)
self.assertEqual(data['ErrMsg'],
'There is already a course defined with the same organization and course number.')
def test_create_course_with_bad_organization(self):
"""Test new course creation - error path for bad organization name"""
self.course_data['org'] = 'University of California, Berkeley'
resp = self.client.post(reverse('create_new_course'), self.course_data)
data = parse_json(resp)
self.assertEqual(resp.status_code, 200)
self.assertEqual(data['ErrMsg'],
"Unable to create course 'Robot Super Course'.\n\nInvalid characters in 'University of California, Berkeley'.")
def test_course_index_view_with_no_courses(self):
"""Test viewing the index page with no courses"""
# Create a course so there is something to view
resp = self.client.get(reverse('index'))
self.assertContains(resp,
'<h1>My Courses</h1>',
status_code=200,
html=True)
def test_course_factory(self):
course = CourseFactory.create()
self.assertIsInstance(course, CourseDescriptor)
def test_item_factory(self):
course = CourseFactory.create()
item = ItemFactory.create(parent_location=course.location)
self.assertIsInstance(item, SequenceDescriptor)
def test_course_index_view_with_course(self):
"""Test viewing the index page with an existing course"""
CourseFactory.create(display_name='Robot Super Educational Course')
resp = self.client.get(reverse('index'))
self.assertContains(resp,
'<span class="class-name">Robot Super Educational Course</span>',
status_code=200,
html=True)
def test_course_overview_view_with_course(self):
"""Test viewing the course overview page with an existing course"""
CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
data = {
'org': 'MITx',
'course': '999',
'name': Location.clean('Robot Super Course'),
}
resp = self.client.get(reverse('course_index', kwargs=data))
self.assertContains(resp,
'<a href="/MITx/999/course/Robot_Super_Course" class="class-name">Robot Super Course</a>',
status_code=200,
html=True)
def test_clone_item(self):
"""Test cloning an item. E.g. creating a new section"""
CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
section_data = {
'parent_location' : 'i4x://MITx/999/course/Robot_Super_Course',
'template' : 'i4x://edx/templates/chapter/Empty',
'display_name': 'Section One',
}
resp = self.client.post(reverse('clone_item'), section_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertRegexpMatches(data['id'],
'^i4x:\/\/MITx\/999\/chapter\/([0-9]|[a-f]){32}$')
def check_edit_unit(self, test_course_name): def check_edit_unit(self, test_course_name):
import_from_xml(modulestore(), 'common/test/data/', [test_course_name]) import_from_xml(modulestore(), 'common/test/data/', [test_course_name])
...@@ -183,9 +99,6 @@ class ContentStoreTest(CmsTestCase): ...@@ -183,9 +99,6 @@ class ContentStoreTest(CmsTestCase):
self.assertEqual(reverse_tabs, course_tabs) self.assertEqual(reverse_tabs, course_tabs)
def test_about_overrides(self): def test_about_overrides(self):
''' '''
This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html
...@@ -210,11 +123,18 @@ class ContentStoreTest(CmsTestCase): ...@@ -210,11 +123,18 @@ class ContentStoreTest(CmsTestCase):
course = ms.get_item(source_location) course = ms.get_item(source_location)
self.assertNotIn('hide_progress_tab', course.metadata) self.assertNotIn('hide_progress_tab', course.metadata)
def test_clone_course(self): def test_clone_course(self):
course_data = {
'template': 'i4x://edx/templates/course/Empty',
'org': 'MITx',
'number': '999',
'display_name': 'Robot Super Course',
}
import_from_xml(modulestore(), 'common/test/data/', ['full']) import_from_xml(modulestore(), 'common/test/data/', ['full'])
resp = self.client.post(reverse('create_new_course'), self.course_data) resp = self.client.post(reverse('create_new_course'), course_data)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
data = parse_json(resp) data = parse_json(resp)
self.assertEqual(data['id'], 'i4x://MITx/999/course/Robot_Super_Course') self.assertEqual(data['id'], 'i4x://MITx/999/course/Robot_Super_Course')
...@@ -302,7 +222,6 @@ class ContentStoreTest(CmsTestCase): ...@@ -302,7 +222,6 @@ class ContentStoreTest(CmsTestCase):
shutil.rmtree(root_dir) shutil.rmtree(root_dir)
def test_course_handouts_rewrites(self): def test_course_handouts_rewrites(self):
ms = modulestore('direct') ms = modulestore('direct')
cs = contentstore() cs = contentstore()
...@@ -323,6 +242,141 @@ class ContentStoreTest(CmsTestCase): ...@@ -323,6 +242,141 @@ class ContentStoreTest(CmsTestCase):
self.assertContains(resp, '/c4x/edX/full/asset/handouts_schematic_tutorial.pdf') self.assertContains(resp, '/c4x/edX/full/asset/handouts_schematic_tutorial.pdf')
class ContentStoreTest(ModuleStoreTestCase):
"""
Tests for the CMS ContentStore application.
"""
def setUp(self):
"""
These tests need a user in the DB so that the django Test Client
can log them in.
They inherit from the ModuleStoreTestCase class so that the mongodb collection
will be cleared out before each test case execution and deleted
afterwards.
"""
uname = 'testuser'
email = 'test+courses@edx.org'
password = 'foo'
# Create the use so we can log them in.
self.user = User.objects.create_user(uname, email, password)
# Note that we do not actually need to do anything
# for registration if we directly mark them active.
self.user.is_active = True
# Staff has access to view all courses
self.user.is_staff = True
self.user.save()
self.client = Client()
self.client.login(username=uname, password=password)
self.course_data = {
'template': 'i4x://edx/templates/course/Empty',
'org': 'MITx',
'number': '999',
'display_name': 'Robot Super Course',
}
def test_create_course(self):
"""Test new course creation - happy path"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertEqual(data['id'], 'i4x://MITx/999/course/Robot_Super_Course')
def test_create_course_duplicate_course(self):
"""Test new course creation - error path"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
resp = self.client.post(reverse('create_new_course'), self.course_data)
data = parse_json(resp)
self.assertEqual(resp.status_code, 200)
self.assertEqual(data['ErrMsg'], 'There is already a course defined with this name.')
def test_create_course_duplicate_number(self):
"""Test new course creation - error path"""
resp = self.client.post(reverse('create_new_course'), self.course_data)
self.course_data['display_name'] = 'Robot Super Course Two'
resp = self.client.post(reverse('create_new_course'), self.course_data)
data = parse_json(resp)
self.assertEqual(resp.status_code, 200)
self.assertEqual(data['ErrMsg'],
'There is already a course defined with the same organization and course number.')
def test_create_course_with_bad_organization(self):
"""Test new course creation - error path for bad organization name"""
self.course_data['org'] = 'University of California, Berkeley'
resp = self.client.post(reverse('create_new_course'), self.course_data)
data = parse_json(resp)
self.assertEqual(resp.status_code, 200)
self.assertEqual(data['ErrMsg'],
"Unable to create course 'Robot Super Course'.\n\nInvalid characters in 'University of California, Berkeley'.")
def test_course_index_view_with_no_courses(self):
"""Test viewing the index page with no courses"""
# Create a course so there is something to view
resp = self.client.get(reverse('index'))
self.assertContains(resp,
'<h1>My Courses</h1>',
status_code=200,
html=True)
def test_course_factory(self):
"""Test that the course factory works correctly."""
course = CourseFactory.create()
self.assertIsInstance(course, CourseDescriptor)
def test_item_factory(self):
"""Test that the item factory works correctly."""
course = CourseFactory.create()
item = ItemFactory.create(parent_location=course.location)
self.assertIsInstance(item, SequenceDescriptor)
def test_course_index_view_with_course(self):
"""Test viewing the index page with an existing course"""
CourseFactory.create(display_name='Robot Super Educational Course')
resp = self.client.get(reverse('index'))
self.assertContains(resp,
'<span class="class-name">Robot Super Educational Course</span>',
status_code=200,
html=True)
def test_course_overview_view_with_course(self):
"""Test viewing the course overview page with an existing course"""
CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
data = {
'org': 'MITx',
'course': '999',
'name': Location.clean('Robot Super Course'),
}
resp = self.client.get(reverse('course_index', kwargs=data))
self.assertContains(resp,
'<a href="/MITx/999/course/Robot_Super_Course" class="class-name">Robot Super Course</a>',
status_code=200,
html=True)
def test_clone_item(self):
"""Test cloning an item. E.g. creating a new section"""
CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
section_data = {
'parent_location' : 'i4x://MITx/999/course/Robot_Super_Course',
'template' : 'i4x://edx/templates/chapter/Empty',
'display_name': 'Section One',
}
resp = self.client.post(reverse('clone_item'), section_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertRegexpMatches(data['id'],
'^i4x:\/\/MITx\/999\/chapter\/([0-9]|[a-f]){32}$')
def test_capa_module(self): def test_capa_module(self):
"""Test that a problem treats markdown specially.""" """Test that a problem treats markdown specially."""
CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course') CourseFactory.create(org='MITx', course='999', display_name='Robot Super Course')
......
from django.test.testcases import TestCase
import datetime import datetime
import time import time
from django.contrib.auth.models import User
import xmodule
from django.test.client import Client
from django.core.urlresolvers import reverse
from xmodule.modulestore import Location
from cms.djangoapps.models.settings.course_details import CourseDetails,\
CourseSettingsEncoder
import json import json
from util import converters
import calendar import calendar
import copy
from util import converters
from util.converters import jsdate_to_time from util.converters import jsdate_to_time
from django.test.testcases import TestCase
from django.contrib.auth.models import User
from django.test.client import Client
from django.core.urlresolvers import reverse
from django.utils.timezone import UTC from django.utils.timezone import UTC
import xmodule
from xmodule.modulestore import Location
from cms.djangoapps.models.settings.course_details import (CourseDetails,
CourseSettingsEncoder)
from cms.djangoapps.models.settings.course_grading import CourseGradingModel from cms.djangoapps.models.settings.course_grading import CourseGradingModel
from cms.djangoapps.contentstore.utils import get_modulestore from cms.djangoapps.contentstore.utils import get_modulestore
import copy
from utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
# YYYY-MM-DDThh:mm:ss.s+/-HH:MM # YYYY-MM-DDThh:mm:ss.s+/-HH:MM
class ConvertersTestCase(TestCase): class ConvertersTestCase(TestCase):
...@@ -36,8 +42,15 @@ class ConvertersTestCase(TestCase): ...@@ -36,8 +42,15 @@ class ConvertersTestCase(TestCase):
self.compare_dates(converters.jsdate_to_time("2013-01-01T00:00:00"), converters.jsdate_to_time("2012-12-31T23:59:59"), datetime.timedelta(seconds=1)) self.compare_dates(converters.jsdate_to_time("2013-01-01T00:00:00"), converters.jsdate_to_time("2012-12-31T23:59:59"), datetime.timedelta(seconds=1))
class CourseTestCase(TestCase): class CourseTestCase(ModuleStoreTestCase):
def setUp(self): def setUp(self):
"""
These tests need a user in the DB so that the django Test Client
can log them in.
They inherit from the ModuleStoreTestCase class so that the mongodb collection
will be cleared out before each test case execution and deleted
afterwards.
"""
uname = 'testuser' uname = 'testuser'
email = 'test+courses@edx.org' email = 'test+courses@edx.org'
password = 'foo' password = 'foo'
...@@ -52,36 +65,15 @@ class CourseTestCase(TestCase): ...@@ -52,36 +65,15 @@ class CourseTestCase(TestCase):
self.user.is_staff = True self.user.is_staff = True
self.user.save() self.user.save()
# 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()"
xmodule.modulestore.django._MODULESTORES = {}
xmodule.modulestore.django.modulestore().collection.drop()
xmodule.templates.update_templates()
self.client = Client() self.client = Client()
self.client.login(username=uname, password=password) self.client.login(username=uname, password=password)
self.course_data = { t='i4x://edx/templates/course/Empty'
'template': 'i4x://edx/templates/course/Empty', o='MITx'
'org': 'MITx', n='999'
'number': '999', dn='Robot Super Course'
'display_name': 'Robot Super Course', self.course_location = Location('i4x', o, n, 'course', 'Robot_Super_Course')
} CourseFactory.create(template=t, org=o, number=n, display_name=dn)
self.course_location = Location('i4x', 'MITx', '999', 'course', 'Robot_Super_Course')
self.create_course()
def tearDown(self):
xmodule.modulestore.django._MODULESTORES = {}
xmodule.modulestore.django.modulestore().collection.drop()
def create_course(self):
"""Create new course"""
self.client.post(reverse('create_new_course'), self.course_data)
class CourseDetailsTestCase(CourseTestCase): class CourseDetailsTestCase(CourseTestCase):
def test_virgin_fetch(self): def test_virgin_fetch(self):
...@@ -146,7 +138,6 @@ class CourseDetailsViewTest(CourseTestCase): ...@@ -146,7 +138,6 @@ class CourseDetailsViewTest(CourseTestCase):
else: else:
return None return None
def test_update_and_fetch(self): def test_update_and_fetch(self):
details = CourseDetails.fetch(self.course_location) details = CourseDetails.fetch(self.course_location)
...@@ -271,5 +262,3 @@ class CourseGradingTest(CourseTestCase): ...@@ -271,5 +262,3 @@ class CourseGradingTest(CourseTestCase):
test_grader.graders[1]['drop_count'] = test_grader.graders[1].get('drop_count') + 1 test_grader.graders[1]['drop_count'] = test_grader.graders[1].get('drop_count') + 1
altered_grader = CourseGradingModel.update_grader_from_json(test_grader.course_location, test_grader.graders[1]) altered_grader = CourseGradingModel.update_grader_from_json(test_grader.course_location, test_grader.graders[1])
self.assertDictEqual(test_grader.graders[1], altered_grader, "drop_count[1] + 2") self.assertDictEqual(test_grader.graders[1], altered_grader, "drop_count[1] + 2")
...@@ -11,8 +11,6 @@ import json ...@@ -11,8 +11,6 @@ import json
from fs.osfs import OSFS from fs.osfs import OSFS
import copy import copy
from student.models import Registration
from django.contrib.auth.models import User
from cms.djangoapps.contentstore.utils import get_modulestore from cms.djangoapps.contentstore.utils import get_modulestore
from xmodule.modulestore import Location from xmodule.modulestore import Location
...@@ -29,22 +27,7 @@ from xmodule.course_module import CourseDescriptor ...@@ -29,22 +27,7 @@ from xmodule.course_module import CourseDescriptor
from xmodule.seq_module import SequenceDescriptor from xmodule.seq_module import SequenceDescriptor
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from .utils import CmsTestCase from utils import ModuleStoreTestCase, parse_json, user, registration
def parse_json(response):
"""Parse response, which is assumed to be json"""
return json.loads(response.content)
def user(email):
"""look up a user by email"""
return User.objects.get(email=email)
def registration(email):
"""look up registration object by email"""
return Registration.objects.get(user__email=email)
class ContentStoreTestCase(TestCase): class ContentStoreTestCase(TestCase):
def _login(self, email, pw): def _login(self, email, pw):
......
from django.test import TestCase from django.test import TestCase
from xmodule.modulestore.django import modulestore, _MODULESTORES import json
from student.models import Registration
from django.contrib.auth.models import User
import xmodule.modulestore.django
from xmodule.templates import update_templates from xmodule.templates import update_templates
# Subclass TestCase and use to initialize the contentstore # Subclass TestCase and use to initialize the contentstore
class CmsTestCase(TestCase): class ModuleStoreTestCase(TestCase):
""" Subclass for any test case that uses the mongodb """ Subclass for any test case that uses the mongodb
module store. This clears it out before running the TestCase module store. This clears it out before running the TestCase
and reinitilizes it with the templates afterwards. """ and reinitilizes it with the templates afterwards. """
def _pre_setup(self): def _pre_setup(self):
super(CmsTestCase, self)._pre_setup() super(ModuleStoreTestCase, self)._pre_setup()
# Flush and initialize the module store # Flush and initialize the module store
# It needs the templates because it creates new records # It needs the templates because it creates new records
# by cloning from the template. # by cloning from the template.
...@@ -17,16 +22,27 @@ class CmsTestCase(TestCase): ...@@ -17,16 +22,27 @@ class CmsTestCase(TestCase):
# (though it shouldn't), do this manually # (though it shouldn't), do this manually
# from the bash shell to drop it: # from the bash shell to drop it:
# $ mongo test_xmodule --eval "db.dropDatabase()" # $ mongo test_xmodule --eval "db.dropDatabase()"
_MODULESTORES = {} xmodule.modulestore.django._MODULESTORES = {}
modulestore().collection.drop() xmodule.modulestore.django.modulestore().collection.drop()
update_templates() update_templates()
def _post_teardown(self): def _post_teardown(self):
# Make sure you flush out the test modulestore after the end # Make sure you flush out the test modulestore after the end
# of the last test because otherwise on the next run # of the last test so the collection will be deleted.
# cms/djangoapps/contentstore/__init__.py # Otherwise there will be lingering collections leftover
# update_templates() will try to update the templates # from executing the tests.
# via upsert and it sometimes seems to be messing things up. xmodule.modulestore.django._MODULESTORES = {}
_MODULESTORES = {} xmodule.modulestore.django.modulestore().collection.drop()
modulestore().collection.drop() super(ModuleStoreTestCase, self)._post_teardown()
super(CmsTestCase, self)._post_teardown()
\ No newline at end of file def parse_json(response):
"""Parse response, which is assumed to be json"""
return json.loads(response.content)
def user(email):
"""look up a user by email"""
return User.objects.get(email=email)
def registration(email):
"""look up registration object by email"""
return Registration.objects.get(user__email=email)
...@@ -1240,6 +1240,11 @@ def edge(request): ...@@ -1240,6 +1240,11 @@ def edge(request):
@login_required @login_required
@expect_json @expect_json
def create_new_course(request): def create_new_course(request):
# This logic is repeated in xmodule/modulestore/tests/factories.py
# so if you change anything here, you need to also change it there.
# TODO: write a test that creates two courses, one with the factory and
# the other with this method, then compare them to make sure they are
# equivalent.
template = Location(request.POST['template']) template = Location(request.POST['template'])
org = request.POST.get('org') org = request.POST.get('org')
number = request.POST.get('number') number = request.POST.get('number')
...@@ -1289,6 +1294,9 @@ def initialize_course_tabs(course): ...@@ -1289,6 +1294,9 @@ def initialize_course_tabs(course):
# at least a list populated with the minimal times # at least a list populated with the minimal times
# @TODO: I don't like the fact that the presentation tier is away of these data related constraints, let's find a better # @TODO: I don't like the fact that the presentation tier is away of these data related constraints, let's find a better
# place for this. Also rather than using a simple list of dictionaries a nice class model would be helpful here # place for this. Also rather than using a simple list of dictionaries a nice class model would be helpful here
# This logic is repeated in xmodule/modulestore/tests/factories.py
# so if you change anything here, you need to also change it there.
course.tabs = [{"type": "courseware"}, course.tabs = [{"type": "courseware"},
{"type": "course_info", "name": "Course Info"}, {"type": "course_info", "name": "Course Info"},
{"type": "discussion", "name": "Discussion"}, {"type": "discussion", "name": "Discussion"},
......
from factory import Factory from factory import Factory
# from datetime import datetime
from time import gmtime from time import gmtime
from uuid import uuid4 from uuid import uuid4
from xmodule.modulestore import Location from xmodule.modulestore import Location
...@@ -22,7 +21,8 @@ class XModuleCourseFactory(Factory): ...@@ -22,7 +21,8 @@ class XModuleCourseFactory(Factory):
@classmethod @classmethod
def _create(cls, target_class, *args, **kwargs): def _create(cls, target_class, *args, **kwargs):
# This logic was taken from the create_new_course method in
# cms/djangoapps/contentstore/views.py
template = Location('i4x', 'edx', 'templates', 'course', 'Empty') template = Location('i4x', 'edx', 'templates', 'course', 'Empty')
org = kwargs.get('org') org = kwargs.get('org')
number = kwargs.get('number') number = kwargs.get('number')
...@@ -41,6 +41,7 @@ class XModuleCourseFactory(Factory): ...@@ -41,6 +41,7 @@ class XModuleCourseFactory(Factory):
new_course.metadata['data_dir'] = uuid4().hex new_course.metadata['data_dir'] = uuid4().hex
new_course.metadata['start'] = stringify_time(gmtime()) new_course.metadata['start'] = stringify_time(gmtime())
new_course.tabs = [{"type": "courseware"}, new_course.tabs = [{"type": "courseware"},
{"type": "course_info", "name": "Course Info"}, {"type": "course_info", "name": "Course Info"},
{"type": "discussion", "name": "Discussion"}, {"type": "discussion", "name": "Discussion"},
......
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