Files
edx-platform/cms/djangoapps/maintenance/tests.py
Matjaz Gregoric 344c72b3e2 Use non-ascii PLATFORM_NAME in tests.
It should help catch unicode encoding problems earlier.

This also updates python-saml dependency to a version that includes a
patch for unicode strings.
2016-09-23 15:38:23 +02:00

266 lines
9.1 KiB
Python

"""
Tests for the maintenance app views.
"""
import ddt
import json
from django.conf import settings
from django.core.urlresolvers import reverse
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from contentstore.management.commands.utils import get_course_versions
from student.tests.factories import AdminFactory, UserFactory
from .views import COURSE_KEY_ERROR_MESSAGES, MAINTENANCE_VIEWS
# This list contains URLs of all maintenance app views.
MAINTENANCE_URLS = [reverse(view['url']) for view in MAINTENANCE_VIEWS.values()]
class TestMaintenanceIndex(ModuleStoreTestCase):
"""
Tests for maintenance index view.
"""
def setUp(self):
super(TestMaintenanceIndex, self).setUp()
self.user = AdminFactory()
login_success = self.client.login(username=self.user.username, password='test')
self.assertTrue(login_success)
self.view_url = reverse('maintenance:maintenance_index')
def test_maintenance_index(self):
"""
Test that maintenance index view lists all the maintenance app views.
"""
response = self.client.get(self.view_url)
self.assertContains(response, 'Maintenance', status_code=200)
# Check that all the expected links appear on the index page.
for url in MAINTENANCE_URLS:
self.assertContains(response, url, status_code=200)
@ddt.ddt
class MaintenanceViewTestCase(ModuleStoreTestCase):
"""
Base class for maintenance view tests.
"""
view_url = ''
def setUp(self):
super(MaintenanceViewTestCase, self).setUp()
self.user = AdminFactory()
login_success = self.client.login(username=self.user.username, password='test')
self.assertTrue(login_success)
def verify_error_message(self, data, error_message):
"""
Verify the response contains error message.
"""
response = self.client.post(self.view_url, data=data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertContains(response, error_message, status_code=200)
def tearDown(self):
"""
Reverse the setup.
"""
self.client.logout()
super(MaintenanceViewTestCase, self).tearDown()
@ddt.ddt
class MaintenanceViewAccessTests(MaintenanceViewTestCase):
"""
Tests for access control of maintenance views.
"""
@ddt.data(MAINTENANCE_URLS)
@ddt.unpack
def test_require_login(self, url):
"""
Test that maintenance app requires user login.
"""
# Log out then try to retrieve the page
self.client.logout()
response = self.client.get(url)
# Expect a redirect to the login page
redirect_url = '{login_url}?next={original_url}'.format(
login_url=reverse('login'),
original_url=url,
)
self.assertRedirects(response, redirect_url)
@ddt.data(MAINTENANCE_URLS)
@ddt.unpack
def test_global_staff_access(self, url):
"""
Test that all maintenance app views are accessible to global staff user.
"""
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
@ddt.data(MAINTENANCE_URLS)
@ddt.unpack
def test_non_global_staff_access(self, url):
"""
Test that all maintenance app views are not accessible to non-global-staff user.
"""
user = UserFactory(username='test', email='test@example.com', password='test')
login_success = self.client.login(username=user.username, password='test')
self.assertTrue(login_success)
response = self.client.get(url)
self.assertContains(
response,
u'Must be {platform_name} staff to perform this action.'.format(platform_name=settings.PLATFORM_NAME),
status_code=403
)
@ddt.ddt
class TestForcePublish(MaintenanceViewTestCase):
"""
Tests for the force publish view.
"""
def setUp(self):
super(TestForcePublish, self).setUp()
self.view_url = reverse('maintenance:force_publish_course')
def setup_test_course(self):
"""
Creates the course and add some changes to it.
Returns:
course: a course object
"""
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.split)
# Add some changes to course
chapter = ItemFactory.create(category='chapter', parent_location=course.location)
self.store.create_child(
self.user.id, # pylint: disable=no-member
chapter.location,
'html',
block_id='html_component'
)
# verify that course has changes.
self.assertTrue(self.store.has_changes(self.store.get_item(course.location)))
return course
@ddt.data(
('', COURSE_KEY_ERROR_MESSAGES['empty_course_key']),
('edx', COURSE_KEY_ERROR_MESSAGES['invalid_course_key']),
('course-v1:e+d+X', COURSE_KEY_ERROR_MESSAGES['course_key_not_found']),
)
@ddt.unpack
def test_invalid_course_key_messages(self, course_key, error_message):
"""
Test all error messages for invalid course keys.
"""
# validate that course key contains error message
self.verify_error_message(
data={'course-id': course_key},
error_message=error_message
)
def test_mongo_course(self):
"""
Test that we get a error message on old mongo courses.
"""
# validate non split error message
course = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo)
self.verify_error_message(
data={'course-id': unicode(course.id)},
error_message='Force publishing course is not supported with old mongo courses.'
)
def test_mongo_course_with_split_course_key(self):
"""
Test that we get an error message `course_key_not_found` for a provided split course key
if we already have an old mongo course.
"""
# validate non split error message
course = CourseFactory.create(org='e', number='d', run='X', default_store=ModuleStoreEnum.Type.mongo)
self.verify_error_message(
data={'course-id': unicode(course.id)},
error_message='Force publishing course is not supported with old mongo courses.'
)
# Now search for the course key in split version.
self.verify_error_message(
data={'course-id': 'course-v1:e+d+X'},
error_message=COURSE_KEY_ERROR_MESSAGES['course_key_not_found']
)
def test_already_published(self):
"""
Test that when a course is forcefully publish, we get a 'course is already published' message.
"""
course = self.setup_test_course()
# publish the course
source_store = modulestore()._get_modulestore_for_courselike(course.id) # pylint: disable=protected-access
source_store.force_publish_course(course.id, self.user.id, commit=True) # pylint: disable=no-member
# now course is published, we should get `already published course` error.
self.verify_error_message(
data={'course-id': unicode(course.id)},
error_message='Course is already in published state.'
)
def verify_versions_are_different(self, course):
"""
Verify draft and published versions point to different locations.
Arguments:
course (object): a course object.
"""
# get draft and publish branch versions
versions = get_course_versions(unicode(course.id))
# verify that draft and publish point to different versions
self.assertNotEqual(versions['draft-branch'], versions['published-branch'])
def get_force_publish_course_response(self, course):
"""
Get force publish the course response.
Arguments:
course (object): a course object.
Returns:
response : response from force publish post view.
"""
# Verify versions point to different locations initially
self.verify_versions_are_different(course)
# force publish course view
data = {
'course-id': unicode(course.id)
}
response = self.client.post(self.view_url, data=data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
response_data = json.loads(response.content)
return response_data
def test_force_publish_dry_run(self):
"""
Test that dry run does not publishes the course but shows possible outcome if force published is executed.
"""
course = self.setup_test_course()
response = self.get_force_publish_course_response(course)
self.assertIn('current_versions', response)
# verify that course still has changes as we just dry ran force publish course.
self.assertTrue(self.store.has_changes(self.store.get_item(course.location)))
# verify that both branch versions are still different
self.verify_versions_are_different(course)