diff --git a/common/djangoapps/terrain/stubs/youtube.py b/common/djangoapps/terrain/stubs/youtube.py index 0f4f7a894d..83e997f1e2 100644 --- a/common/djangoapps/terrain/stubs/youtube.py +++ b/common/djangoapps/terrain/stubs/youtube.py @@ -90,7 +90,10 @@ class StubYouTubeHandler(StubHttpRequestHandler): params = urlparse(self.path) youtube_id = params.path.split('/').pop() - self._send_video_response(youtube_id, "I'm youtube.") + if self.server.config.get('youtube_api_private_video'): + self._send_private_video_response(youtube_id, "I'm youtube private video.") + else: + self._send_video_response(youtube_id, "I'm youtube.") elif 'get_youtube_api' in self.path: if self.server.config.get('youtube_api_blocked'): @@ -130,6 +133,30 @@ class StubYouTubeHandler(StubHttpRequestHandler): self.send_response(200, content=response, headers={'Content-type': 'text/html'}) self.log_message("Youtube: sent response {}".format(message)) + def _send_private_video_response(self, message): + """ + Send private video error message back to the client for video player requests. + """ + # Construct the response content + callback = self.get_params['callback'] + data = OrderedDict({ + "error": OrderedDict({ + "code": 403, + "errors": [ + { + "code": "ServiceForbiddenException", + "domain": "GData", + "internalReason": "Private video" + } + ], + "message": message, + }) + }) + response = "{cb}({data})".format(cb=callback, data=json.dumps(data)) + + self.send_response(200, content=response, headers={'Content-type': 'text/html'}) + self.log_message("Youtube: sent response {}".format(message)) + class StubYouTubeService(StubHttpService): """ diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js index 68f2a03cc0..05654966f5 100644 --- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js +++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js @@ -756,7 +756,7 @@ function (VideoPlayer, VideoStorage, i18n) { try { return this.metadata[this.youtubeId()].duration; } catch (err) { - return this.metadata[this.youtubeId('1.0')].duration; + return _.result(this.metadata[this.youtubeId('1.0')], 'duration') || 0; } } diff --git a/common/test/acceptance/pages/studio/video/video.py b/common/test/acceptance/pages/studio/video/video.py index 75e8da1427..36effb74de 100644 --- a/common/test/acceptance/pages/studio/video/video.py +++ b/common/test/acceptance/pages/studio/video/video.py @@ -118,7 +118,19 @@ class VideoComponentPage(VideoPage): self._wait_for(lambda: self.q(css=CLASS_SELECTORS['video_init']).present, 'Video Player Initialized') self._wait_for(lambda: not self.q(css=CLASS_SELECTORS['video_spinner']).visible, 'Video Buffering Completed') - self._wait_for(lambda: self.q(css=CLASS_SELECTORS['video_controls']).visible, 'Player Controls are Visible') + self._wait_for(self.is_controls_visible, 'Player Controls are Visible') + + @wait_for_js + def is_controls_visible(self): + """ + Get current visibility sate of all video controls. + + Returns: + bool: True means video controls are visible for all videos, False means video controls are not visible + for one or more videos + + """ + return self.q(css=CLASS_SELECTORS['video_controls']).visible def click_button(self, button_name, index=0): """ diff --git a/common/test/acceptance/tests/video/test_studio_video_module.py b/common/test/acceptance/tests/video/test_studio_video_module.py index 34835c6109..7f8da4afad 100644 --- a/common/test/acceptance/tests/video/test_studio_video_module.py +++ b/common/test/acceptance/tests/video/test_studio_video_module.py @@ -95,12 +95,14 @@ class CMSVideoBaseTest(UniqueCourseTest): self._install_course_fixture() self._navigate_to_course_unit_page() - def edit_component(self): + def edit_component(self, xblock_index=1): """ Open component Edit Dialog for first component on page. + + Arguments: + xblock_index: number starting from 1 (0th entry is the unit page itself) """ - # The 0th entry is the unit page itself. - self.unit_page.xblocks[1].edit() + self.unit_page.xblocks[xblock_index].edit() def open_advanced_tab(self): """ @@ -225,6 +227,27 @@ class CMSVideoTest(CMSVideoBaseTest): self.assertFalse(self.video.is_captions_visible()) + def test_video_controls_shown_correctly(self): + """ + Scenario: Video controls for all videos show correctly + Given I have created two Video components + And first is private video + When I reload the page + Then video controls for all videos are visible + """ + self._create_course_unit(youtube_stub_config={'youtube_api_private_video': True}) + self.video.create_video() + + # change id of first default video + self.edit_component(1) + self.open_advanced_tab() + self.video.set_field_value('YouTube ID', 'sampleid123') + self.save_unit_settings() + + # again open unit page and check that video controls show for both videos + self._navigate_to_course_unit_page() + self.assertTrue(self.video.is_controls_visible()) + def test_captions_shown_correctly(self): """ Scenario: Captions are shown correctly