diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_migrate_transcripts.py b/cms/djangoapps/contentstore/management/commands/tests/test_migrate_transcripts.py
index 58e81d86e7..113fc1fa81 100644
--- a/cms/djangoapps/contentstore/management/commands/tests/test_migrate_transcripts.py
+++ b/cms/djangoapps/contentstore/management/commands/tests/test_migrate_transcripts.py
@@ -18,6 +18,7 @@ from openedx.core.djangoapps.video_config.models import (
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
+from xmodule.video_module import VideoBlock
from xmodule.video_module.transcripts_utils import save_to_store
from edxval import api as api
from testfixtures import LogCapture
@@ -105,9 +106,9 @@ class TestMigrateTranscripts(ModuleStoreTestCase):
youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8"
show_captions="false"
download_track="false"
- start_time="00:00:01"
+ start_time="1.0"
download_video="false"
- end_time="00:01:00">
+ end_time="60.0">
@@ -122,9 +123,9 @@ class TestMigrateTranscripts(ModuleStoreTestCase):
youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8"
show_captions="false"
download_track="false"
- start_time="00:00:01"
+ start_time="1.0"
download_video="false"
- end_time="00:01:00">
+ end_time="60.0">
@@ -133,11 +134,11 @@ class TestMigrateTranscripts(ModuleStoreTestCase):
'''
self.video_descriptor = ItemFactory.create(
parent_location=self.course.location, category='video',
- data={'data': video_sample_xml}
+ **VideoBlock.parse_video_xml(video_sample_xml)
)
self.video_descriptor_2 = ItemFactory.create(
parent_location=self.course_2.location, category='video',
- data={'data': video_sample_xml_2}
+ **VideoBlock.parse_video_xml(video_sample_xml_2)
)
save_to_store(SRT_FILEDATA, 'subs_grmtran1.srt', 'text/srt', self.video_descriptor.location)
diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index 5b48c6fd9e..e0df1a65ac 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -54,6 +54,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, chec
from xmodule.modulestore.xml_exporter import export_course_to_xml
from xmodule.modulestore.xml_importer import import_course_from_xml, perform_xlint
from xmodule.seq_module import SequenceDescriptor
+from xmodule.video_module import VideoBlock
TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE)
TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'] = 'test_xcontent_%s' % uuid4().hex
@@ -1815,15 +1816,15 @@ class MetadataSaveTestCase(ContentStoreTestCase):
"""
self.video_descriptor = ItemFactory.create(
parent_location=course.location, category='video',
- data={'data': video_sample_xml}
+ **VideoBlock.parse_video_xml(video_sample_xml)
)
def test_metadata_not_persistence(self):
@@ -1840,7 +1841,6 @@ class MetadataSaveTestCase(ContentStoreTestCase):
'youtube_id_1_5',
'start_time',
'end_time',
- 'source',
'html5_sources',
'track'
}
diff --git a/cms/djangoapps/contentstore/views/tests/test_course_index.py b/cms/djangoapps/contentstore/views/tests/test_course_index.py
index 42879eed70..d1f0154538 100644
--- a/cms/djangoapps/contentstore/views/tests/test_course_index.py
+++ b/cms/djangoapps/contentstore/views/tests/test_course_index.py
@@ -718,7 +718,7 @@ class TestCourseReIndex(CourseTestCase):
course_id=unicode(self.course.id))
self.assertEqual(response['total'], 1)
- @mock.patch('xmodule.video_module.VideoDescriptor.index_dictionary')
+ @mock.patch('xmodule.video_module.VideoBlock.index_dictionary')
def test_reindex_video_error_json_responses(self, mock_index_dictionary):
"""
Test json response with mocked error data for video
@@ -828,7 +828,7 @@ class TestCourseReIndex(CourseTestCase):
course_id=unicode(self.course.id))
self.assertEqual(response['total'], 1)
- @mock.patch('xmodule.video_module.VideoDescriptor.index_dictionary')
+ @mock.patch('xmodule.video_module.VideoBlock.index_dictionary')
def test_indexing_video_error_responses(self, mock_index_dictionary):
"""
Test do_course_reindex response with mocked error data for video
diff --git a/cms/djangoapps/contentstore/views/tests/test_transcripts.py b/cms/djangoapps/contentstore/views/tests/test_transcripts.py
index 05e03aebd6..8dc31a1284 100644
--- a/cms/djangoapps/contentstore/views/tests/test_transcripts.py
+++ b/cms/djangoapps/contentstore/views/tests/test_transcripts.py
@@ -21,6 +21,7 @@ from xmodule.contentstore.content import StaticContent
from xmodule.contentstore.django import contentstore
from xmodule.exceptions import NotFoundError
from xmodule.modulestore.django import modulestore
+from xmodule.video_module import VideoBlock
from xmodule.video_module.transcripts_utils import (
GetTranscriptsFromYouTubeException,
Transcript,
@@ -94,7 +95,9 @@ class BaseTranscripts(CourseTestCase):
self.item = modulestore().get_item(self.video_usage_key)
# hI10vDNYz4M - valid Youtube ID with transcripts.
# JMD_ifUUfsU, AKqURZnYqpk, DYpADpL7jAY - valid Youtube IDs without transcripts.
- self.item.data = ''
+ self.set_fields_from_xml(
+ self.item, ''
+ )
modulestore().update_item(self.item, self.user.id)
self.item = modulestore().get_item(self.video_usage_key)
@@ -129,7 +132,7 @@ class BaseTranscripts(CourseTestCase):
response = self.client.ajax_post('/xblock/', data)
usage_key = self._get_usage_key(response)
item = modulestore().get_item(usage_key)
- item.data = ''
+ self.set_fields_from_xml(self.item, '')
modulestore().update_item(item, self.user.id)
return usage_key
@@ -139,6 +142,11 @@ class BaseTranscripts(CourseTestCase):
self.assertEqual(response.status_code, expected_status_code)
self.assertEqual(response_content['status'], expected_message)
+ def set_fields_from_xml(self, item, xml):
+ fields_data = VideoBlock.parse_video_xml(xml)
+ for key, value in fields_data.items():
+ setattr(item, key, value)
+
@ddt.ddt
class TestUploadTranscripts(BaseTranscripts):
@@ -836,7 +844,7 @@ class TestCheckTranscripts(BaseTranscripts):
"""
def test_success_download_nonyoutube(self):
subs_id = str(uuid4())
- self.item.data = textwrap.dedent(u"""
+ self.set_fields_from_xml(self.item, u"""
'''
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -376,7 +376,7 @@ class VideoDescriptorImportTestCase(TestCase):
id_generator = Mock()
id_generator.target_course_id = course_id
- output = VideoDescriptor.from_xml(xml_data, module_system, id_generator)
+ output = VideoBlock.from_xml(xml_data, module_system, id_generator)
self.assert_attributes_equal(output, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -407,7 +407,7 @@ class VideoDescriptorImportTestCase(TestCase):
'''
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': '',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -419,7 +419,7 @@ class VideoDescriptorImportTestCase(TestCase):
'track': '',
'handout': None,
'download_track': False,
- 'download_video': True,
+ 'download_video': False,
'html5_sources': ['http://www.example.com/source.mp4'],
'data': ''
})
@@ -438,7 +438,7 @@ class VideoDescriptorImportTestCase(TestCase):
'''
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': '',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -449,7 +449,7 @@ class VideoDescriptorImportTestCase(TestCase):
'end_time': datetime.timedelta(seconds=0.0),
'track': 'http://www.example.com/track',
'download_track': True,
- 'download_video': True,
+ 'download_video': False,
'html5_sources': ['http://www.example.com/source.mp4'],
'data': '',
'transcripts': {},
@@ -461,7 +461,7 @@ class VideoDescriptorImportTestCase(TestCase):
"""
module_system = DummySystem(load_error_modules=True)
xml_data = ''
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': '',
'youtube_id_1_0': '3_yD_cEKoCk',
@@ -500,7 +500,7 @@ class VideoDescriptorImportTestCase(TestCase):
youtube_id_1_0=""OEoXaMPEzf10""
/>
'''
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': 'OEoXaMPEzf65',
'youtube_id_1_0': 'OEoXaMPEzf10',
@@ -524,7 +524,7 @@ class VideoDescriptorImportTestCase(TestCase):
youtube="1.0:"p2Q6BrNhdh8",1.25:"1EeWXzPdhSA"">
'''
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': '',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -543,7 +543,7 @@ class VideoDescriptorImportTestCase(TestCase):
def test_old_video_format(self):
"""
- Test backwards compatibility with VideoModule's XML format.
+ Test backwards compatibility with VideoBlock's XML format.
"""
module_system = DummySystem(load_error_modules=True)
xml_data = """
@@ -557,7 +557,7 @@ class VideoDescriptorImportTestCase(TestCase):
"""
- output = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ output = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(output, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -574,7 +574,7 @@ class VideoDescriptorImportTestCase(TestCase):
def test_old_video_data(self):
"""
- Ensure that Video is able to read VideoModule's model data.
+ Ensure that Video is able to read VideoBlock's model data.
"""
module_system = DummySystem(load_error_modules=True)
xml_data = """
@@ -587,7 +587,7 @@ class VideoDescriptorImportTestCase(TestCase):
"""
- video = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ video = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(video, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -604,7 +604,7 @@ class VideoDescriptorImportTestCase(TestCase):
def test_import_with_float_times(self):
"""
- Ensure that Video is able to read VideoModule's model data.
+ Ensure that Video is able to read VideoBlock's model data.
"""
module_system = DummySystem(load_error_modules=True)
xml_data = """
@@ -617,7 +617,7 @@ class VideoDescriptorImportTestCase(TestCase):
"""
- video = VideoDescriptor.from_xml(xml_data, module_system, Mock())
+ video = VideoBlock.from_xml(xml_data, module_system, Mock())
self.assert_attributes_equal(video, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -665,7 +665,7 @@ class VideoDescriptorImportTestCase(TestCase):
)
id_generator = Mock()
id_generator.target_course_id = 'test_course_id'
- video = VideoDescriptor.from_xml(xml_data, module_system, id_generator)
+ video = VideoBlock.from_xml(xml_data, module_system, id_generator)
self.assert_attributes_equal(video, {'edx_video_id': edx_video_id})
mock_val_api.import_from_xml.assert_called_once_with(
@@ -690,12 +690,12 @@ class VideoDescriptorImportTestCase(TestCase):
"""
with self.assertRaises(mock_val_api.ValCannotCreateError):
- VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
+ VideoBlock.from_xml(xml_data, module_system, id_generator=Mock())
-class VideoExportTestCase(VideoDescriptorTestBase):
+class VideoExportTestCase(VideoBlockTestBase):
"""
- Make sure that VideoDescriptor can export itself to XML correctly.
+ Make sure that VideoBlock can export itself to XML correctly.
"""
def setUp(self):
@@ -773,7 +773,7 @@ class VideoExportTestCase(VideoDescriptorTestBase):
xml = self.descriptor.definition_to_xml(self.file_system)
parser = etree.XMLParser(remove_blank_text=True)
- xml_string = ''
+ xml_string = ''
expected = etree.XML(xml_string, parser=parser)
self.assertXmlEqual(expected, xml)
@@ -813,7 +813,7 @@ class VideoExportTestCase(VideoDescriptorTestBase):
"""
xml = self.descriptor.definition_to_xml(self.file_system)
# Check that download_video field is also set to default (False) in xml for backward compatibility
- expected = '\n'
+ expected = '\n'
self.assertEquals(expected, etree.tostring(xml, pretty_print=True))
@patch('xmodule.video_module.video_module.edxval_api', None)
@@ -823,7 +823,7 @@ class VideoExportTestCase(VideoDescriptorTestBase):
"""
self.descriptor.transcripts = None
xml = self.descriptor.definition_to_xml(self.file_system)
- expected = '\n'
+ expected = '\n'
self.assertEquals(expected, etree.tostring(xml, pretty_print=True))
@patch('xmodule.video_module.video_module.edxval_api', None)
@@ -850,9 +850,9 @@ class VideoExportTestCase(VideoDescriptorTestBase):
@patch.object(settings, 'FEATURES', create=True, new={
'FALLBACK_TO_ENGLISH_TRANSCRIPTS': False,
})
-class VideoDescriptorStudentViewDataTestCase(unittest.TestCase):
+class VideoBlockStudentViewDataTestCase(unittest.TestCase):
"""
- Make sure that VideoDescriptor returns the expected student_view_data.
+ Make sure that VideoBlock returns the expected student_view_data.
"""
VIDEO_URL_1 = 'http://www.example.com/source_low.mp4'
@@ -865,41 +865,6 @@ class VideoDescriptorStudentViewDataTestCase(unittest.TestCase):
{'only_on_web': True},
{'only_on_web': True},
),
- # Ensure that the deprecated `source` attribute is included in the `all_sources` list.
- (
- {
- 'only_on_web': False,
- 'youtube_id_1_0': None,
- 'source': VIDEO_URL_1,
- },
- {
- 'only_on_web': False,
- 'duration': None,
- 'transcripts': {},
- 'encoded_videos': {
- 'fallback': {'url': VIDEO_URL_1, 'file_size': 0},
- },
- 'all_sources': [VIDEO_URL_1],
- },
- ),
- # Ensure that `html5_sources` take precendence over deprecated `source` url
- (
- {
- 'only_on_web': False,
- 'youtube_id_1_0': None,
- 'source': VIDEO_URL_1,
- 'html5_sources': [VIDEO_URL_2, VIDEO_URL_3],
- },
- {
- 'only_on_web': False,
- 'duration': None,
- 'transcripts': {},
- 'encoded_videos': {
- 'fallback': {'url': VIDEO_URL_2, 'file_size': 0},
- },
- 'all_sources': [VIDEO_URL_2, VIDEO_URL_3, VIDEO_URL_1],
- },
- ),
# Ensure that YouTube URLs are included in `encoded_videos`, but not `all_sources`.
(
{
@@ -1002,9 +967,9 @@ class VideoDescriptorStudentViewDataTestCase(unittest.TestCase):
# The default value in {lms,cms}/envs/common.py and xmodule/tests/test_video.py should be consistent.
'FALLBACK_TO_ENGLISH_TRANSCRIPTS': True,
})
-class VideoDescriptorIndexingTestCase(unittest.TestCase):
+class VideoBlockIndexingTestCase(unittest.TestCase):
"""
- Make sure that VideoDescriptor can format data for indexing as expected.
+ Make sure that VideoBlock can format data for indexing as expected.
"""
def test_video_with_no_subs_index_dictionary(self):
diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
index 4e2e004b1b..dd18e3ab88 100644
--- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
+++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
@@ -34,7 +34,6 @@ from xmodule.course_module import CourseDescriptor
from xmodule.html_module import HtmlDescriptor
from xmodule.poll_module import PollDescriptor
from xmodule.word_cloud_module import WordCloudDescriptor
-#from xmodule.video_module import VideoDescriptor
from xmodule.seq_module import SequenceDescriptor
from xmodule.conditional_module import ConditionalDescriptor
from xmodule.randomize_module import RandomizeDescriptor
@@ -51,8 +50,6 @@ LEAF_XMODULES = {
HtmlDescriptor: [{}],
PollDescriptor: [{'display_name': 'Poll Display Name'}],
WordCloudDescriptor: [{}],
- # This is being excluded because it has dependencies on django
- #VideoDescriptor,
}
diff --git a/common/lib/xmodule/xmodule/video_module/bumper_utils.py b/common/lib/xmodule/xmodule/video_module/bumper_utils.py
index c440b6ace3..4ade5b3116 100644
--- a/common/lib/xmodule/xmodule/video_module/bumper_utils.py
+++ b/common/lib/xmodule/xmodule/video_module/bumper_utils.py
@@ -127,7 +127,7 @@ def bumper_metadata(video, sources):
unused_track_url, bumper_transcript_language, bumper_languages = video.get_transcripts_for_student(transcripts)
metadata = OrderedDict({
- 'saveStateUrl': video.system.ajax_url + '/save_user_state',
+ 'saveStateUrl': video.ajax_url + '/save_user_state',
'showCaptions': json.dumps(video.show_captions),
'sources': sources,
'streams': '',
diff --git a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py
index 0ae8e3e98c..32c52c2330 100644
--- a/common/lib/xmodule/xmodule/video_module/transcripts_utils.py
+++ b/common/lib/xmodule/xmodule/video_module/transcripts_utils.py
@@ -730,7 +730,7 @@ class Transcript(object):
class VideoTranscriptsMixin(object):
"""Mixin class for transcript functionality.
- This is necessary for both VideoModule and VideoDescriptor.
+ This is necessary for VideoBlock.
"""
def available_translations(self, transcripts, verify_assets=None, is_bumper=False):
@@ -740,7 +740,7 @@ class VideoTranscriptsMixin(object):
Arguments:
verify_assets (boolean): If True, checks to ensure that the transcripts
really exist in the contentstore. If False, we just look at the
- VideoDescriptor fields and do not query the contentstore. One reason
+ VideoBlock fields and do not query the contentstore. One reason
we might do this is to avoid slamming contentstore() with queries
when trying to make a listing of videos and their languages.
diff --git a/common/lib/xmodule/xmodule/video_module/video_handlers.py b/common/lib/xmodule/xmodule/video_module/video_handlers.py
index 6c4106f609..195af52ca7 100644
--- a/common/lib/xmodule/xmodule/video_module/video_handlers.py
+++ b/common/lib/xmodule/xmodule/video_module/video_handlers.py
@@ -203,7 +203,7 @@ class VideoStudentViewHandlers(object):
if transcript_name:
# Get the asset path for course
asset_path = None
- course = self.descriptor.runtime.modulestore.get_course(self.course_id)
+ course = self.runtime.modulestore.get_course(self.course_id)
if course.static_asset_path:
asset_path = course.static_asset_path
else:
diff --git a/common/lib/xmodule/xmodule/video_module/video_module.py b/common/lib/xmodule/xmodule/video_module/video_module.py
index d83bab3869..8385410bab 100644
--- a/common/lib/xmodule/xmodule/video_module/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module/video_module.py
@@ -24,7 +24,6 @@ import six
from django.conf import settings
from lxml import etree
from opaque_keys.edx.locator import AssetLocator
-from pkg_resources import resource_string
from web_fragments.fragment import Fragment
from xblock.completable import XBlockCompletionMode
from xblock.core import XBlock
@@ -36,14 +35,19 @@ from openedx.core.djangoapps.video_pipeline.config.waffle import DEPRECATE_YOUTU
from openedx.core.lib.cache_utils import request_cached
from openedx.core.lib.license import LicenseMixin
from xmodule.contentstore.content import StaticContent
-from xmodule.editing_module import TabsEditingDescriptor
+from xmodule.editing_module import EditingMixin, TabsEditingMixin
from xmodule.exceptions import NotFoundError
from xmodule.modulestore.inheritance import InheritanceKeyValueStore, own_metadata
-from xmodule.raw_module import EmptyDataRawDescriptor
+from xmodule.raw_module import EmptyDataRawMixin
from xmodule.validation import StudioValidation, StudioValidationMessage
+from xmodule.util.xmodule_django import add_webpack_to_fragment
from xmodule.video_module import manage_video_subtitles_save
-from xmodule.x_module import PUBLIC_VIEW, STUDENT_VIEW, XModule, module_attr
-from xmodule.xml_module import deserialize_field, is_pointer_tag, name_to_pathname
+from xmodule.x_module import (
+ PUBLIC_VIEW, STUDENT_VIEW,
+ HTMLSnippet, ResourceTemplates, shim_xmodule_js,
+ XModuleMixin, XModuleToXBlockMixin, XModuleDescriptorToXBlockMixin,
+)
+from xmodule.xml_module import XmlMixin, deserialize_field, is_pointer_tag, name_to_pathname
from .bumper_utils import bumperize
from .transcripts_utils import (
@@ -61,25 +65,25 @@ from .video_xfields import VideoFields
# The following import/except block for edxval is temporary measure until
# edxval is a proper XBlock Runtime Service.
#
-# Here's the deal: the VideoModule should be able to take advantage of edx-val
+# Here's the deal: the VideoBlock should be able to take advantage of edx-val
# (https://github.com/edx/edx-val) to figure out what URL to give for video
# resources that have an edx_video_id specified. edx-val is a Django app, and
# including it causes tests to fail because we run common/lib tests standalone
# without Django dependencies. The alternatives seem to be:
#
-# 1. Move VideoModule out of edx-platform.
+# 1. Move VideoBlock out of edx-platform.
# 2. Accept the Django dependency in common/lib.
# 3. Try to import, catch the exception on failure, and check for the existence
# of edxval_api before invoking it in the code.
# 4. Make edxval an XBlock Runtime Service
#
-# (1) is a longer term goal. VideoModule should be made into an XBlock and
+# (1) is a longer term goal. VideoBlock should be made into an XBlock and
# extracted from edx-platform entirely. But that's expensive to do because of
# the various dependencies (like templates). Need to sort this out.
# (2) is explicitly discouraged.
# (3) is what we're doing today. The code is still functional when called within
# the context of the LMS, but does not cause failure on import when running
-# standalone tests. Most VideoModule tests tend to be in the LMS anyway,
+# standalone tests. Most VideoBlock tests tend to be in the LMS anyway,
# probably for historical reasons, so we're not making things notably worse.
# (4) is one of the next items on the backlog for edxval, and should get rid
# of this particular import silliness. It's just that I haven't made one before,
@@ -104,8 +108,12 @@ EXPORT_IMPORT_COURSE_DIR = u'course'
EXPORT_IMPORT_STATIC_DIR = u'static'
-@XBlock.wants('settings', 'completion')
-class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers, XModule, LicenseMixin):
+@XBlock.wants('settings', 'completion', 'i18n', 'request_cache')
+class VideoBlock(
+ VideoFields, VideoTranscriptsMixin, VideoStudioViewHandlers, VideoStudentViewHandlers,
+ TabsEditingMixin, EmptyDataRawMixin, XmlMixin, EditingMixin,
+ XModuleDescriptorToXBlockMixin, XModuleToXBlockMixin, HTMLSnippet, ResourceTemplates, XModuleMixin,
+ LicenseMixin):
"""
XML source example:
input[type="file"]',
diff --git a/common/test/acceptance/tests/video/test_video_license.py b/common/test/acceptance/tests/video/test_video_license.py
index da03f76609..343625c8fd 100644
--- a/common/test/acceptance/tests/video/test_video_license.py
+++ b/common/test/acceptance/tests/video/test_video_license.py
@@ -57,7 +57,7 @@ class VideoLicenseTest(StudioCourseTest):
self.lms_courseware.visit()
video = self.lms_courseware.q(css=".vert .xblock .video")
self.assertTrue(video.is_present())
- video_license = self.lms_courseware.q(css=".vert .xblock.xmodule_VideoModule .xblock-license")
+ video_license = self.lms_courseware.q(css=".vert .xblock.xmodule_VideoBlock .xblock-license")
self.assertFalse(video_license.is_present())
def test_arr_license(self):
@@ -83,7 +83,7 @@ class VideoLicenseTest(StudioCourseTest):
self.lms_courseware.visit()
video = self.lms_courseware.q(css=".vert .xblock .video")
self.assertTrue(video.is_present())
- video_license_css = ".vert .xblock.xmodule_VideoModule .xblock-license"
+ video_license_css = ".vert .xblock.xmodule_VideoBlock .xblock-license"
self.lms_courseware.wait_for_element_presence(
video_license_css, "Video module license block is present"
)
@@ -113,7 +113,7 @@ class VideoLicenseTest(StudioCourseTest):
self.lms_courseware.visit()
video = self.lms_courseware.q(css=".vert .xblock .video")
self.assertTrue(video.is_present())
- video_license_css = ".vert .xblock.xmodule_VideoModule .xblock-license"
+ video_license_css = ".vert .xblock.xmodule_VideoBlock .xblock-license"
self.lms_courseware.wait_for_element_presence(
video_license_css, "Video module license block is present"
)
diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py
index a80247ef0f..6d8d278240 100644
--- a/common/test/acceptance/tests/video/test_video_module.py
+++ b/common/test/acceptance/tests/video/test_video_module.py
@@ -1013,7 +1013,7 @@ class YouTubeQualityTest(VideoBaseTest):
@attr('a11y')
-class LMSVideoModuleA11yTest(VideoBaseTest):
+class LMSVideoBlockA11yTest(VideoBaseTest):
"""
LMS Video Accessibility Test Class
"""
@@ -1030,7 +1030,7 @@ class LMSVideoModuleA11yTest(VideoBaseTest):
browser = 'firefox'
with patch.dict(os.environ, {'SELENIUM_BROWSER': browser}):
- super(LMSVideoModuleA11yTest, self).setUp()
+ super(LMSVideoBlockA11yTest, self).setUp()
def test_video_player_a11y(self):
# load transcripts so we can test skipping to
diff --git a/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py b/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py
index 063b774c42..f0f14acf4f 100644
--- a/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py
+++ b/lms/djangoapps/courseware/management/commands/tests/test_dump_course.py
@@ -133,11 +133,11 @@ class CommandsTestBase(SharedModuleStoreTestCase):
video_id = text_type(test_course_key.make_usage_key('video', 'Welcome'))
self.assertEqual(dump[video_id]['category'], 'video')
- course_metadata = dump[video_id]['metadata']
- course_metadata.pop('edx_video_id', None)
+ video_metadata = dump[video_id]['metadata']
+ video_metadata.pop('edx_video_id', None)
self.assertItemsEqual(
- list(course_metadata.keys()),
- ['download_video', 'youtube_id_0_75', 'youtube_id_1_0', 'youtube_id_1_25', 'youtube_id_1_5']
+ list(video_metadata.keys()),
+ ['youtube_id_0_75', 'youtube_id_1_0', 'youtube_id_1_25', 'youtube_id_1_5']
)
self.assertIn('youtube_id_1_0', dump[video_id]['metadata'])
diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py
index c065c4cb08..65f08d38d4 100644
--- a/lms/djangoapps/courseware/tests/test_module_render.py
+++ b/lms/djangoapps/courseware/tests/test_module_render.py
@@ -76,6 +76,7 @@ from xmodule.modulestore.tests.django_utils import (
)
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, ToyCourseFactory, check_mongo_calls
from xmodule.modulestore.tests.test_asides import AsideTestType
+from xmodule.video_module import VideoBlock
from xmodule.x_module import STUDENT_VIEW, CombinedSystem, XModule, XModuleDescriptor
TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
@@ -989,14 +990,12 @@ class TestTOC(ModuleStoreTestCase):
# - 1 for the course
# - 1 for its children
# - 1 for its grandchildren
- # Split makes 6 queries to load the course to depth 2:
- # - load the structure
- # - load 5 definitions
- # Split makes 5 queries to render the toc:
- # - it loads the active version at the start of the bulk operation
- # - it loads 4 definitions, because it instantiates 4 VideoModules
- # each of which access a Scope.content field in __init__
- @ddt.data((ModuleStoreEnum.Type.mongo, 3, 0, 0), (ModuleStoreEnum.Type.split, 6, 0, 5))
+ # Split makes 2 queries to load the course to depth 2:
+ # - 1 for the structure
+ # - 1 for 5 definitions
+ # Split makes 1 query to render the toc:
+ # - 1 for the active version at the start of the bulk operation
+ @ddt.data((ModuleStoreEnum.Type.mongo, 3, 0, 0), (ModuleStoreEnum.Type.split, 2, 0, 1))
@ddt.unpack
def test_toc_toy_from_chapter(self, default_ms, setup_finds, setup_sends, toc_finds):
with self.store.default_store(default_ms):
@@ -1031,14 +1030,12 @@ class TestTOC(ModuleStoreTestCase):
# - 1 for the course
# - 1 for its children
# - 1 for its grandchildren
- # Split makes 6 queries to load the course to depth 2:
- # - load the structure
- # - load 5 definitions
- # Split makes 5 queries to render the toc:
- # - it loads the active version at the start of the bulk operation
- # - it loads 4 definitions, because it instantiates 4 VideoModules
- # each of which access a Scope.content field in __init__
- @ddt.data((ModuleStoreEnum.Type.mongo, 3, 0, 0), (ModuleStoreEnum.Type.split, 6, 0, 5))
+ # Split makes 2 queries to load the course to depth 2:
+ # - 1 for the structure
+ # - 1 for 5 definitions
+ # Split makes 1 query to render the toc:
+ # - 1 for the active version at the start of the bulk operation
+ @ddt.data((ModuleStoreEnum.Type.mongo, 3, 0, 0), (ModuleStoreEnum.Type.split, 2, 0, 1))
@ddt.unpack
def test_toc_toy_from_section(self, default_ms, setup_finds, setup_sends, toc_finds):
with self.store.default_store(default_ms):
@@ -1937,6 +1934,7 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
PER_COURSE_ANONYMIZED_DESCRIPTORS = (LTIDescriptor, )
PER_STUDENT_ANONYMIZED_XBLOCKS = [
ProblemBlock,
+ VideoBlock,
]
# The "set" here is to work around the bug that load_classes returns duplicates for multiply-declared classes.
diff --git a/lms/djangoapps/courseware/tests/test_video_handlers.py b/lms/djangoapps/courseware/tests/test_video_handlers.py
index e6d6f26120..ef953fd2ae 100644
--- a/lms/djangoapps/courseware/tests/test_video_handlers.py
+++ b/lms/djangoapps/courseware/tests/test_video_handlers.py
@@ -25,6 +25,7 @@ from xmodule.contentstore.django import contentstore
from xmodule.exceptions import NotFoundError
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
+from xmodule.video_module import VideoBlock
from xmodule.video_module.transcripts_utils import Transcript, edxval_api, subs_filename
from xmodule.x_module import STUDENT_VIEW
@@ -127,7 +128,26 @@ def attach_bumper_transcript(item, filename, lang="en"):
item.video_bumper["transcripts"][lang] = filename
-class TestVideo(BaseTestXmodule):
+class BaseTestVideoXBlock(BaseTestXmodule):
+ """Base class for VideoXBlock tests."""
+
+ CATEGORY = 'video'
+
+ def initialize_block(self, data=None, **kwargs):
+ """ Initialize an XBlock to run tests on. """
+ if data:
+ # VideoBlock data field is no longer used but to avoid needing to re-do
+ # a lot of tests code, parse and set the values as fields.
+ fields_data = VideoBlock.parse_video_xml(data)
+ kwargs.update(fields_data)
+ super(BaseTestVideoXBlock, self).initialize_module(**kwargs)
+
+ def setUp(self):
+ super(BaseTestVideoXBlock, self).setUp()
+ self.initialize_block(data=self.DATA, metadata=self.METADATA)
+
+
+class TestVideo(BaseTestVideoXBlock):
"""Integration tests: web client + mongo."""
CATEGORY = "video"
DATA = SOURCE_XML
@@ -225,7 +245,7 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo):
def setUp(self):
super(TestTranscriptAvailableTranslationsDispatch, self).setUp()
self.item_descriptor.render(STUDENT_VIEW)
- self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+ self.item = self.item_descriptor
self.subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
def test_available_translation_en(self):
@@ -383,7 +403,7 @@ class TestTranscriptAvailableTranslationsBumperDispatch(TestVideo):
def setUp(self):
super(TestTranscriptAvailableTranslationsBumperDispatch, self).setUp()
self.item_descriptor.render(STUDENT_VIEW)
- self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+ self.item = self.item_descriptor
self.dispatch = "available_translations/?is_bumper=1"
self.item.video_bumper = {"transcripts": {"en": ""}}
@@ -449,7 +469,7 @@ class TestTranscriptDownloadDispatch(TestVideo):
def setUp(self):
super(TestTranscriptDownloadDispatch, self).setUp()
self.item_descriptor.render(STUDENT_VIEW)
- self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+ self.item = self.item_descriptor
def test_download_transcript_not_exist(self):
request = Request.blank('/download')
@@ -499,7 +519,7 @@ class TestTranscriptDownloadDispatch(TestVideo):
self.assertEqual(response.headers['Content-Disposition'], 'attachment; filename="en_塞.srt"')
@patch('xmodule.video_module.transcripts_utils.edxval_api.get_video_transcript_data')
- @patch('xmodule.video_module.VideoModule.get_transcript', Mock(side_effect=NotFoundError))
+ @patch('xmodule.video_module.VideoBlock.get_transcript', Mock(side_effect=NotFoundError))
def test_download_fallback_transcript(self, mock_get_video_transcript_data):
"""
Verify val transcript is returned as a fallback if it is not found in the content store.
@@ -560,7 +580,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
def setUp(self):
super(TestTranscriptTranslationGetDispatch, self).setUp()
self.item_descriptor.render(STUDENT_VIEW)
- self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+ self.item = self.item_descriptor
self.item.video_bumper = {"transcripts": {"en": ""}}
@ddt.data(
@@ -747,7 +767,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
response.headerlist
)
- @patch('xmodule.video_module.VideoModule.course_id', return_value='not_a_course_locator')
+ @patch('xmodule.video_module.VideoBlock.course_id', return_value='not_a_course_locator')
def test_translation_static_non_course(self, __):
"""
Test that get_static_transcript short-circuits in the case of a non-CourseLocator.
@@ -769,8 +789,8 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
store.update_item(self.course, self.user.id)
@patch('xmodule.video_module.transcripts_utils.edxval_api.get_video_transcript_data')
- @patch('xmodule.video_module.VideoModule.translation', Mock(side_effect=NotFoundError))
- @patch('xmodule.video_module.VideoModule.get_static_transcript', Mock(return_value=Response(status=404)))
+ @patch('xmodule.video_module.VideoBlock.translation', Mock(side_effect=NotFoundError))
+ @patch('xmodule.video_module.VideoBlock.get_static_transcript', Mock(return_value=Response(status=404)))
def test_translation_fallback_transcript(self, mock_get_video_transcript_data):
"""
Verify that the val transcript is returned as a fallback,
@@ -801,8 +821,8 @@ class TestTranscriptTranslationGetDispatch(TestVideo):
for attribute, value in six.iteritems(expected_headers):
self.assertEqual(response.headers[attribute], value)
- @patch('xmodule.video_module.VideoModule.translation', Mock(side_effect=NotFoundError))
- @patch('xmodule.video_module.VideoModule.get_static_transcript', Mock(return_value=Response(status=404)))
+ @patch('xmodule.video_module.VideoBlock.translation', Mock(side_effect=NotFoundError))
+ @patch('xmodule.video_module.VideoBlock.get_static_transcript', Mock(return_value=Response(status=404)))
def test_translation_fallback_transcript_feature_disabled(self):
"""
Verify that val transcript is not returned when its feature is disabled.
@@ -1132,7 +1152,7 @@ class TestGetTranscript(TestVideo):
def setUp(self):
super(TestGetTranscript, self).setUp()
self.item_descriptor.render(STUDENT_VIEW)
- self.item = self.item_descriptor.xmodule_runtime.xmodule_instance
+ self.item = self.item_descriptor
def test_good_transcript(self):
"""
diff --git a/lms/djangoapps/courseware/tests/test_video_mongo.py b/lms/djangoapps/courseware/tests/test_video_mongo.py
index 0f30f8f913..70fb649e9e 100644
--- a/lms/djangoapps/courseware/tests/test_video_mongo.py
+++ b/lms/djangoapps/courseware/tests/test_video_mongo.py
@@ -46,14 +46,13 @@ from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.inheritance import own_metadata
from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_MODULESTORE, TEST_DATA_SPLIT_MODULESTORE
from xmodule.tests.test_import import DummySystem
-from xmodule.tests.test_video import VideoDescriptorTestBase, instantiate_descriptor
-from xmodule.video_module import VideoDescriptor, bumper_utils, video_utils
+from xmodule.tests.test_video import VideoBlockTestBase
+from xmodule.video_module import VideoBlock, bumper_utils, video_utils
from xmodule.video_module.transcripts_utils import Transcript, save_to_store, subs_filename
from xmodule.video_module.video_module import EXPORT_IMPORT_COURSE_DIR, EXPORT_IMPORT_STATIC_DIR
from xmodule.x_module import PUBLIC_VIEW, STUDENT_VIEW
-from .helpers import BaseTestXmodule
-from .test_video_handlers import TestVideo
+from .test_video_handlers import BaseTestVideoXBlock, TestVideo
from .test_video_xml import SOURCE_XML
MODULESTORES = {
@@ -96,7 +95,7 @@ class TestVideoYouTube(TestVideo):
'metadata': json.dumps(OrderedDict({
'autoAdvance': False,
'saveStateEnabled': True,
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg',
'sources': sources,
@@ -146,7 +145,7 @@ class TestVideoNonYouTube(TestVideo):
display_name="A Name"
sub="a_sub_file.srt.sjson"
download_video="true"
- start_time="01:00:03" end_time="01:00:10"
+ start_time="3603.0" end_time="3610.0"
>
@@ -178,7 +177,7 @@ class TestVideoNonYouTube(TestVideo):
'metadata': json.dumps(OrderedDict({
'autoAdvance': False,
'saveStateEnabled': True,
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '1.00:3_yD_cEKoCk',
'sources': sources,
@@ -222,7 +221,7 @@ class TestVideoNonYouTube(TestVideo):
@ddt.ddt
-class TestGetHtmlMethod(BaseTestXmodule):
+class TestGetHtmlMethod(BaseTestVideoXBlock):
'''
Make sure that `get_html` works correctly.
'''
@@ -280,7 +279,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
@@ -360,7 +359,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
transcripts=data['transcripts'],
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
track_url = self.get_handler_url('transcript', 'download')
context = self.item_descriptor.render(STUDENT_VIEW).content
@@ -370,7 +369,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
})
expected_context.update({
'transcript_download_format': (
@@ -394,7 +393,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
display_name="A Name"
sub="a_sub_file.srt.sjson" source="{source}"
download_video="{download_video}"
- start_time="01:00:03" end_time="01:00:10"
+ start_time="3603.0" end_time="3610.0"
>
{sources}
@@ -409,7 +408,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
""",
'result': {
- 'download_video_link': u'example_source.mp4',
+ 'download_video_link': u'example.mp4',
'sources': [u'example.mp4', u'example.webm'],
},
},
@@ -474,7 +473,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
source=data['source'],
sources=data['sources']
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
context = self.item_descriptor.render(STUDENT_VIEW).content
expected_context = dict(initial_context)
@@ -482,7 +481,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'sources': data['result'].get('sources', []),
})
expected_context.update({
@@ -498,14 +497,14 @@ class TestGetHtmlMethod(BaseTestXmodule):
def test_get_html_with_non_existent_edx_video_id(self):
"""
- Tests the VideoModule get_html where a edx_video_id is given but a video is not found
+ Tests the VideoBlock get_html where a edx_video_id is given but a video is not found
"""
SOURCE_XML = u"""
{sources}
@@ -520,7 +519,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
""",
'edx_video_id': "meow",
'result': {
- 'download_video_link': u'example_source.mp4',
+ 'download_video_link': u'example.mp4',
'sources': [u'example.mp4', u'example.webm'],
}
}
@@ -530,11 +529,11 @@ class TestGetHtmlMethod(BaseTestXmodule):
sources=no_video_data['sources'],
edx_video_id=no_video_data['edx_video_id']
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
# Referencing a non-existent VAL ID in courseware won't cause an error --
- # it'll just fall back to the values in the VideoDescriptor.
- self.assertIn("example_source.mp4", self.item_descriptor.render(STUDENT_VIEW).content)
+ # it'll just fall back to the values in the VideoBlock.
+ self.assertIn("example.mp4", self.item_descriptor.render(STUDENT_VIEW).content)
def test_get_html_with_mocked_edx_video_id(self):
SOURCE_XML = """
@@ -542,7 +541,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
display_name="A Name"
sub="a_sub_file.srt.sjson" source="{source}"
download_video="{download_video}"
- start_time="01:00:03" end_time="01:00:10"
+ start_time="3603.0" end_time="3610.0"
edx_video_id="{edx_video_id}"
>
{sources}
@@ -596,7 +595,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
sources=data['sources'],
edx_video_id=data['edx_video_id']
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
with patch('edxval.api.get_video_info') as mock_get_video_info:
mock_get_video_info.return_value = {
@@ -620,7 +619,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'sources': data['result']['sources'],
})
expected_context.update({
@@ -636,7 +635,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
def test_get_html_with_existing_edx_video_id(self):
"""
- Tests the `VideoModule` `get_html` where `edx_video_id` is given and related video is found
+ Tests the `VideoBlock` `get_html` where `edx_video_id` is given and related video is found
"""
edx_video_id = 'thundercats'
# create video with provided edx_video_id and return encoded_videos
@@ -665,7 +664,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
def test_get_html_with_existing_unstripped_edx_video_id(self):
"""
- Tests the `VideoModule` `get_html` where `edx_video_id` with some unwanted tab(\t)
+ Tests the `VideoBlock` `get_html` where `edx_video_id` with some unwanted tab(\t)
is given and related video is found
"""
edx_video_id = 'thundercats'
@@ -731,7 +730,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
display_name="A Name"
sub="a_sub_file.srt.sjson" source="{source}"
download_video="{download_video}"
- start_time="01:00:03" end_time="01:00:10"
+ start_time="3603.0" end_time="3610.0"
edx_video_id="{edx_video_id}"
>
{sources}
@@ -769,7 +768,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
sources=data['sources'],
edx_video_id=data['edx_video_id']
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
# context returned by get_html
context = self.item_descriptor.render(STUDENT_VIEW).content
@@ -779,7 +778,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'sources': data['result']['sources'],
})
expected_context.update({
@@ -820,7 +819,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
sub="a_sub_file.srt.sjson" source="{source}"
download_video="{download_video}"
edx_video_id="{edx_video_id}"
- start_time="01:00:03" end_time="01:00:10"
+ start_time="3603.0" end_time="3610.0"
>
{sources}
@@ -834,7 +833,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
""",
'result': {
- 'download_video_link': u'example_source.mp4',
+ 'download_video_link': u'http://example.com/example.mp4',
'sources': [
u'http://cdn-example.com/example.mp4',
u'http://cdn-example.com/example.webm'
@@ -881,7 +880,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
sources=data['sources'],
edx_video_id=data['edx_video_id'],
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
self.item_descriptor.xmodule_runtime.user_location = 'CN'
context = self.item_descriptor.render('student_view').content
expected_context = dict(initial_context)
@@ -889,7 +888,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'sources': data['result'].get('sources', []),
})
expected_context.update({
@@ -919,7 +918,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
sub="a_sub_file.srt.sjson" source="{source}"
download_video="{download_video}"
edx_video_id="{edx_video_id}"
- start_time="01:00:03" end_time="01:00:10"
+ start_time="3603.0" end_time="3610.0"
>
{sources}
@@ -932,7 +931,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
""",
'result': {
- 'download_video_link': u'example_source.mp4',
+ 'download_video_link': u'http://example.com/example.mp4',
'sources': [
u'http://example.com/example.mp4',
],
@@ -972,7 +971,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
sources=data['sources'],
edx_video_id=data['edx_video_id'],
)
- self.initialize_module(data=DATA)
+ self.initialize_block(data=DATA)
# Mocking the edxval API call because if not done,
# the method throws exception as no VAL entry is found
@@ -992,7 +991,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'sources': data['result'].get('sources', []),
})
expected_context.update({
@@ -1025,7 +1024,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
with patch('xmodule.video_module.video_module.HLSPlaybackEnabledFlag.feature_enabled') as feature_enabled:
feature_enabled.return_value = hls_feature_enabled
video_xml = '[]'
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
self.item_descriptor.render(STUDENT_VIEW)
get_urls_for_profiles.assert_called_with(
self.item_descriptor.edx_video_id,
@@ -1050,7 +1049,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'desktop_mp4': 'https://mp4.com/dm.mp4'
}
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn("'download_video_link': 'https://mp4.com/dm.mp4'", context)
@@ -1069,7 +1068,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
"""
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn("'download_video_link': None", context)
@@ -1083,7 +1082,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
"""
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn('"saveStateEnabled": true', context)
context = self.item_descriptor.render(PUBLIC_VIEW).content
@@ -1097,7 +1096,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
video_xml = '[]'
get_course_video_image_url.return_value = '/media/video-images/poster.png'
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn('"poster": "/media/video-images/poster.png"', context)
@@ -1110,7 +1109,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
video_xml = '[]'
get_course_video_image_url.return_value = '/media/video-images/poster.png'
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn("\'poster\': \'null\'", context)
@@ -1121,7 +1120,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
Verify that `prioritize_hls` is set to `False` if `HLSPlaybackEnabledFlag` is disabled.
"""
video_xml = '[]'
- self.initialize_module(data=video_xml)
+ self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn('"prioritizeHls": false', context)
@@ -1176,13 +1175,13 @@ class TestGetHtmlMethod(BaseTestXmodule):
DEPRECATE_YOUTUBE_FLAG = waffle_flags()[DEPRECATE_YOUTUBE]
with patch.object(WaffleFlagCourseOverrideModel, 'override_value', return_value=data['course_override']):
with override_flag(DEPRECATE_YOUTUBE_FLAG.namespaced_flag_name, active=data['waffle_enabled']):
- self.initialize_module(data=video_xml, metadata=metadata)
+ self.initialize_block(data=video_xml, metadata=metadata)
context = self.item_descriptor.render(STUDENT_VIEW).content
self.assertIn(u'"prioritizeHls": {}'.format(data['result']), context)
@ddt.ddt
-class TestVideoDescriptorInitialization(BaseTestXmodule):
+class TestVideoBlockInitialization(BaseTestVideoXBlock):
"""
Make sure that module initialization works correctly.
"""
@@ -1191,66 +1190,9 @@ class TestVideoDescriptorInitialization(BaseTestXmodule):
METADATA = {}
def setUp(self):
- super(TestVideoDescriptorInitialization, self).setUp()
+ super(TestVideoBlockInitialization, self).setUp()
self.setup_course()
- def test_source_not_in_html5sources(self):
- metadata = {
- 'source': 'http://example.org/video.mp4',
- 'html5_sources': ['http://youtu.be/3_yD_cEKoCk.mp4'],
- }
-
- self.initialize_module(metadata=metadata)
- fields = self.item_descriptor.editable_metadata_fields
-
- self.assertIn('source', fields)
- self.assertEqual(self.item_descriptor.source, 'http://example.org/video.mp4')
- self.assertTrue(self.item_descriptor.download_video)
- self.assertTrue(self.item_descriptor.source_visible)
-
- def test_source_in_html5sources(self):
- metadata = {
- 'source': 'http://example.org/video.mp4',
- 'html5_sources': ['http://example.org/video.mp4'],
- }
-
- self.initialize_module(metadata=metadata)
- fields = self.item_descriptor.editable_metadata_fields
-
- self.assertNotIn('source', fields)
- self.assertTrue(self.item_descriptor.download_video)
- self.assertFalse(self.item_descriptor.source_visible)
-
- def test_download_video_is_explicitly_set(self):
- metadata = {
- 'track': u'http://some_track.srt',
- 'source': 'http://example.org/video.mp4',
- 'html5_sources': ['http://youtu.be/3_yD_cEKoCk.mp4'],
- 'download_video': False,
- }
-
- self.initialize_module(metadata=metadata)
-
- fields = self.item_descriptor.editable_metadata_fields
- self.assertIn('source', fields)
- self.assertIn('download_video', fields)
-
- self.assertFalse(self.item_descriptor.download_video)
- self.assertTrue(self.item_descriptor.source_visible)
- self.assertTrue(self.item_descriptor.download_track)
-
- def test_source_is_empty(self):
- metadata = {
- 'source': '',
- 'html5_sources': ['http://youtu.be/3_yD_cEKoCk.mp4'],
- }
-
- self.initialize_module(metadata=metadata)
- fields = self.item_descriptor.editable_metadata_fields
-
- self.assertNotIn('source', fields)
- self.assertFalse(self.item_descriptor.download_video)
-
@ddt.data(
(
{
@@ -1295,7 +1237,7 @@ class TestVideoDescriptorInitialization(BaseTestXmodule):
"""
with patch('xmodule.video_module.video_module.edxval_api.get_urls_for_profiles') as get_urls_for_profiles:
get_urls_for_profiles.return_value = val_video_encodings
- self.initialize_module(
+ self.initialize_block(
data='[]'
)
context = self.item_descriptor.get_context()
@@ -1332,7 +1274,7 @@ class TestVideoDescriptorInitialization(BaseTestXmodule):
"""
with patch('xmodule.video_module.video_module.edxval_api.get_urls_for_profiles') as get_urls_for_profiles:
get_urls_for_profiles.return_value = val_video_encodings
- self.initialize_module(
+ self.initialize_block(
data='[]'
)
context = self.item_descriptor.get_context()
@@ -1340,7 +1282,7 @@ class TestVideoDescriptorInitialization(BaseTestXmodule):
@ddt.ddt
-class TestEditorSavedMethod(BaseTestXmodule):
+class TestEditorSavedMethod(BaseTestVideoXBlock):
"""
Make sure that `editor_saved` method works correctly.
"""
@@ -1369,7 +1311,7 @@ class TestEditorSavedMethod(BaseTestXmodule):
for video.
"""
self.MODULESTORE = MODULESTORES[default_store] # pylint: disable=invalid-name
- self.initialize_module(metadata=self.metadata)
+ self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
with open(self.file_path, "r") as myfile:
save_to_store(myfile.read(), self.file_name, 'text/sjson', item.location)
@@ -1389,7 +1331,7 @@ class TestEditorSavedMethod(BaseTestXmodule):
sub will be generated by editor_saved function.
"""
self.MODULESTORE = MODULESTORES[default_store]
- self.initialize_module(metadata=self.metadata)
+ self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
with open(self.file_path, "r") as myfile:
save_to_store(myfile.read(), self.file_name, 'text/sjson', item.location)
@@ -1414,7 +1356,7 @@ class TestEditorSavedMethod(BaseTestXmodule):
self.metadata.update({
'edx_video_id': unstripped_video_id
})
- self.initialize_module(metadata=self.metadata)
+ self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
self.assertEqual(item.edx_video_id, unstripped_video_id)
@@ -1432,7 +1374,7 @@ class TestEditorSavedMethod(BaseTestXmodule):
for a given `edx_video_id`.
"""
self.MODULESTORE = MODULESTORES[default_store]
- self.initialize_module(metadata=self.metadata)
+ self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
self.assertEqual(item.youtube_id_1_0, '3_yD_cEKoCk')
@@ -1444,14 +1386,14 @@ class TestEditorSavedMethod(BaseTestXmodule):
@ddt.ddt
-class TestVideoDescriptorStudentViewJson(CacheIsolationTestCase):
+class TestVideoBlockStudentViewJson(BaseTestVideoXBlock, CacheIsolationTestCase):
"""
- Tests for the student_view_data method on VideoDescriptor.
+ Tests for the student_view_data method on VideoBlock.
"""
TEST_DURATION = 111.0
TEST_PROFILE = "mobile"
- TEST_SOURCE_URL = "http://www.example.com/source.mp4"
- TEST_LANGUAGE = "ge"
+ TEST_SOURCE_URL = u"http://www.example.com/source.mp4"
+ TEST_LANGUAGE = u"ge"
TEST_ENCODED_VIDEO = {
'profile': TEST_PROFILE,
'bitrate': 333,
@@ -1460,10 +1402,10 @@ class TestVideoDescriptorStudentViewJson(CacheIsolationTestCase):
}
TEST_EDX_VIDEO_ID = 'test_edx_video_id'
TEST_YOUTUBE_ID = 'test_youtube_id'
- TEST_YOUTUBE_EXPECTED_URL = 'https://www.youtube.com/watch?v=test_youtube_id'
+ TEST_YOUTUBE_EXPECTED_URL = u'https://www.youtube.com/watch?v=test_youtube_id'
def setUp(self):
- super(TestVideoDescriptorStudentViewJson, self).setUp()
+ super(TestVideoBlockStudentViewJson, self).setUp()
video_declaration = (
""
)
@@ -1474,7 +1416,8 @@ class TestVideoDescriptorStudentViewJson(CacheIsolationTestCase):
""]
)
self.transcript_url = "transcript_url"
- self.video = instantiate_descriptor(data=sample_xml)
+ self.initialize_block(data=sample_xml)
+ self.video = self.item_descriptor
self.video.runtime.handler_url = Mock(return_value=self.transcript_url)
self.video.runtime.course_id = MagicMock()
@@ -1576,7 +1519,8 @@ class TestVideoDescriptorStudentViewJson(CacheIsolationTestCase):
""
])
self.transcript_url = "transcript_url"
- self.video = instantiate_descriptor(data=sample_xml)
+ self.initialize_block(data=sample_xml)
+ self.video = self.item_descriptor
self.video.runtime.handler_url = Mock(return_value=self.transcript_url)
self.video.runtime.course_id = MagicMock()
result = self.get_result()
@@ -1639,12 +1583,12 @@ class TestVideoDescriptorStudentViewJson(CacheIsolationTestCase):
@ddt.ddt
-class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
+class VideoBlockTest(TestCase, VideoBlockTestBase):
"""
Tests for video descriptor that requires access to django settings.
"""
def setUp(self):
- super(VideoDescriptorTest, self).setUp()
+ super(VideoBlockTest, self).setUp()
self.descriptor.runtime.handler_url = MagicMock()
self.descriptor.runtime.course_id = MagicMock()
self.temp_dir = mkdtemp()
@@ -1724,7 +1668,7 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
expected_str = u"""
-
+
@@ -1816,7 +1760,7 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
"""
self.descriptor.edx_video_id = 'nonexistent'
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
- expected_str = """"""
+ expected_str = """"""
parser = etree.XMLParser(remove_blank_text=True)
expected = etree.XML(expected_str, parser=parser)
self.assertXmlEqual(expected, actual)
@@ -1829,7 +1773,7 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
mock_get_video_ids_info.return_value = True, []
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
- expected_str = ''
+ expected_str = ''
parser = etree.XMLParser(remove_blank_text=True)
expected = etree.XML(expected_str, parser=parser)
@@ -2162,7 +2106,7 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
"""
with self.assertRaises(ValCannotCreateError):
- VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
+ VideoBlock.from_xml(xml_data, module_system, id_generator=Mock())
with self.assertRaises(ValVideoNotFoundError):
get_video_info("test_edx_video_id")
@@ -2226,7 +2170,7 @@ class TestVideoWithBumper(TestVideo):
'branding_info': None,
'license': None,
'bumper_metadata': json.dumps(OrderedDict({
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'showCaptions': 'true',
'sources': ['http://test_bumper.mp4'],
'streams': '',
@@ -2251,7 +2195,7 @@ class TestVideoWithBumper(TestVideo):
'metadata': json.dumps(OrderedDict({
'autoAdvance': False,
'saveStateEnabled': True,
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg',
'sources': sources,
@@ -2325,7 +2269,7 @@ class TestAutoAdvanceVideo(TestVideo):
'metadata': json.dumps(OrderedDict({
'autoAdvance': autoadvance_flag,
'saveStateEnabled': True,
- 'saveStateUrl': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state',
+ 'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg',
'sources': [u'example.mp4', u'example.webm'],
@@ -2395,8 +2339,8 @@ class TestAutoAdvanceVideo(TestVideo):
"""
# This first render is done to initialize the instance
self.item_descriptor.render(STUDENT_VIEW)
- item_instance = self.item_descriptor.xmodule_runtime.xmodule_instance
- item_instance.video_auto_advance = new_value
+ self.item_descriptor.video_auto_advance = new_value
+ self.item_descriptor._reset_dirty_field(self.item_descriptor.fields['video_auto_advance']) # pylint: disable=protected-access
# After this step, render() should see the new value
# e.g. use self.item_descriptor.render(STUDENT_VIEW).content
diff --git a/lms/djangoapps/courseware/tests/test_video_xml.py b/lms/djangoapps/courseware/tests/test_video_xml.py
index d870a3c992..bed49f0524 100644
--- a/lms/djangoapps/courseware/tests/test_video_xml.py
+++ b/lms/djangoapps/courseware/tests/test_video_xml.py
@@ -16,8 +16,8 @@ course, section, subsection, unit, etc.
"""
from __future__ import absolute_import
-from xmodule.tests import LogicTest
-from xmodule.video_module import VideoDescriptor
+from django.test import TestCase
+from xmodule.video_module import VideoBlock
SOURCE_XML = """
@@ -34,10 +34,8 @@ SOURCE_XML = """
"""
-class VideoModuleLogicTest(LogicTest):
- """Tests for logic of Video Xmodule."""
-
- descriptor_class = VideoDescriptor
+class VideoBlockLogicTest(TestCase):
+ """Tests for logic of VideoBlock."""
raw_field_data = {
'data': ''
@@ -46,7 +44,7 @@ class VideoModuleLogicTest(LogicTest):
def test_parse_youtube(self):
"""Test parsing old-style Youtube ID strings into a dict."""
youtube_str = '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg'
- output = VideoDescriptor._parse_youtube(youtube_str)
+ output = VideoBlock._parse_youtube(youtube_str)
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
'1.00': 'ZwkTiUPN0mg',
'1.25': 'rsq9auxASqI',
@@ -58,7 +56,7 @@ class VideoModuleLogicTest(LogicTest):
empty string.
"""
youtube_str = '0.75:jNCf2gIqpeE'
- output = VideoDescriptor._parse_youtube(youtube_str)
+ output = VideoBlock._parse_youtube(youtube_str)
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
'1.00': '',
'1.25': '',
@@ -71,8 +69,8 @@ class VideoModuleLogicTest(LogicTest):
youtube_str = '1.00:p2Q6BrNhdh8'
youtube_str_hack = '1.0:p2Q6BrNhdh8'
self.assertEqual(
- VideoDescriptor._parse_youtube(youtube_str),
- VideoDescriptor._parse_youtube(youtube_str_hack)
+ VideoBlock._parse_youtube(youtube_str),
+ VideoBlock._parse_youtube(youtube_str_hack)
)
def test_parse_youtube_empty(self):
@@ -80,7 +78,7 @@ class VideoModuleLogicTest(LogicTest):
Some courses have empty youtube attributes, so we should handle
that well.
"""
- self.assertEqual(VideoDescriptor._parse_youtube(''),
+ self.assertEqual(VideoBlock._parse_youtube(''),
{'0.75': '',
'1.00': '',
'1.25': '',
diff --git a/lms/envs/production.py b/lms/envs/production.py
index 6c1c14fae9..b07e245ba9 100644
--- a/lms/envs/production.py
+++ b/lms/envs/production.py
@@ -806,8 +806,8 @@ FACEBOOK_APP_SECRET = AUTH_TOKENS.get("FACEBOOK_APP_SECRET")
FACEBOOK_APP_ID = AUTH_TOKENS.get("FACEBOOK_APP_ID")
XBLOCK_SETTINGS = ENV_TOKENS.get('XBLOCK_SETTINGS', {})
-XBLOCK_SETTINGS.setdefault("VideoDescriptor", {})["licensing_enabled"] = FEATURES.get("LICENSING", False)
-XBLOCK_SETTINGS.setdefault("VideoModule", {})['YOUTUBE_API_KEY'] = AUTH_TOKENS.get('YOUTUBE_API_KEY', YOUTUBE_API_KEY)
+XBLOCK_SETTINGS.setdefault("VideoBlock", {})["licensing_enabled"] = FEATURES.get("LICENSING", False)
+XBLOCK_SETTINGS.setdefault("VideoBlock", {})['YOUTUBE_API_KEY'] = AUTH_TOKENS.get('YOUTUBE_API_KEY', YOUTUBE_API_KEY)
##### VIDEO IMAGE STORAGE #####
VIDEO_IMAGE_SETTINGS = ENV_TOKENS.get('VIDEO_IMAGE_SETTINGS', VIDEO_IMAGE_SETTINGS)