Commit c860f790 by Greg Price

Merge pull request #7508 from edx/gprice/export-import-val

Include VAL data in video module export/import
parents e394c181 cfcb3048
...@@ -40,20 +40,7 @@ class VideoUploadTestMixin(object): ...@@ -40,20 +40,7 @@ class VideoUploadTestMixin(object):
"course_video_upload_token": self.test_token, "course_video_upload_token": self.test_token,
} }
self.save_course() self.save_course()
self.profiles = [ self.profiles = ["profile1", "profile2"]
{
"profile_name": "profile1",
"extension": "mp4",
"width": 640,
"height": 480,
},
{
"profile_name": "profile2",
"extension": "mp4",
"width": 1920,
"height": 1080,
},
]
self.previous_uploads = [ self.previous_uploads = [
{ {
"edx_video_id": "test1", "edx_video_id": "test1",
......
...@@ -15,20 +15,21 @@ the course, section, subsection, unit, etc. ...@@ -15,20 +15,21 @@ the course, section, subsection, unit, etc.
import unittest import unittest
import datetime import datetime
from uuid import uuid4 from uuid import uuid4
from mock import Mock, patch
from . import LogicTest
from lxml import etree from lxml import etree
from mock import ANY, Mock, patch
from django.conf import settings
from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.video_module import VideoDescriptor, create_youtube_string, get_video_from_cdn
from .test_import import DummySystem
from xblock.field_data import DictFieldData from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds from xblock.fields import ScopeIds
from xmodule.tests import get_test_descriptor_system from xmodule.tests import get_test_descriptor_system
from xmodule.video_module import VideoDescriptor, create_youtube_string, get_video_from_cdn
from xmodule.video_module.transcripts_utils import download_youtube_subs, save_to_store from xmodule.video_module.transcripts_utils import download_youtube_subs, save_to_store
from . import LogicTest
from django.conf import settings from .test_import import DummySystem
SRT_FILEDATA = ''' SRT_FILEDATA = '''
0 0
...@@ -89,6 +90,19 @@ def instantiate_descriptor(**field_data): ...@@ -89,6 +90,19 @@ def instantiate_descriptor(**field_data):
) )
# Because of the way xmodule.video_module.video_module imports edxval.api, we
# must mock the entire module, which requires making mock exception classes.
class _MockValVideoNotFoundError(Exception):
"""Mock ValVideoNotFoundError exception"""
pass
class _MockValCannotCreateError(Exception):
"""Mock ValCannotCreateError exception"""
pass
class VideoModuleTest(LogicTest): class VideoModuleTest(LogicTest):
"""Logic tests for Video Xmodule.""" """Logic tests for Video Xmodule."""
descriptor_class = VideoDescriptor descriptor_class = VideoDescriptor
...@@ -176,6 +190,21 @@ class VideoDescriptorTestBase(unittest.TestCase): ...@@ -176,6 +190,21 @@ class VideoDescriptorTestBase(unittest.TestCase):
super(VideoDescriptorTestBase, self).setUp() super(VideoDescriptorTestBase, self).setUp()
self.descriptor = instantiate_descriptor() self.descriptor = instantiate_descriptor()
def assertXmlEqual(self, expected, xml):
"""
Assert that the given XML fragments have the same attributes, text, and
(recursively) children
"""
def get_child_tags(elem):
"""Extract the list of tag names for children of elem"""
return [child.tag for child in elem]
for attr in ['tag', 'attrib', 'text', 'tail']:
self.assertEqual(getattr(expected, attr), getattr(xml, attr))
self.assertEqual(get_child_tags(expected), get_child_tags(xml))
for left, right in zip(expected, xml):
self.assertXmlEqual(left, right)
class TestCreateYoutubeString(VideoDescriptorTestBase): class TestCreateYoutubeString(VideoDescriptorTestBase):
""" """
...@@ -522,21 +551,61 @@ class VideoDescriptorImportTestCase(unittest.TestCase): ...@@ -522,21 +551,61 @@ class VideoDescriptorImportTestCase(unittest.TestCase):
'data': '' 'data': ''
}) })
@patch('xmodule.video_module.video_module.edxval_api')
def test_import_val_data(self, mock_val_api):
def mock_val_import(xml, edx_video_id):
"""Mock edxval.api.import_from_xml"""
self.assertEqual(xml.tag, 'video_asset')
self.assertEqual(dict(xml.items()), {'mock_attr': ''})
self.assertEqual(edx_video_id, 'test_edx_video_id')
mock_val_api.import_from_xml = Mock(wraps=mock_val_import)
module_system = DummySystem(load_error_modules=True)
# import new edx_video_id
xml_data = """
<video edx_video_id="test_edx_video_id">
<video_asset mock_attr=""/>
</video>
"""
video = VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
self.assert_attributes_equal(video, {'edx_video_id': 'test_edx_video_id'})
mock_val_api.import_from_xml.assert_called_once_with(ANY, 'test_edx_video_id')
@patch('xmodule.video_module.video_module.edxval_api')
def test_import_val_data_invalid(self, mock_val_api):
mock_val_api.ValCannotCreateError = _MockValCannotCreateError
mock_val_api.import_from_xml = Mock(side_effect=mock_val_api.ValCannotCreateError)
module_system = DummySystem(load_error_modules=True)
# Negative duration is invalid
xml_data = """
<video edx_video_id="test_edx_video_id">
<video_asset client_video_id="test_client_video_id" duration="-1"/>
</video>
"""
with self.assertRaises(mock_val_api.ValCannotCreateError):
VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
class VideoExportTestCase(VideoDescriptorTestBase): class VideoExportTestCase(VideoDescriptorTestBase):
""" """
Make sure that VideoDescriptor can export itself to XML correctly. Make sure that VideoDescriptor can export itself to XML correctly.
""" """
def assertXmlEqual(self, expected, xml): @patch('xmodule.video_module.video_module.edxval_api')
for attr in ['tag', 'attrib', 'text', 'tail']: def test_export_to_xml(self, mock_val_api):
self.assertEqual(getattr(expected, attr), getattr(xml, attr))
for left, right in zip(expected, xml):
self.assertXmlEqual(left, right)
def test_export_to_xml(self):
""" """
Test that we write the correct XML on export. Test that we write the correct XML on export.
""" """
def mock_val_export(edx_video_id):
"""Mock edxval.api.export_to_xml"""
return etree.Element( # pylint:disable=no-member
'video_asset',
attrib={'export_edx_video_id': edx_video_id}
)
mock_val_api.export_to_xml = mock_val_export
self.descriptor.youtube_id_0_75 = 'izygArpw-Qo' self.descriptor.youtube_id_0_75 = 'izygArpw-Qo'
self.descriptor.youtube_id_1_0 = 'p2Q6BrNhdh8' self.descriptor.youtube_id_1_0 = 'p2Q6BrNhdh8'
self.descriptor.youtube_id_1_25 = '1EeWXzPdhSA' self.descriptor.youtube_id_1_25 = '1EeWXzPdhSA'
...@@ -550,6 +619,7 @@ class VideoExportTestCase(VideoDescriptorTestBase): ...@@ -550,6 +619,7 @@ class VideoExportTestCase(VideoDescriptorTestBase):
self.descriptor.html5_sources = ['http://www.example.com/source.mp4', 'http://www.example.com/source.ogg'] self.descriptor.html5_sources = ['http://www.example.com/source.mp4', 'http://www.example.com/source.ogg']
self.descriptor.download_video = True self.descriptor.download_video = True
self.descriptor.transcripts = {'ua': 'ukrainian_translation.srt', 'ge': 'german_translation.srt'} self.descriptor.transcripts = {'ua': 'ukrainian_translation.srt', 'ge': 'german_translation.srt'}
self.descriptor.edx_video_id = 'test_edx_video_id'
xml = self.descriptor.definition_to_xml(None) # We don't use the `resource_fs` parameter xml = self.descriptor.definition_to_xml(None) # We don't use the `resource_fs` parameter
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
...@@ -561,11 +631,25 @@ class VideoExportTestCase(VideoDescriptorTestBase): ...@@ -561,11 +631,25 @@ class VideoExportTestCase(VideoDescriptorTestBase):
<handout src="http://www.example.com/handout"/> <handout src="http://www.example.com/handout"/>
<transcript language="ge" src="german_translation.srt" /> <transcript language="ge" src="german_translation.srt" />
<transcript language="ua" src="ukrainian_translation.srt" /> <transcript language="ua" src="ukrainian_translation.srt" />
<video_asset export_edx_video_id="test_edx_video_id"/>
</video> </video>
''' '''
expected = etree.XML(xml_string, parser=parser) expected = etree.XML(xml_string, parser=parser)
self.assertXmlEqual(expected, xml) self.assertXmlEqual(expected, xml)
@patch('xmodule.video_module.video_module.edxval_api')
def test_export_to_xml_val_error(self, mock_val_api):
# Export should succeed without VAL data if video does not exist
mock_val_api.ValVideoNotFoundError = _MockValVideoNotFoundError
mock_val_api.export_to_xml = Mock(side_effect=mock_val_api.ValVideoNotFoundError)
self.descriptor.edx_video_id = 'test_edx_video_id'
xml = self.descriptor.definition_to_xml(None)
parser = etree.XMLParser(remove_blank_text=True)
xml_string = '<video url_name="SampleProblem" download_video="false"/>'
expected = etree.XML(xml_string, parser=parser)
self.assertXmlEqual(expected, xml)
def test_export_to_xml_empty_end_time(self): def test_export_to_xml_empty_end_time(self):
""" """
Test that we write the correct XML on export. Test that we write the correct XML on export.
......
...@@ -404,8 +404,7 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler ...@@ -404,8 +404,7 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
xml_data: A string of xml that will be translated into data and children for xml_data: A string of xml that will be translated into data and children for
this module this module
system: A DescriptorSystem for interacting with external resources system: A DescriptorSystem for interacting with external resources
org and course are optional strings that will be used in the generated modules id_generator is used to generate course-specific urls and identifiers
url identifiers
""" """
xml_object = etree.fromstring(xml_data) xml_object = etree.fromstring(xml_data)
url_name = xml_object.get('url_name', xml_object.get('slug')) url_name = xml_object.get('url_name', xml_object.get('slug'))
...@@ -478,6 +477,12 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler ...@@ -478,6 +477,12 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
ele.set('src', self.transcripts[transcript_language]) ele.set('src', self.transcripts[transcript_language])
xml.append(ele) xml.append(ele)
if self.edx_video_id and edxval_api:
try:
xml.append(edxval_api.export_to_xml(self.edx_video_id))
except edxval_api.ValVideoNotFoundError:
pass
return xml return xml
def get_context(self): def get_context(self):
...@@ -621,6 +626,15 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler ...@@ -621,6 +626,15 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
if 'download_track' not in field_data and track is not None: if 'download_track' not in field_data and track is not None:
field_data['download_track'] = True field_data['download_track'] = True
video_asset_elem = xml.find('video_asset')
if (
edxval_api and
video_asset_elem is not None and
'edx_video_id' in field_data
):
# Allow ValCannotCreateError to escape
edxval_api.import_from_xml(video_asset_elem, field_data['edx_video_id'])
return field_data return field_data
def index_dictionary(self): def index_dictionary(self):
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -396,7 +396,7 @@ CREATE TABLE `auth_permission` ( ...@@ -396,7 +396,7 @@ CREATE TABLE `auth_permission` (
UNIQUE KEY `content_type_id` (`content_type_id`,`codename`), UNIQUE KEY `content_type_id` (`content_type_id`,`codename`),
KEY `auth_permission_e4470c6e` (`content_type_id`), KEY `auth_permission_e4470c6e` (`content_type_id`),
CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`) CONSTRAINT `content_type_id_refs_id_728de91f` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=499 DEFAULT CHARSET=utf8; ) ENGINE=InnoDB AUTO_INCREMENT=511 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `auth_registration`; DROP TABLE IF EXISTS `auth_registration`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
...@@ -623,6 +623,20 @@ CREATE TABLE `certificates_certificategenerationcoursesetting` ( ...@@ -623,6 +623,20 @@ CREATE TABLE `certificates_certificategenerationcoursesetting` (
KEY `certificates_certificategenerationcoursesetting_b4b47e7a` (`course_key`) KEY `certificates_certificategenerationcoursesetting_b4b47e7a` (`course_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `certificates_certificatehtmlviewconfiguration`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `certificates_certificatehtmlviewconfiguration` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`change_date` datetime NOT NULL,
`changed_by_id` int(11) DEFAULT NULL,
`enabled` tinyint(1) NOT NULL,
`configuration` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `certificates_certificatehtmlviewconfiguration_16905482` (`changed_by_id`),
CONSTRAINT `changed_by_id_refs_id_8584db17` FOREIGN KEY (`changed_by_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `certificates_certificatewhitelist`; DROP TABLE IF EXISTS `certificates_certificatewhitelist`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
...@@ -772,6 +786,31 @@ CREATE TABLE `course_creators_coursecreator` ( ...@@ -772,6 +786,31 @@ CREATE TABLE `course_creators_coursecreator` (
CONSTRAINT `user_id_refs_id_6a0e6044` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) CONSTRAINT `user_id_refs_id_6a0e6044` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `course_groups_coursecohort`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `course_groups_coursecohort` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`course_user_group_id` int(11) NOT NULL,
`assignment_type` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `course_user_group_id` (`course_user_group_id`),
CONSTRAINT `course_user_group_id_refs_id_8febc00f` FOREIGN KEY (`course_user_group_id`) REFERENCES `course_groups_courseusergroup` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `course_groups_coursecohortssettings`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `course_groups_coursecohortssettings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`is_cohorted` tinyint(1) NOT NULL,
`course_id` varchar(255) NOT NULL,
`cohorted_discussions` longtext,
`always_cohort_inline_discussions` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `course_id` (`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `course_groups_courseusergroup`; DROP TABLE IF EXISTS `course_groups_courseusergroup`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
...@@ -1031,8 +1070,8 @@ CREATE TABLE `django_admin_log` ( ...@@ -1031,8 +1070,8 @@ CREATE TABLE `django_admin_log` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `django_admin_log_fbfc09f1` (`user_id`), KEY `django_admin_log_fbfc09f1` (`user_id`),
KEY `django_admin_log_e4470c6e` (`content_type_id`), KEY `django_admin_log_e4470c6e` (`content_type_id`),
CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`), CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
CONSTRAINT `content_type_id_refs_id_288599e6` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`) CONSTRAINT `user_id_refs_id_c8665aa` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `django_comment_client_permission`; DROP TABLE IF EXISTS `django_comment_client_permission`;
...@@ -1094,7 +1133,7 @@ CREATE TABLE `django_content_type` ( ...@@ -1094,7 +1133,7 @@ CREATE TABLE `django_content_type` (
`model` varchar(100) NOT NULL, `model` varchar(100) NOT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `app_label` (`app_label`,`model`) UNIQUE KEY `app_label` (`app_label`,`model`)
) ENGINE=InnoDB AUTO_INCREMENT=166 DEFAULT CHARSET=utf8; ) ENGINE=InnoDB AUTO_INCREMENT=170 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `django_openid_auth_association`; DROP TABLE IF EXISTS `django_openid_auth_association`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
...@@ -1294,9 +1333,9 @@ DROP TABLE IF EXISTS `edxval_profile`; ...@@ -1294,9 +1333,9 @@ DROP TABLE IF EXISTS `edxval_profile`;
CREATE TABLE `edxval_profile` ( CREATE TABLE `edxval_profile` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`profile_name` varchar(50) NOT NULL, `profile_name` varchar(50) NOT NULL,
`extension` varchar(10) NOT NULL, `extension` varchar(10) DEFAULT 'mp4',
`width` int(10) unsigned NOT NULL, `width` int(10) unsigned DEFAULT '1',
`height` int(10) unsigned NOT NULL, `height` int(10) unsigned DEFAULT '1',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `profile_name` (`profile_name`) UNIQUE KEY `profile_name` (`profile_name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
...@@ -1650,6 +1689,20 @@ CREATE TABLE `milestones_usermilestone` ( ...@@ -1650,6 +1689,20 @@ CREATE TABLE `milestones_usermilestone` (
CONSTRAINT `milestone_id_refs_id_af7fa460` FOREIGN KEY (`milestone_id`) REFERENCES `milestones_milestone` (`id`) CONSTRAINT `milestone_id_refs_id_af7fa460` FOREIGN KEY (`milestone_id`) REFERENCES `milestones_milestone` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `mobile_api_mobileapiconfig`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `mobile_api_mobileapiconfig` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`change_date` datetime NOT NULL,
`changed_by_id` int(11) DEFAULT NULL,
`enabled` tinyint(1) NOT NULL,
`video_profiles` longtext NOT NULL,
PRIMARY KEY (`id`),
KEY `mobile_api_mobileapiconfig_16905482` (`changed_by_id`),
CONSTRAINT `changed_by_id_refs_id_97c2f4c8` FOREIGN KEY (`changed_by_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `notes_note`; DROP TABLE IF EXISTS `notes_note`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
...@@ -2245,7 +2298,7 @@ CREATE TABLE `south_migrationhistory` ( ...@@ -2245,7 +2298,7 @@ CREATE TABLE `south_migrationhistory` (
`migration` varchar(255) NOT NULL, `migration` varchar(255) NOT NULL,
`applied` datetime NOT NULL, `applied` datetime NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=222 DEFAULT CHARSET=utf8; ) ENGINE=InnoDB AUTO_INCREMENT=228 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `splash_splashconfig`; DROP TABLE IF EXISTS `splash_splashconfig`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
......
...@@ -2,15 +2,21 @@ ...@@ -2,15 +2,21 @@
"""Video xmodule tests in mongo.""" """Video xmodule tests in mongo."""
import json import json
from collections import OrderedDict from collections import OrderedDict
from mock import patch, MagicMock
from lxml import etree
from mock import patch, MagicMock, Mock
from django.conf import settings from django.conf import settings
from django.test import TestCase
from xmodule.video_module import create_youtube_string from xmodule.video_module import create_youtube_string, VideoDescriptor
from xmodule.x_module import STUDENT_VIEW from xmodule.x_module import STUDENT_VIEW
from xmodule.tests.test_video import VideoDescriptorTestBase from xmodule.tests.test_video import VideoDescriptorTestBase
from xmodule.tests.test_import import DummySystem
from edxval.api import create_profile, create_video from edxval.api import (
create_profile, create_video, get_video_info, ValCannotCreateError, ValVideoNotFoundError
)
from . import BaseTestXmodule from . import BaseTestXmodule
from .test_video_xml import SOURCE_XML from .test_video_xml import SOURCE_XML
...@@ -520,15 +526,7 @@ class TestGetHtmlMethod(BaseTestXmodule): ...@@ -520,15 +526,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
# create test profiles and their encodings # create test profiles and their encodings
encoded_videos = [] encoded_videos = []
for profile, extension in [("desktop_webm", "webm"), ("desktop_mp4", "mp4")]: for profile, extension in [("desktop_webm", "webm"), ("desktop_mp4", "mp4")]:
result = create_profile( create_profile(profile)
dict(
profile_name=profile,
extension=extension,
width=200,
height=2001
)
)
self.assertEqual(result, profile)
encoded_videos.append( encoded_videos.append(
dict( dict(
url=u"http://fake-video.edx.org/thundercats.{}".format(extension), url=u"http://fake-video.edx.org/thundercats.{}".format(extension),
...@@ -831,7 +829,7 @@ class TestVideoDescriptorInitialization(BaseTestXmodule): ...@@ -831,7 +829,7 @@ class TestVideoDescriptorInitialization(BaseTestXmodule):
self.assertFalse(self.item_descriptor.download_video) self.assertFalse(self.item_descriptor.download_video)
class VideoDescriptorTest(VideoDescriptorTestBase): class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
""" """
Tests for video descriptor that requires access to django settings. Tests for video descriptor that requires access to django settings.
""" """
...@@ -859,3 +857,79 @@ class VideoDescriptorTest(VideoDescriptorTestBase): ...@@ -859,3 +857,79 @@ class VideoDescriptorTest(VideoDescriptorTestBase):
] ]
rendered_context = self.descriptor.get_context() rendered_context = self.descriptor.get_context()
self.assertListEqual(rendered_context['tabs'], correct_tabs) self.assertListEqual(rendered_context['tabs'], correct_tabs)
def test_export_val_data(self):
self.descriptor.edx_video_id = 'test_edx_video_id'
create_profile('mobile')
create_video({
'edx_video_id': self.descriptor.edx_video_id,
'client_video_id': 'test_client_video_id',
'duration': 111,
'status': 'dummy',
'encoded_videos': [{
'profile': 'mobile',
'url': 'http://example.com/video',
'file_size': 222,
'bitrate': 333,
}],
})
actual = self.descriptor.definition_to_xml(resource_fs=None)
expected_str = """
<video download_video="false" url_name="SampleProblem">
<video_asset client_video_id="test_client_video_id" duration="111.0">
<encoded_video profile="mobile" url="http://example.com/video" file_size="222" bitrate="333"/>
</video_asset>
</video>
"""
parser = etree.XMLParser(remove_blank_text=True)
expected = etree.XML(expected_str, parser=parser)
self.assertXmlEqual(expected, actual)
def test_export_val_data_not_found(self):
self.descriptor.edx_video_id = 'nonexistent'
actual = self.descriptor.definition_to_xml(resource_fs=None)
expected_str = """<video download_video="false" url_name="SampleProblem"/>"""
parser = etree.XMLParser(remove_blank_text=True)
expected = etree.XML(expected_str, parser=parser)
self.assertXmlEqual(expected, actual)
def test_import_val_data(self):
create_profile('mobile')
module_system = DummySystem(load_error_modules=True)
xml_data = """
<video edx_video_id="test_edx_video_id">
<video_asset client_video_id="test_client_video_id" duration="111.0">
<encoded_video profile="mobile" url="http://example.com/video" file_size="222" bitrate="333"/>
</video_asset>
</video>
"""
video = VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
self.assertEqual(video.edx_video_id, 'test_edx_video_id')
video_data = get_video_info(video.edx_video_id)
self.assertEqual(video_data['client_video_id'], 'test_client_video_id')
self.assertEqual(video_data['duration'], 111)
self.assertEqual(video_data['status'], 'imported')
self.assertEqual(video_data['courses'], [])
self.assertEqual(video_data['encoded_videos'][0]['profile'], 'mobile')
self.assertEqual(video_data['encoded_videos'][0]['url'], 'http://example.com/video')
self.assertEqual(video_data['encoded_videos'][0]['file_size'], 222)
self.assertEqual(video_data['encoded_videos'][0]['bitrate'], 333)
def test_import_val_data_invalid(self):
create_profile('mobile')
module_system = DummySystem(load_error_modules=True)
# Negative file_size is invalid
xml_data = """
<video edx_video_id="test_edx_video_id">
<video_asset client_video_id="test_client_video_id" duration="111.0">
<encoded_video profile="mobile" url="http://example.com/video" file_size="-222" bitrate="333"/>
</video_asset>
</video>
"""
with self.assertRaises(ValCannotCreateError):
VideoDescriptor.from_xml(xml_data, module_system, id_generator=Mock())
with self.assertRaises(ValVideoNotFoundError):
get_video_info("test_edx_video_id")
...@@ -63,24 +63,9 @@ class TestVideoAPITestCase(MobileAPITestCase): ...@@ -63,24 +63,9 @@ class TestVideoAPITestCase(MobileAPITestCase):
self.youtube_url = 'http://val.edx.org/val/youtube.mp4' self.youtube_url = 'http://val.edx.org/val/youtube.mp4'
self.html5_video_url = 'http://video.edx.org/html5/video.mp4' self.html5_video_url = 'http://video.edx.org/html5/video.mp4'
api.create_profile({ api.create_profile('youtube')
'profile_name': 'youtube', api.create_profile('mobile_high')
'extension': 'mp4', api.create_profile('mobile_low')
'width': 1280,
'height': 720
})
api.create_profile({
'profile_name': 'mobile_high',
'extension': 'mp4',
'width': 750,
'height': 590
})
api.create_profile({
'profile_name': 'mobile_low',
'extension': 'mp4',
'width': 640,
'height': 480
})
# create the video in VAL # create the video in VAL
api.create_video({ api.create_video({
......
...@@ -35,7 +35,7 @@ git+https://github.com/mitocw/django-cas.git@60a5b8e5a62e63e0d5d224a87f0b489201a ...@@ -35,7 +35,7 @@ git+https://github.com/mitocw/django-cas.git@60a5b8e5a62e63e0d5d224a87f0b489201a
-e git+https://github.com/edx/ease.git@97de68448e5495385ba043d3091f570a699d5b5f#egg=ease -e git+https://github.com/edx/ease.git@97de68448e5495385ba043d3091f570a699d5b5f#egg=ease
-e git+https://github.com/edx/i18n-tools.git@193cebd9aa784f8899ef496f2aa050b08eff402b#egg=i18n-tools -e git+https://github.com/edx/i18n-tools.git@193cebd9aa784f8899ef496f2aa050b08eff402b#egg=i18n-tools
-e git+https://github.com/edx/edx-oauth2-provider.git@0.4.2#egg=oauth2-provider -e git+https://github.com/edx/edx-oauth2-provider.git@0.4.2#egg=oauth2-provider
-e git+https://github.com/edx/edx-val.git@64aa7637e3459fb3000a85a9e156880a40307dd1#egg=edx-val -e git+https://github.com/edx/edx-val.git@cb9cf1a37124ad8e589734b36d4e8199e0082a02#egg=edx-val
-e git+https://github.com/pmitros/RecommenderXBlock.git@9b07e807c89ba5761827d0387177f71aa57ef056#egg=recommender-xblock -e git+https://github.com/pmitros/RecommenderXBlock.git@9b07e807c89ba5761827d0387177f71aa57ef056#egg=recommender-xblock
-e git+https://github.com/edx/edx-milestones.git@547f2250ee49e73ce8d7ff4e78ecf1b049892510#egg=edx-milestones -e git+https://github.com/edx/edx-milestones.git@547f2250ee49e73ce8d7ff4e78ecf1b049892510#egg=edx-milestones
-e git+https://github.com/edx/edx-search.git@21ac6b06b3bfe789dcaeaf4e2ab5b00a688324d4#egg=edx-search -e git+https://github.com/edx/edx-search.git@21ac6b06b3bfe789dcaeaf4e2ab5b00a688324d4#egg=edx-search
......
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