Import video transcripts - EDUCATOR-2173

This commit is contained in:
Mushtaq Ali
2018-03-01 16:00:26 +05:00
parent 3db89e98ba
commit 5a9477af30
11 changed files with 409 additions and 67 deletions

View File

@@ -313,7 +313,12 @@ class CourseTestCase(ProceduralCourseTestMixin, ModuleStoreTestCase):
self.assertEqual(course1_item.data, course2_item.data)
# compare meta-data
self.assertEqual(own_metadata(course1_item), own_metadata(course2_item))
course1_metadata = own_metadata(course1_item)
course2_metadata = own_metadata(course2_item)
# Omit edx_video_id as it can be different in case of extrnal video imports.
course1_metadata.pop('edx_video_id', None)
course2_metadata.pop('edx_video_id', None)
self.assertEqual(course1_metadata, course2_metadata)
# compare children
self.assertEqual(course1_item.has_children, course2_item.has_children)

View File

@@ -6,6 +6,7 @@ Unit tests for the Mongo modulestore
# pylint: disable=bad-continuation
from nose.tools import assert_equals, assert_raises, \
assert_not_equals, assert_false, assert_true, assert_greater, assert_is_instance, assert_is_none
from django.test import TestCase
# pylint: enable=E0611
from path import Path as path
import pymongo
@@ -15,7 +16,6 @@ from tempfile import mkdtemp
from uuid import uuid4
from datetime import datetime
from pytz import UTC
import unittest
from mock import patch
from xblock.core import XBlock
@@ -68,7 +68,7 @@ class ReferenceTestXBlock(XModuleMixin):
reference_dict = ReferenceValueDict(scope=Scope.settings)
class TestMongoModuleStoreBase(unittest.TestCase):
class TestMongoModuleStoreBase(TestCase):
'''
Basic setup for all tests
'''
@@ -772,7 +772,7 @@ class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore):
self.assertRaises(ItemNotFoundError, lambda: self.draft_store.get_all_asset_metadata(course_key, 'asset')[:1])
class TestMongoKeyValueStore(unittest.TestCase):
class TestMongoKeyValueStore(TestCase):
"""
Tests for MongoKeyValueStore.
"""

View File

@@ -153,9 +153,9 @@ class CountMongoCallsCourseTraversal(TestCase):
(MIXED_SPLIT_MODULESTORE_BUILDER, 0, False, True, 38),
(MIXED_SPLIT_MODULESTORE_BUILDER, 0, True, True, 38),
(MIXED_SPLIT_MODULESTORE_BUILDER, None, False, False, 4),
(MIXED_SPLIT_MODULESTORE_BUILDER, None, True, False, 4),
(MIXED_SPLIT_MODULESTORE_BUILDER, 0, False, False, 4),
(MIXED_SPLIT_MODULESTORE_BUILDER, 0, True, False, 4)
(MIXED_SPLIT_MODULESTORE_BUILDER, None, True, False, 3),
(MIXED_SPLIT_MODULESTORE_BUILDER, 0, False, False, 3),
(MIXED_SPLIT_MODULESTORE_BUILDER, 0, True, False, 3)
)
@ddt.unpack
def test_number_mongo_calls(self, store_builder, depth, lazy, access_all_block_fields, num_mongo_calls):

View File

@@ -3,7 +3,7 @@ Tests around our XML modulestore, including importing
well-formed and not-well-formed XML.
"""
import os.path
import unittest
from django.test import TestCase
from glob import glob
from mock import patch, Mock
@@ -28,7 +28,7 @@ def glob_tildes_at_end(path):
return no_tildes + with_tildes
class TestXMLModuleStore(unittest.TestCase):
class TestXMLModuleStore(TestCase):
"""
Test around the XML modulestore
"""

View File

@@ -1,10 +1,13 @@
# -*- coding: utf-8 -*-
import datetime
import ddt
import unittest
from tempfile import mkdtemp
from fs.memoryfs import MemoryFS
import ddt
from django.test import TestCase
from fs.osfs import OSFS
from lxml import etree
from mock import Mock, patch
@@ -33,7 +36,7 @@ COURSE = 'test_course'
class DummySystem(ImportSystem):
@patch('xmodule.modulestore.xml.OSFS', lambda dir: MemoryFS())
@patch('xmodule.modulestore.xml.OSFS', lambda dir: OSFS(mkdtemp()))
def __init__(self, load_error_modules, library=False):
if library:
@@ -58,7 +61,7 @@ class DummySystem(ImportSystem):
raise Exception("Shouldn't be called")
class BaseCourseTestCase(unittest.TestCase):
class BaseCourseTestCase(TestCase):
'''Make sure module imports work properly, including for malformed inputs'''
@staticmethod
def get_system(load_error_modules=True, library=False):
@@ -208,7 +211,8 @@ class ImportTestCase(BaseCourseTestCase):
)
# Now export and check things
descriptor.runtime.export_fs = MemoryFS()
file_system = OSFS(mkdtemp())
descriptor.runtime.export_fs = file_system.makedir(u'course', recreate=True)
node = etree.Element('unknown')
descriptor.add_xml_to_node(node)
@@ -594,7 +598,6 @@ class ImportTestCase(BaseCourseTestCase):
video = sections[i]
# Name should be 'video_{hash}'
print "video {0} url_name: {1}".format(i, video.url_name)
self.assertEqual(len(video.url_name), len('video_') + 12)
def test_poll_and_conditional_import(self):

View File

@@ -24,6 +24,7 @@ from mock import ANY, Mock, patch, MagicMock
import ddt
from django.conf import settings
from django.test import TestCase
from django.test.utils import override_settings
from fs.osfs import OSFS
@@ -34,7 +35,7 @@ from xblock.fields import ScopeIds
from xmodule.tests import get_test_descriptor_system
from xmodule.validation import StudioValidationMessage
from xmodule.video_module import VideoDescriptor, create_youtube_string, EXPORT_STATIC_DIR
from xmodule.video_module import VideoDescriptor, create_youtube_string, EXPORT_IMPORT_STATIC_DIR
from xmodule.video_module.transcripts_utils import download_youtube_subs, save_to_store
from . import LogicTest
from .test_import import DummySystem
@@ -259,7 +260,7 @@ class TestCreateYouTubeUrl(VideoDescriptorTestBase):
@ddt.ddt
class VideoDescriptorImportTestCase(unittest.TestCase):
class VideoDescriptorImportTestCase(TestCase):
"""
Make sure that VideoDescriptor can import an old XML-based video correctly.
"""
@@ -628,30 +629,46 @@ class VideoDescriptorImportTestCase(unittest.TestCase):
@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, course_id):
"""
Test that `from_xml` works method works as expected.
"""
def mock_val_import(xml, edx_video_id, resource_fs, static_dir, external_transcripts, course_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')
self.assertEqual(static_dir, EXPORT_IMPORT_STATIC_DIR)
self.assertIsNotNone(resource_fs)
self.assertEqual(external_transcripts, {u'en': [u'subs_3_yD_cEKoCk.srt.sjson']})
self.assertEqual(course_id, 'test_course_id')
return edx_video_id
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)
# Create static directory in import file system and place transcript files inside it.
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
# import new edx_video_id
xml_data = """
<video edx_video_id="test_edx_video_id">
<video edx_video_id="{edx_video_id}">
<video_asset mock_attr=""/>
</video>
"""
""".format(
edx_video_id=edx_video_id
)
id_generator = Mock()
id_generator.target_course_id = 'test_course_id'
video = VideoDescriptor.from_xml(xml_data, module_system, id_generator)
self.assert_attributes_equal(video, {'edx_video_id': 'test_edx_video_id'})
self.assert_attributes_equal(video, {'edx_video_id': edx_video_id})
mock_val_api.import_from_xml.assert_called_once_with(
ANY,
'test_edx_video_id',
edx_video_id,
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR,
{u'en': [u'subs_3_yD_cEKoCk.srt.sjson']},
course_id='test_course_id'
)
@@ -721,7 +738,7 @@ class VideoExportTestCase(VideoDescriptorTestBase):
self.assertXmlEqual(expected, xml)
mock_val_api.export_to_xml.assert_called_once_with(
video_id=edx_video_id,
static_dir=EXPORT_STATIC_DIR,
static_dir=EXPORT_IMPORT_STATIC_DIR,
resource_fs=self.file_system,
course_id=unicode(self.descriptor.runtime.course_id.for_branch(None)),
)

View File

@@ -2,10 +2,10 @@
Xml parsing tests for XModules
"""
import pprint
from django.test import TestCase
from lxml import etree
from mock import Mock
from six import text_type
from unittest import TestCase
from xmodule.x_module import XMLParsingSystem, policy_key
from xmodule.mako_module import MakoDescriptorSystem

View File

@@ -4,7 +4,8 @@ Factories for generating edXML for testing XModule import
import inspect
from fs.memoryfs import MemoryFS
from tempfile import mkdtemp
from fs.osfs import OSFS
from factory import Factory, lazy_attribute, post_generation, Sequence
from lxml import etree
@@ -68,7 +69,7 @@ class XmlImportFactory(Factory):
class Meta(object):
model = XmlImportData
filesystem = MemoryFS()
filesystem = OSFS(mkdtemp())
xblock_mixins = (InheritanceMixin, XModuleMixin, HierarchyMixin)
xblock_select = only_xmodules
url_name = Sequence(str)

View File

@@ -16,7 +16,7 @@ import copy
import json
import logging
import random
from collections import OrderedDict
from collections import defaultdict, OrderedDict
from operator import itemgetter
from pkg_resources import resource_string
@@ -48,6 +48,7 @@ from .transcripts_utils import (
Transcript,
VideoTranscriptsMixin,
clean_video_id,
subs_filename,
)
from .transcripts_model_utils import (
is_val_transcript_feature_enabled_for_course
@@ -99,7 +100,8 @@ log = logging.getLogger(__name__)
_ = lambda text: text
EXPORT_STATIC_DIR = u'static'
EXPORT_IMPORT_COURSE_DIR = u'course'
EXPORT_IMPORT_STATIC_DIR = u'static'
@XBlock.wants('settings', 'completion')
@@ -649,8 +651,12 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
field_data,
)
# update val with info extracted from `xml_object`
video.import_video_info_into_val(xml_object, getattr(id_generator, 'target_course_id', None))
# Update VAL with info extracted from `xml_object`
video.edx_video_id = video.import_video_info_into_val(
xml_object,
system.resources_fs,
getattr(id_generator, 'target_course_id', None)
)
return video
@@ -716,16 +722,16 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
xml.append(ele)
edx_video_id = clean_video_id(self.edx_video_id)
if edx_video_id:
if edxval_api and edx_video_id:
try:
# Create static dir if not created earlier.
resource_fs.makedirs(EXPORT_STATIC_DIR, recreate=True)
resource_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
xml.append(
edxval_api.export_to_xml(
video_id=edx_video_id,
resource_fs=resource_fs,
static_dir=EXPORT_STATIC_DIR,
static_dir=EXPORT_IMPORT_STATIC_DIR,
course_id=unicode(self.runtime.course_id.for_branch(None))
)
)
@@ -934,28 +940,49 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
return field_data
def import_video_info_into_val(self, xml, course_id):
def import_video_info_into_val(self, xml, resource_fs, course_id):
"""
Import parsed video info from `xml` into edxval.
Arguments:
xml (lxml object): xml representation of video to be imported
xml (lxml object): xml representation of video to be imported.
resource_fs (OSFS): Import file system.
course_id (str): course id
"""
edx_video_id = ''
if self.edx_video_id is not None:
edx_video_id = self.edx_video_id.strip()
edx_video_id = clean_video_id(self.edx_video_id)
# Create video_asset is not already present.
video_asset_elem = xml.find('video_asset')
if edxval_api and video_asset_elem is not None:
# Always pass the edx_video_id, Whether the video is internal or external
# In case of external, we only need to import transcripts and for that
# purpose video id is already present in the xml
edxval_api.import_from_xml(
if video_asset_elem is None:
video_asset_elem = etree.Element('video_asset')
# This will be a dict containing the list of names of the external transcripts.
# Example:
# {
# 'en': ['The_Flash.srt', 'Harry_Potter.srt'],
# 'es': ['Green_Arrow.srt']
# }
external_transcripts = defaultdict(list)
# Add trancript from self.sub and self.youtube_id_1_0 fields.
external_transcripts['en'] = [
subs_filename(transcript, 'en')
for transcript in [self.sub, self.youtube_id_1_0] if transcript
]
for language_code, transcript in self.transcripts.items():
external_transcripts[language_code].append(transcript)
if edxval_api:
edx_video_id = edxval_api.import_from_xml(
video_asset_elem,
edx_video_id,
resource_fs,
EXPORT_IMPORT_STATIC_DIR,
external_transcripts,
course_id=course_id
)
return edx_video_id
def index_dictionary(self):
xblock_body = super(VideoDescriptor, self).index_dictionary()

View File

@@ -132,8 +132,10 @@ 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)
self.assertItemsEqual(
dump[video_id]['metadata'].keys(),
course_metadata.keys(),
['download_video', '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'])

View File

@@ -27,6 +27,7 @@ from edxval.api import (
get_video_transcript,
get_video_transcript_data
)
from edxval.utils import create_file_in_fs
from lxml import etree
from mock import MagicMock, Mock, patch
from nose.plugins.attrib import attr
@@ -40,8 +41,8 @@ from xmodule.modulestore.tests.django_utils import TEST_DATA_MONGO_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, rewrite_video_url, video_utils
from xmodule.video_module.transcripts_utils import Transcript, save_to_store
from xmodule.video_module.video_module import EXPORT_STATIC_DIR
from xmodule.video_module.transcripts_utils import Transcript, save_to_store, subs_filename
from xmodule.video_module.video_module import EXPORT_IMPORT_STATIC_DIR, EXPORT_IMPORT_COURSE_DIR
from xmodule.x_module import STUDENT_VIEW
from .helpers import BaseTestXmodule
@@ -53,7 +54,7 @@ MODULESTORES = {
ModuleStoreEnum.Type.split: TEST_DATA_SPLIT_MODULESTORE,
}
TRANSCRIPT_FILE_DATA = """
TRANSCRIPT_FILE_SRT_DATA = """
1
00:00:14,370 --> 00:00:16,530
I am overwatch.
@@ -63,6 +64,8 @@ I am overwatch.
可以用“我不太懂艺术 但我知道我喜欢什么”做比喻.
"""
TRANSCRIPT_FILE_SJSON_DATA = """{\n "start": [10],\n "end": [100],\n "text": ["Hi, welcome to edxval."]\n}"""
@attr(shard=1)
class TestVideoYouTube(TestVideo):
@@ -1521,6 +1524,7 @@ class TestVideoDescriptorStudentViewJson(TestCase):
@attr(shard=1)
@ddt.ddt
class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
"""
Tests for video descriptor that requires access to django settings.
@@ -1530,16 +1534,16 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
self.descriptor.runtime.handler_url = MagicMock()
self.descriptor.runtime.course_id = MagicMock()
self.temp_dir = mkdtemp()
self.file_system = OSFS(self.temp_dir)
file_system = OSFS(self.temp_dir)
self.file_system = file_system.makedir(EXPORT_IMPORT_COURSE_DIR, recreate=True)
self.addCleanup(shutil.rmtree, self.temp_dir)
def get_video_transcript_data(self, video_id):
def get_video_transcript_data(self, video_id, language_code='en', file_format='srt', provider='Custom'):
return dict(
video_id=video_id,
language_code='ar',
url='{media_url}ext101.srt'.format(media_url=settings.MEDIA_URL), # MEDIA_URL is /static/uploads/
provider='Cielo24',
file_format='srt',
language_code=language_code,
provider=provider,
file_format=file_format,
)
def test_get_context(self):
@@ -1575,7 +1579,10 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
"""
language_code = 'ar'
transcript_file_name = 'test_edx_video_id-ar.srt'
expected_transcript_path = combine(self.temp_dir, combine(EXPORT_STATIC_DIR, transcript_file_name))
expected_transcript_path = combine(
combine(self.temp_dir, EXPORT_IMPORT_COURSE_DIR),
combine(EXPORT_IMPORT_STATIC_DIR, transcript_file_name)
)
self.descriptor.edx_video_id = 'test_edx_video_id'
create_profile('mobile')
@@ -1591,14 +1598,14 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
'bitrate': 333,
}],
})
transcript_url = create_or_update_video_transcript(
create_or_update_video_transcript(
video_id=self.descriptor.edx_video_id,
language_code=language_code,
metadata={
'provider': 'Cielo24',
'file_format': 'srt'
},
file_data=ContentFile(TRANSCRIPT_FILE_DATA)
file_data=ContentFile(TRANSCRIPT_FILE_SRT_DATA)
)
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
@@ -1607,12 +1614,11 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
<video_asset client_video_id="test_client_video_id" duration="111.0" image="">
<encoded_video profile="mobile" url="http://example.com/video" file_size="222" bitrate="333"/>
<transcripts>
<transcript file_format="srt" file_name='video-transcripts/{transcript_name}' language_code="{language_code}" provider="Cielo24"/>
<transcript file_format="srt" language_code="{language_code}" provider="Cielo24"/>
</transcripts>
</video_asset>
</video>
""".format(
transcript_name=transcript_url.split('/')[-1],
language_code=language_code
)
parser = etree.XMLParser(remove_blank_text=True)
@@ -1620,7 +1626,7 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
self.assertXmlEqual(expected, actual)
# Verify transcript file is created.
self.assertEqual([transcript_file_name], self.file_system.listdir(EXPORT_STATIC_DIR))
self.assertEqual([transcript_file_name], self.file_system.listdir(EXPORT_IMPORT_STATIC_DIR))
# Also verify the content of created transcript file.
expected_transcript_content = File(open(expected_transcript_path)).read()
@@ -1653,22 +1659,67 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
self.assertXmlEqual(expected, actual)
def test_import_val_data_internal(self):
"""
Test that import val data internal works as expected.
"""
create_profile('mobile')
module_system = DummySystem(load_error_modules=True)
edx_video_id = 'test_edx_video_id'
sub_id = '0CzPOIIdUsA'
external_transcript_name = 'The_Flash.srt'
external_transcript_language_code = 'ur'
val_transcript_language_code = 'ar'
val_transcript_provider = 'Cielo24'
external_transcripts = {
external_transcript_language_code: external_transcript_name
}
# Create static directory in import file system and place transcript files inside it.
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
# Create VAL transcript.
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
'test_edx_video_id-ar.srt',
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
# Create self.sub and self.transcripts transcript.
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
subs_filename(sub_id, self.descriptor.transcript_language),
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
external_transcript_name,
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
xml_data = """
<video edx_video_id="test_edx_video_id">
<video edx_video_id='{edx_video_id}' sub='{sub_id}' transcripts='{transcripts}'>
<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"/>
<transcripts>
<transcript file_format="srt" file_name="ext101.srt" language_code="ar" provider="Cielo24" video_id="test_edx_video_id"/>
<transcript file_format="srt" language_code="{val_transcript_language_code}" provider="{val_transcript_provider}"/>
</transcripts>
</video_asset>
</video>
"""
""".format(
edx_video_id=edx_video_id,
sub_id=sub_id,
transcripts=json.dumps(external_transcripts),
val_transcript_language_code=val_transcript_language_code,
val_transcript_provider=val_transcript_provider
)
id_generator = Mock()
id_generator.target_course_id = "test_course_id"
video = self.descriptor.from_xml(xml_data, module_system, id_generator)
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')
@@ -1679,10 +1730,246 @@ class VideoDescriptorTest(TestCase, VideoDescriptorTestBase):
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)
# verify transcript data
self.assertDictEqual(
get_video_transcript(video.edx_video_id, 'ar'),
self.get_video_transcript_data('test_edx_video_id')
# Verify that VAL transcript is imported.
self.assertDictContainsSubset(
self.get_video_transcript_data(
edx_video_id,
language_code=val_transcript_language_code,
provider=val_transcript_provider
),
get_video_transcript(video.edx_video_id, val_transcript_language_code)
)
# Verify that transcript from sub field is imported.
self.assertDictContainsSubset(
self.get_video_transcript_data(
edx_video_id,
language_code=self.descriptor.transcript_language
),
get_video_transcript(video.edx_video_id, self.descriptor.transcript_language)
)
# Verify that transcript from transcript field is imported.
self.assertDictContainsSubset(
self.get_video_transcript_data(
edx_video_id,
language_code=external_transcript_language_code
),
get_video_transcript(video.edx_video_id, external_transcript_language_code)
)
def test_import_no_video_id(self):
"""
Test that importing a video with no video id, creates a new external video.
"""
xml_data = """<video><video_asset></video_asset></video>"""
module_system = DummySystem(load_error_modules=True)
id_generator = Mock()
# Verify edx_video_id is empty before.
self.assertEqual(self.descriptor.edx_video_id, u'')
video = self.descriptor.from_xml(xml_data, module_system, id_generator)
# Verify edx_video_id is populated after the import.
self.assertNotEqual(video.edx_video_id, u'')
video_data = get_video_info(video.edx_video_id)
self.assertEqual(video_data['client_video_id'], 'External Video')
self.assertEqual(video_data['duration'], 0.0)
self.assertEqual(video_data['status'], 'external')
def test_import_val_transcript(self):
"""
Test that importing a video with val transcript, creates a new transcript record.
"""
edx_video_id = 'test_edx_video_id'
val_transcript_language_code = 'es'
val_transcript_provider = 'Cielo24'
xml_data = """
<video edx_video_id='{edx_video_id}'>
<video_asset client_video_id="test_client_video_id" duration="111.0">
<transcripts>
<transcript file_format="srt" language_code="{val_transcript_language_code}" provider="{val_transcript_provider}"/>
</transcripts>
</video_asset>
</video>
""".format(
edx_video_id=edx_video_id,
val_transcript_language_code=val_transcript_language_code,
val_transcript_provider=val_transcript_provider
)
module_system = DummySystem(load_error_modules=True)
id_generator = Mock()
# Create static directory in import file system and place transcript files inside it.
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
# Create VAL transcript.
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
'test_edx_video_id-es.srt',
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
# Verify edx_video_id is empty before.
self.assertEqual(self.descriptor.edx_video_id, u'')
video = self.descriptor.from_xml(xml_data, module_system, id_generator)
# Verify edx_video_id is populated after the import.
self.assertNotEqual(video.edx_video_id, u'')
video_data = get_video_info(video.edx_video_id)
self.assertEqual(video_data['status'], 'imported')
# Verify that VAL transcript is imported.
self.assertDictContainsSubset(
self.get_video_transcript_data(
edx_video_id,
language_code=val_transcript_language_code,
provider=val_transcript_provider
),
get_video_transcript(video.edx_video_id, val_transcript_language_code)
)
@ddt.data(
(
'test_sub_id',
{'en': 'The_Flash.srt'},
'<transcripts><transcript file_format="srt" language_code="en" provider="Cielo24"/></transcripts>',
# VAL transcript takes priority
{
'video_id': u'test_edx_video_id',
'language_code': u'en',
'file_format': 'srt',
'provider': 'Cielo24'
}
),
(
'',
{'en': 'The_Flash.srt'},
'<transcripts><transcript file_format="srt" language_code="en" provider="Cielo24"/></transcripts>',
# VAL transcript takes priority
{
'video_id': u'test_edx_video_id',
'language_code': u'en',
'file_format': 'srt',
'provider': 'Cielo24'
}
),
(
'test_sub_id',
{},
'<transcripts><transcript file_format="srt" language_code="en" provider="Cielo24"/></transcripts>',
# VAL transcript takes priority
{
'video_id': u'test_edx_video_id',
'language_code': u'en',
'file_format': 'srt',
'provider': 'Cielo24'
}
),
(
'test_sub_id',
{'en': 'The_Flash.srt'},
'',
# self.sub transcript takes priority
{
'video_id': u'test_edx_video_id',
'language_code': u'en',
'file_format': 'sjson',
'provider': 'Custom'
}
),
(
'',
{'en': 'The_Flash.srt'},
'',
# self.transcripts would be saved.
{
'video_id': u'test_edx_video_id',
'language_code': u'en',
'file_format': 'srt',
'provider': 'Custom'
}
)
)
@ddt.unpack
def test_import_val_transcript_priority(self, sub_id, external_transcripts, val_transcripts, expected_transcript):
"""
Test that importing a video with different type of transcripts for same language,
creates expected transcript record.
"""
edx_video_id = 'test_edx_video_id'
language_code = 'en'
module_system = DummySystem(load_error_modules=True)
id_generator = Mock()
# Create static directory in import file system and place transcript files inside it.
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
xml_data = "<video edx_video_id='test_edx_video_id'"
# Prepare self.sub transcript data.
if sub_id:
create_file_in_fs(
TRANSCRIPT_FILE_SJSON_DATA,
subs_filename(sub_id, language_code),
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
xml_data += " sub='{sub_id}'".format(
sub_id=sub_id
)
# Prepare self.transcripts transcripts data.
if external_transcripts:
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
external_transcripts['en'],
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
xml_data += " transcripts='{transcripts}'".format(
transcripts=json.dumps(external_transcripts),
)
xml_data += '><video_asset client_video_id="test_client_video_id" duration="111.0">'
# Prepare VAL transcripts data.
if val_transcripts:
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
'{edx_video_id}-{language_code}.srt'.format(
edx_video_id=edx_video_id,
language_code=language_code
),
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
xml_data += val_transcripts
xml_data += '</video_asset></video>'
# Verify edx_video_id is empty before import.
self.assertEqual(self.descriptor.edx_video_id, u'')
video = self.descriptor.from_xml(xml_data, module_system, id_generator)
# Verify edx_video_id is not empty after import.
self.assertNotEqual(video.edx_video_id, u'')
video_data = get_video_info(video.edx_video_id)
self.assertEqual(video_data['status'], 'imported')
# Verify that correct transcripts are imported.
self.assertDictContainsSubset(
expected_transcript,
get_video_transcript(video.edx_video_id, language_code)
)
def test_import_val_data_invalid(self):