Commit 61f7373a by Adam

Merge pull request #7552 from edx/hotfix/2015-04-01

Fixed static pages removed on import for split course.
parents 41d7d52b 464bcf33
"""Tests for display of certificates on the student dashboard. """
import unittest
import ddt
from django.conf import settings
from django.core.urlresolvers import reverse
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from student.tests.factories import UserFactory, CourseEnrollmentFactory
from certificates.tests.factories import GeneratedCertificateFactory # pylint: disable=import-error
@ddt.ddt
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
class CertificateDisplayTest(ModuleStoreTestCase):
"""Tests display of certificates on the student dashboard. """
USERNAME = "test_user"
PASSWORD = "password"
DOWNLOAD_URL = "http://www.example.com/certificate.pdf"
def setUp(self):
super(CertificateDisplayTest, self).setUp()
self.user = UserFactory.create(username=self.USERNAME, password=self.PASSWORD)
result = self.client.login(username=self.USERNAME, password=self.PASSWORD)
self.assertTrue(result, msg="Could not log in")
self.course = CourseFactory()
self.course.certificates_display_behavior = "early_with_info"
self.update_course(self.course, self.user.username)
@ddt.data('verified', 'professional')
def test_display_verified_certificate(self, enrollment_mode):
self._create_certificate(enrollment_mode)
self._check_can_download_certificate()
def _create_certificate(self, enrollment_mode):
"""Simulate that the user has a generated certificate. """
CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id, mode=enrollment_mode)
GeneratedCertificateFactory(
user=self.user,
course_id=self.course.id,
mode=enrollment_mode,
download_url=self.DOWNLOAD_URL,
status="downloadable",
grade=0.98,
)
def _check_can_download_certificate(self):
response = self.client.get(reverse('dashboard'))
self.assertContains(response, u'Download Your ID Verified')
self.assertContains(response, self.DOWNLOAD_URL)
......@@ -13,6 +13,7 @@ and then for each combination of modulestores, performing the sequence:
"""
from contextlib import contextmanager, nested
import itertools
import os
from path import path
import random
from shutil import rmtree
......@@ -314,14 +315,15 @@ class MixedModulestoreBuilder(StoreBuilderBase):
# Split stores all asset metadata in the structure collection.
return store.db_connection.structures
MIXED_MODULESTORE_BOTH_SETUP = MixedModulestoreBuilder([
('draft', MongoModulestoreBuilder()),
('split', VersioningModulestoreBuilder())
])
DRAFT_MODULESTORE_SETUP = MixedModulestoreBuilder([('draft', MongoModulestoreBuilder())])
SPLIT_MODULESTORE_SETUP = MixedModulestoreBuilder([('split', VersioningModulestoreBuilder())])
MIXED_MODULESTORE_SETUPS = (
MixedModulestoreBuilder([('draft', MongoModulestoreBuilder())]),
MixedModulestoreBuilder([('split', VersioningModulestoreBuilder())]),
DRAFT_MODULESTORE_SETUP,
SPLIT_MODULESTORE_SETUP,
)
MIXED_MS_SETUPS_SHORT = (
'mixed_mongo',
......@@ -347,6 +349,8 @@ COURSE_DATA_NAMES = (
'split_test_module_draft',
)
EXPORTED_COURSE_DIR_NAME = 'exported_source_course'
@ddt.ddt
@attr('mongo')
......@@ -397,14 +401,14 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase):
source_content,
source_course_key,
self.export_dir,
'exported_source_course',
EXPORTED_COURSE_DIR_NAME,
)
import_course_from_xml(
dest_store,
'test_user',
self.export_dir,
source_dirs=['exported_source_course'],
source_dirs=[EXPORTED_COURSE_DIR_NAME],
static_content_store=dest_content,
target_id=dest_course_key,
raise_on_failure=True,
......@@ -448,3 +452,58 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase):
dest_store,
dest_course_key,
)
def test_split_course_export_import(self):
# Construct the contentstore for storing the first import
with MongoContentstoreBuilder().build() as source_content:
# Construct the modulestore for storing the first import (using the previously created contentstore)
with SPLIT_MODULESTORE_SETUP.build(contentstore=source_content) as source_store:
# Construct the contentstore for storing the second import
with MongoContentstoreBuilder().build() as dest_content:
# Construct the modulestore for storing the second import (using the second contentstore)
with SPLIT_MODULESTORE_SETUP.build(contentstore=dest_content) as dest_store:
source_course_key = source_store.make_course_key('a', 'source', '2015_Fall')
dest_course_key = dest_store.make_course_key('a', 'dest', '2015_Fall')
import_course_from_xml(
source_store,
'test_user',
TEST_DATA_DIR,
source_dirs=['split_course_with_static_tabs'],
static_content_store=source_content,
target_id=source_course_key,
raise_on_failure=True,
create_if_not_present=True,
)
export_course_to_xml(
source_store,
source_content,
source_course_key,
self.export_dir,
EXPORTED_COURSE_DIR_NAME,
)
source_course = source_store.get_course(source_course_key, depth=None, lazy=False)
self.assertEqual(source_course.url_name, 'course')
export_dir_path = path(self.export_dir)
policy_dir = export_dir_path / 'exported_source_course' / 'policies' / source_course.url_name
policy_path = policy_dir / 'policy.json'
self.assertTrue(os.path.exists(policy_path))
import_course_from_xml(
dest_store,
'test_user',
self.export_dir,
source_dirs=[EXPORTED_COURSE_DIR_NAME],
static_content_store=dest_content,
target_id=dest_course_key,
raise_on_failure=True,
create_if_not_present=True,
)
dest_course = dest_store.get_course(dest_course_key, depth=None, lazy=False)
self.assertEqual(dest_course.url_name, 'course')
......@@ -264,8 +264,14 @@ class CourseExportManager(ExportManager):
'about', 'about', '.html'
)
course_policy_dir_name = courselike.location.run
if courselike.url_name != courselike.location.run and courselike.url_name == 'course':
# Use url_name for split mongo because course_run is not used when loading policies.
course_policy_dir_name = courselike.url_name
course_run_policy_dir = policies_dir.makeopendir(course_policy_dir_name)
# export the grading policy
course_run_policy_dir = policies_dir.makeopendir(courselike.location.run)
with course_run_policy_dir.open('grading_policy.json', 'w') as grading_policy:
grading_policy.write(dumps(courselike.grading_policy, cls=EdxJSONEncoder, sort_keys=True, indent=4))
......
<course url_name='course' org='split_test' course='split_test'>
</course>
<course advanced_modules="[&quot;drag-and-drop-v2&quot;]" display_name="Test Static Tab" due_date_display_format="" graceperiod="" no_grade="false" pdf_textbooks="[]" start="&quot;2015-01-01T00:00:00+00:00&quot;" use_latex_compiler="true">
</course>
{"GRADER": [{"short_label": "HW", "min_count": 12, "type": "Homework", "drop_count": 2, "weight": 0.15}, {"min_count": 12, "type": "Lab", "drop_count": 2, "weight": 0.15}, {"short_label": "Midterm", "min_count": 1, "type": "Midterm Exam", "drop_count": 0, "weight": 0.3}, {"short_label": "Final", "min_count": 1, "type": "Final Exam", "drop_count": 0, "weight": 0.4}], "GRADE_CUTOFFS": {"Pass": 0.5}}
{"course/3111": {"tabs": [{"type": "courseware", "name": "Courseware"}, {"type": "course_info", "name": "Course Info"}, {"type": "textbooks", "name": "Textbooks"}, {"type": "discussion", "name": "Discussion"}, {"type": "wiki", "name": "Wiki"}, {"type": "progress", "name": "Progress"}, {"name": "Test Page", "type": "static_tab", "url_slug": "test_page.html"}], "advanced_modules": ["split_test"], "display_name": "split export test", "user_partitions": [{"description": "Experiment 1", "version": 1, "id": 0, "groups": [{"version": 1, "id": 0, "name": "group 0"}, {"version": 1, "id": 1, "name": "group 1"}], "name": "Experiment 0,1"}, {"description": "Experiment 2", "version": 1, "id": 1, "groups": [{"version": 1, "id": 0, "name": "group A"}, {"version": 1, "id": 1, "name": "group B"}, {"version": 1, "id": 2, "name": "group C"}], "name": "Experiment A,B,C"}], "discussion_topics": {"General": {"id": "i4x-foo-1111-course-3111"}}}}
<p>Add the content you want students to see on this page.</p>
......@@ -44,6 +44,7 @@ class CommandsTestBase(ModuleStoreTestCase):
"""
__test__ = False
url_name = '2012_Fall'
def setUp(self):
super(CommandsTestBase, self).setUp()
......@@ -198,7 +199,7 @@ class CommandsTestBase(ModuleStoreTestCase):
assert_in = self.assertIn
assert_in('edX-simple-2012_Fall', names)
assert_in('edX-simple-2012_Fall/policies/2012_Fall/policy.json', names)
assert_in('edX-simple-2012_Fall/policies/{}/policy.json'.format(self.url_name), names)
assert_in('edX-simple-2012_Fall/html/toylab.html', names)
assert_in('edX-simple-2012_Fall/videosequence/A_simple_sequence.xml', names)
assert_in('edX-simple-2012_Fall/sequential/Lecture_2.xml', names)
......@@ -229,3 +230,4 @@ class CommandSplitMongoTestCase(CommandsTestBase):
"""
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
__test__ = True
url_name = 'course'
<%page args="cert_status, course, enrollment" />
<%! from django.utils.translation import ugettext as _ %>
<%!
from django.utils.translation import ugettext as _
from course_modes.models import CourseMode
%>
<%namespace name='static' file='../static_content.html'/>
<%
......@@ -61,7 +64,7 @@ else:
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document')}">
${_("Download Your {cert_name_short} (PDF)").format(cert_name_short=cert_name_short)}</a></li>
% elif cert_status['show_download_url'] and enrollment.mode == 'verified':
% elif cert_status['show_download_url'] and enrollment.mode in CourseMode.VERIFIED_MODES:
<li class="action">
<a class="btn" href="${cert_status['download_url']}"
title="${_('This link will open/download a PDF document of your verified {cert_name_long}.').format(cert_name_long=cert_name_long)}">
......
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