Commit a25a0d71 by Jean Manuel Nater

refactored tests in courseware to draw course info from mongo instead of xmlmodulestore

parent ee011597
...@@ -52,8 +52,8 @@ class Location(_LocationBase): ...@@ -52,8 +52,8 @@ class Location(_LocationBase):
Locations representations of URLs of the Locations representations of URLs of the
form {tag}://{org}/{course}/{category}/{name}[@{revision}] form {tag}://{org}/{course}/{category}/{name}[@{revision}]
However, they can also be represented a dictionaries (specifying each component), However, they can also be represented as dictionaries (specifying each component),
tuples or list (specified in order), or as strings of the url tuples or lists (specified in order), or as strings of the url
''' '''
__slots__ = () __slots__ = ()
......
...@@ -31,6 +31,10 @@ from xmodule.modulestore import Location ...@@ -31,6 +31,10 @@ from xmodule.modulestore import Location
from xmodule.modulestore.xml_importer import import_from_xml from xmodule.modulestore.xml_importer import import_from_xml
from xmodule.modulestore.xml import XMLModuleStore from xmodule.modulestore.xml import XMLModuleStore
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
log = logging.getLogger("mitx." + __name__) log = logging.getLogger("mitx." + __name__)
...@@ -117,8 +121,121 @@ TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR) ...@@ -117,8 +121,121 @@ TEST_DATA_XML_MODULESTORE = xml_store_config(TEST_DATA_DIR)
TEST_DATA_MONGO_MODULESTORE = mongo_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) TEST_DATA_DRAFT_MONGO_MODULESTORE = draft_mongo_store_config(TEST_DATA_DIR)
class MongoLoginHelpers(ModuleStoreTestCase):
def assertRedirectsNoFollow(self, response, expected_url):
"""
http://devblog.point2.com/2010/04/23/djangos-assertredirects-little-gotcha/
Don't check that the redirected-to page loads--there should be other tests for that.
Some of the code taken from django.test.testcases.py
"""
self.assertEqual(response.status_code, 302,
'Response status code was %d instead of 302'
% (response.status_code))
url = response['Location']
e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url)
if not (e_scheme or e_netloc):
expected_url = urlunsplit(('http', 'testserver',
e_path, e_query, e_fragment))
self.assertEqual(url, expected_url,
"Response redirected to '%s', expected '%s'" %
(url, expected_url))
def _login(self, email, password):
'''Login. View should always return 200. The success/fail is in the
returned json'''
resp = self.client.post(reverse('login'),
{'email': email, 'password': password})
self.assertEqual(resp.status_code, 200)
return resp
def login(self, email, password):
'''Login, check that it worked.'''
resp = self._login(email, password)
data = parse_json(resp)
self.assertTrue(data['success'])
return resp
def logout(self):
'''Logout, check that it worked.'''
resp = self.client.get(reverse('logout'), {})
# should redirect
self.assertEqual(resp.status_code, 302)
return resp
def _create_account(self, username, email, password):
'''Try to create an account. No error checking'''
resp = self.client.post('/create_account', {
'username': username,
'email': email,
'password': password,
'name': 'Fred Weasley',
'terms_of_service': 'true',
'honor_code': 'true',
})
return resp
def create_account(self, username, email, password):
'''Create the account and check that it worked'''
resp = self._create_account(username, email, password)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertEqual(data['success'], True)
# Check both that the user is created, and inactive
self.assertFalse(get_user(email).is_active)
return resp
def _activate_user(self, email):
'''Look up the activation key for the user, then hit the activate view.
No error checking'''
activation_key = get_registration(email).activation_key
# and now we try to activate
url = reverse('activate', kwargs={'key': activation_key})
resp = self.client.get(url)
return resp
def activate_user(self, email):
resp = self._activate_user(email)
self.assertEqual(resp.status_code, 200)
# Now make sure that the user is now actually activated
self.assertTrue(get_user(email).is_active)
def enroll(self, course):
"""Enroll the currently logged-in user, and check that it worked."""
result = self.try_enroll(course)
self.assertTrue(result)
def try_enroll(self, course):
"""Try to enroll. Return bool success instead of asserting it."""
resp = self.client.post('/change_enrollment', {
'enrollment_action': 'enroll',
'course_id': course.id,
})
print ('Enrollment in %s result status code: %s'
% (course.location.url(), str(resp.status_code)))
return resp.status_code == 200
def check_for_get_code(self, code, url):
"""
Check that we got the expected code when accessing url via GET.
Returns the response.
"""
resp = self.client.get(url)
self.assertEqual(resp.status_code, code,
"got code %d for url '%s'. Expected code %d"
% (resp.status_code, url, code))
return resp
class LoginEnrollmentTestCase(TestCase): class LoginEnrollmentTestCase(TestCase):
''' '''
Base TestCase providing support for user creation, Base TestCase providing support for user creation,
activation, login, and course enrollment activation, login, and course enrollment
...@@ -403,19 +520,35 @@ class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase): ...@@ -403,19 +520,35 @@ class TestCoursesLoadTestCase_MongoModulestore(PageLoaderTestCase):
self.assertGreater(len(course.textbooks), 0) self.assertGreater(len(course.textbooks), 0)
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) #@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE)
class TestNavigation(LoginEnrollmentTestCase): class TestNavigation(MongoLoginHelpers):
#class TestNavigation(LoginEnrollmentTestCase):
"""Check that navigation state is saved properly""" """Check that navigation state is saved properly"""
def setUp(self): def setUp(self):
xmodule.modulestore.django._MODULESTORES = {} xmodule.modulestore.django._MODULESTORES = {}
# Assume courses are there # Assume courses are there
self.full = modulestore().get_course("edX/full/6.002_Spring_2012") #self.full = modulestore().get_course("edX/full/6.002_Spring_2012")
self.toy = modulestore().get_course("edX/toy/2012_Fall") #self.toy = modulestore().get_course("edX/toy/2012_Fall")
self.course = CourseFactory.create()
self.full = CourseFactory.create(display_name = 'RoboboboboBOT')
# Create two accounts self.chapter0 = ItemFactory.create(parent_location=self.course.location,
display_name='Overview')
self.chapter9 = ItemFactory.create(parent_location=self.course.location,
display_name='factory_chapter')
self.section0 = ItemFactory.create(parent_location=self.chapter0.location,
display_name='Welcome')
self.section9 = ItemFactory.create(parent_location=self.chapter9.location,
display_name='factory_section')
#Create two accounts
self.student = 'view@test.com' self.student = 'view@test.com'
self.student2 = 'view2@test.com' self.student2 = 'view2@test.com'
self.password = 'foo' self.password = 'foo'
...@@ -427,42 +560,43 @@ class TestNavigation(LoginEnrollmentTestCase): ...@@ -427,42 +560,43 @@ class TestNavigation(LoginEnrollmentTestCase):
def test_accordion_state(self): def test_accordion_state(self):
"""Make sure that the accordion remembers where you were properly""" """Make sure that the accordion remembers where you were properly"""
self.login(self.student, self.password) self.login(self.student, self.password)
self.enroll(self.toy) self.enroll(self.course)
self.enroll(self.full) self.enroll(self.full)
# First request should redirect to ToyVideos # First request should redirect to ToyVideos
resp = self.client.get(reverse('courseware', resp = self.client.get(reverse('courseware',
kwargs={'course_id': self.toy.id})) kwargs={'course_id': self.course.id}))
# Don't use no-follow, because state should # Don't use no-follow, because state should
# only be saved once we actually hit the section # only be saved once we actually hit the section
self.assertRedirects(resp, reverse( self.assertRedirects(resp, reverse(
'courseware_section', kwargs={'course_id': self.toy.id, 'courseware_section', kwargs={'course_id': self.course.id,
'chapter': 'Overview', 'chapter': 'Overview',
'section': 'Toy_Videos'})) 'section': 'Welcome'}))
# Hitting the couseware tab again should # Hitting the couseware tab again should
# redirect to the first chapter: 'Overview' # redirect to the first chapter: 'Overview'
resp = self.client.get(reverse('courseware', resp = self.client.get(reverse('courseware',
kwargs={'course_id': self.toy.id})) kwargs={'course_id': self.course.id}))
self.assertRedirectsNoFollow(resp, reverse('courseware_chapter', self.assertRedirectsNoFollow(resp, reverse('courseware_chapter',
kwargs={'course_id': self.toy.id, kwargs={'course_id': self.course.id,
'chapter': 'Overview'})) 'chapter': 'Overview'}))
# Now we directly navigate to a section in a different chapter # Now we directly navigate to a section in a different chapter
self.check_for_get_code(200, reverse('courseware_section', self.check_for_get_code(200, reverse('courseware_section',
kwargs={'course_id': self.toy.id, kwargs={'course_id': self.course.id,
'chapter': 'secret:magic', 'chapter': 'factory_chapter',
'section': 'toyvideo'})) 'section': 'factory_section'}))
# And now hitting the courseware tab should redirect to 'secret:magic' # And now hitting the courseware tab should redirect to 'secret:magic'
resp = self.client.get(reverse('courseware', resp = self.client.get(reverse('courseware',
kwargs={'course_id': self.toy.id})) kwargs={'course_id': self.course.id}))
self.assertRedirectsNoFollow(resp, reverse('courseware_chapter', self.assertRedirectsNoFollow(resp, reverse('courseware_chapter',
kwargs={'course_id': self.toy.id, kwargs={'course_id': self.course.id,
'chapter': 'secret:magic'})) 'chapter': 'factory_chapter'}))
@override_settings(MODULESTORE=TEST_DATA_DRAFT_MONGO_MODULESTORE) @override_settings(MODULESTORE=TEST_DATA_DRAFT_MONGO_MODULESTORE)
...@@ -478,17 +612,31 @@ class TestDraftModuleStore(TestCase): ...@@ -478,17 +612,31 @@ class TestDraftModuleStore(TestCase):
# The bug was that 'course_id' argument was # The bug was that 'course_id' argument was
# not allowed to be passed in (i.e. was throwing exception) # not allowed to be passed in (i.e. was throwing exception)
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) class TestViewAuth(MongoLoginHelpers):
class TestViewAuth(LoginEnrollmentTestCase):
"""Check that view authentication works properly""" """Check that view authentication works properly"""
def setUp(self): def setUp(self):
xmodule.modulestore.django._MODULESTORES = {} xmodule.modulestore.django._MODULESTORES = {}
self.full = modulestore().get_course("edX/full/6.002_Spring_2012") self.full = CourseFactory.create(display_name='Robot_Sub_Course')
self.toy = modulestore().get_course("edX/toy/2012_Fall")
self.course = CourseFactory.create()
self.overview_chapter = ItemFactory.create(display_name='Overview')
self.progress_chapter = ItemFactory.create(parent_location=self.course.location,
display_name='progress')
self.info_chapter = ItemFactory.create(parent_location=self.course.location,
display_name='info')
self.welcome_section = ItemFactory.create(parent_location=self.overview_chapter.location,
display_name='Welcome')
self.somewhere_in_progress = ItemFactory.create(parent_location=self.progress_chapter.location,
display_name='1')
# Create two accounts # Create two accounts
self.student = 'view@test.com' self.student = 'view@test.com'
self.instructor = 'view2@test.com' self.instructor = 'view2@test.com'
...@@ -507,21 +655,22 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -507,21 +655,22 @@ class TestViewAuth(LoginEnrollmentTestCase):
self.login(self.student, self.password) self.login(self.student, self.password)
# shouldn't work before enroll # shouldn't work before enroll
response = self.client.get(reverse('courseware', response = self.client.get(reverse('courseware',
kwargs={'course_id': self.toy.id})) kwargs={'course_id': self.course.id}))
self.assertRedirectsNoFollow(response, self.assertRedirectsNoFollow(response,
reverse('about_course', reverse('about_course',
args=[self.toy.id])) args=[self.course.id]))
self.enroll(self.toy) self.enroll(self.course)
self.enroll(self.full) self.enroll(self.full)
# should work now -- redirect to first page # should work now -- redirect to first page
response = self.client.get(reverse('courseware', response = self.client.get(reverse('courseware',
kwargs={'course_id': self.toy.id})) kwargs={'course_id': self.course.id}))
self.assertRedirectsNoFollow(response, self.assertRedirectsNoFollow(response,
reverse('courseware_section', reverse('courseware_section',
kwargs={'course_id': self.toy.id, kwargs={'course_id': self.course.id,
'chapter': 'Overview', 'chapter': 'Overview',
'section': 'Toy_Videos'})) 'section': 'Welcome'}))
def instructor_urls(course): def instructor_urls(course):
"list of urls that only instructors/staff should be able to see" "list of urls that only instructors/staff should be able to see"
...@@ -536,15 +685,15 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -536,15 +685,15 @@ class TestViewAuth(LoginEnrollmentTestCase):
return urls return urls
# Randomly sample an instructor page # Randomly sample an instructor page
url = random.choice(instructor_urls(self.toy) + url = random.choice(instructor_urls(self.course) +
instructor_urls(self.full)) instructor_urls(self.full))
# Shouldn't be able to get to the instructor pages # Shouldn't be able to get to the instructor pages
print 'checking for 404 on {0}'.format(url) print 'checking for 404 on {0}'.format(url)
self.check_for_get_code(404, url) self.check_for_get_code(404, url)
# Make the instructor staff in the toy course # Make the instructor staff in the toy course
group_name = _course_staff_group_name(self.toy.location) group_name = _course_staff_group_name(self.course.location)
group = Group.objects.create(name=group_name) group = Group.objects.create(name=group_name)
group.user_set.add(get_user(self.instructor)) group.user_set.add(get_user(self.instructor))
...@@ -552,7 +701,7 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -552,7 +701,7 @@ class TestViewAuth(LoginEnrollmentTestCase):
self.login(self.instructor, self.password) self.login(self.instructor, self.password)
# Now should be able to get to the toy course, but not the full course # Now should be able to get to the toy course, but not the full course
url = random.choice(instructor_urls(self.toy)) url = random.choice(instructor_urls(self.course))
print 'checking for 200 on {0}'.format(url) print 'checking for 200 on {0}'.format(url)
self.check_for_get_code(200, url) self.check_for_get_code(200, url)
...@@ -566,8 +715,9 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -566,8 +715,9 @@ class TestViewAuth(LoginEnrollmentTestCase):
instructor.save() instructor.save()
# and now should be able to load both # and now should be able to load both
url = random.choice(instructor_urls(self.toy) + url = random.choice(instructor_urls(self.course) +
instructor_urls(self.full)) instructor_urls(self.full))
print 'checking for 200 on {0}'.format(url) print 'checking for 200 on {0}'.format(url)
self.check_for_get_code(200, url) self.check_for_get_code(200, url)
...@@ -580,11 +730,11 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -580,11 +730,11 @@ class TestViewAuth(LoginEnrollmentTestCase):
""" """
oldDSD = settings.MITX_FEATURES['DISABLE_START_DATES'] oldDSD = settings.MITX_FEATURES['DISABLE_START_DATES']
try: # try:
settings.MITX_FEATURES['DISABLE_START_DATES'] = False # settings.MITX_FEATURES['DISABLE_START_DATES'] = False
test() # test()
finally: # finally:
settings.MITX_FEATURES['DISABLE_START_DATES'] = oldDSD settings.MITX_FEATURES['DISABLE_START_DATES'] = oldDSD
def test_dark_launch(self): def test_dark_launch(self):
"""Make sure that before course start, students can't access course """Make sure that before course start, students can't access course
...@@ -604,10 +754,10 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -604,10 +754,10 @@ class TestViewAuth(LoginEnrollmentTestCase):
# Make courses start in the future # Make courses start in the future
tomorrow = time.time() + 24 * 3600 tomorrow = time.time() + 24 * 3600
self.toy.lms.start = time.gmtime(tomorrow) self.course.lms.start = time.gmtime(tomorrow)
self.full.lms.start = time.gmtime(tomorrow) self.full.lms.start = time.gmtime(tomorrow)
self.assertFalse(self.toy.has_started()) self.assertFalse(self.course.has_started())
self.assertFalse(self.full.has_started()) self.assertFalse(self.full.has_started())
self.assertFalse(settings.MITX_FEATURES['DISABLE_START_DATES']) self.assertFalse(settings.MITX_FEATURES['DISABLE_START_DATES'])
...@@ -691,28 +841,28 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -691,28 +841,28 @@ class TestViewAuth(LoginEnrollmentTestCase):
# First, try with an enrolled student # First, try with an enrolled student
print '=== Testing student access....' print '=== Testing student access....'
self.login(self.student, self.password) self.login(self.student, self.password)
self.enroll(self.toy) self.enroll(self.course)
self.enroll(self.full) self.enroll(self.full)
# shouldn't be able to get to anything except the light pages # shouldn't be able to get to anything except the light pages
check_non_staff(self.toy) check_non_staff(self.course)
check_non_staff(self.full) check_non_staff(self.full)
print '=== Testing course instructor access....' print '=== Testing course instructor access....'
# Make the instructor staff in the toy course # Make the instructor staff in the toy course
group_name = _course_staff_group_name(self.toy.location) group_name = _course_staff_group_name(self.course.location)
group = Group.objects.create(name=group_name) group = Group.objects.create(name=group_name)
group.user_set.add(get_user(self.instructor)) group.user_set.add(get_user(self.instructor))
self.logout() self.logout()
self.login(self.instructor, self.password) self.login(self.instructor, self.password)
# Enroll in the classes---can't see courseware otherwise. # Enroll in the classes---can't see courseware otherwise.
self.enroll(self.toy) self.enroll(self.course)
self.enroll(self.full) self.enroll(self.full)
# should now be able to get to everything for toy course # should now be able to get to everything for self.course
check_non_staff(self.full) check_non_staff(self.full)
check_staff(self.toy) check_staff(self.course)
print '=== Testing staff access....' print '=== Testing staff access....'
# now also make the instructor staff # now also make the instructor staff
...@@ -722,7 +872,7 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -722,7 +872,7 @@ class TestViewAuth(LoginEnrollmentTestCase):
# and now should be able to load both # and now should be able to load both
check_staff(self.toy) check_staff(self.toy)
check_staff(self.full) #check_staff(self.full)
def _do_test_enrollment_period(self): def _do_test_enrollment_period(self):
"""Actually do the test, relying on settings to be right.""" """Actually do the test, relying on settings to be right."""
...@@ -733,9 +883,9 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -733,9 +883,9 @@ class TestViewAuth(LoginEnrollmentTestCase):
yesterday = time.time() - 24 * 3600 yesterday = time.time() - 24 * 3600
print "changing" print "changing"
# toy course's enrollment period hasn't started # self.course's enrollment period hasn't started
self.toy.enrollment_start = time.gmtime(tomorrow) self.course.enrollment_start = time.gmtime(tomorrow)
self.toy.enrollment_end = time.gmtime(nextday) self.course.enrollment_end = time.gmtime(nextday)
# full course's has # full course's has
self.full.enrollment_start = time.gmtime(yesterday) self.full.enrollment_start = time.gmtime(yesterday)
...@@ -745,12 +895,12 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -745,12 +895,12 @@ class TestViewAuth(LoginEnrollmentTestCase):
# First, try with an enrolled student # First, try with an enrolled student
print '=== Testing student access....' print '=== Testing student access....'
self.login(self.student, self.password) self.login(self.student, self.password)
self.assertFalse(self.try_enroll(self.toy)) self.assertFalse(self.try_enroll(self.course))
self.assertTrue(self.try_enroll(self.full)) self.assertTrue(self.try_enroll(self.full))
print '=== Testing course instructor access....' print '=== Testing course instructor access....'
# Make the instructor staff in the toy course # Make the instructor staff in the toy course
group_name = _course_staff_group_name(self.toy.location) group_name = _course_staff_group_name(self.course.location)
group = Group.objects.create(name=group_name) group = Group.objects.create(name=group_name)
group.user_set.add(get_user(self.instructor)) group.user_set.add(get_user(self.instructor))
...@@ -758,7 +908,7 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -758,7 +908,7 @@ class TestViewAuth(LoginEnrollmentTestCase):
self.logout() self.logout()
self.login(self.instructor, self.password) self.login(self.instructor, self.password)
print "Instructor should be able to enroll in toy course" print "Instructor should be able to enroll in toy course"
self.assertTrue(self.try_enroll(self.toy)) self.assertTrue(self.try_enroll(self.course))
print '=== Testing staff access....' print '=== Testing staff access....'
# now make the instructor global staff, but not in the instructor group # now make the instructor global staff, but not in the instructor group
...@@ -768,8 +918,8 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -768,8 +918,8 @@ class TestViewAuth(LoginEnrollmentTestCase):
instructor.save() instructor.save()
# unenroll and try again # unenroll and try again
self.unenroll(self.toy) self.unenroll(self.course)
self.assertTrue(self.try_enroll(self.toy)) self.assertTrue(self.try_enroll(self.course))
def _do_test_beta_period(self): def _do_test_beta_period(self):
"""Actually test beta periods, relying on settings to be right.""" """Actually test beta periods, relying on settings to be right."""
...@@ -783,23 +933,23 @@ class TestViewAuth(LoginEnrollmentTestCase): ...@@ -783,23 +933,23 @@ class TestViewAuth(LoginEnrollmentTestCase):
# yesterday = time.time() - 24 * 3600 # yesterday = time.time() - 24 * 3600
# toy course's hasn't started # toy course's hasn't started
self.toy.lms.start = time.gmtime(tomorrow) self.course.lms.start = time.gmtime(tomorrow)
self.assertFalse(self.toy.has_started()) self.assertFalse(self.course.has_started())
# but should be accessible for beta testers # but should be accessible for beta testers
self.toy.lms.days_early_for_beta = 2 self.course.lms.days_early_for_beta = 2
# student user shouldn't see it # student user shouldn't see it
student_user = get_user(self.student) student_user = get_user(self.student)
self.assertFalse(has_access(student_user, self.toy, 'load')) self.assertFalse(has_access(student_user, self.course, 'load'))
# now add the student to the beta test group # now add the student to the beta test group
group_name = course_beta_test_group_name(self.toy.location) group_name = course_beta_test_group_name(self.course.location)
group = Group.objects.create(name=group_name) group = Group.objects.create(name=group_name)
group.user_set.add(student_user) group.user_set.add(student_user)
# now the student should see it # now the student should see it
self.assertTrue(has_access(student_user, self.toy, 'load')) self.assertTrue(has_access(student_user, self.course, 'load'))
@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE) @override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE)
......
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