Import video transcripts - EDUCATOR-2173
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)),
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user