diff --git a/common/test/acceptance/tests/test_video_module.py b/common/test/acceptance/tests/test_video_module.py index 63be00c055..8a5dd95e9e 100644 --- a/common/test/acceptance/tests/test_video_module.py +++ b/common/test/acceptance/tests/test_video_module.py @@ -4,6 +4,8 @@ Acceptance tests for Video. """ +import json +import requests from .helpers import UniqueCourseTest from ..pages.lms.video import VideoPage from ..pages.lms.tab_nav import TabNavPage @@ -13,6 +15,8 @@ from ..pages.lms.course_info import CourseInfoPage from ..fixtures.course import CourseFixture, XBlockFixtureDesc VIDEO_SOURCE_PORT = 8777 +YOUTUBE_STUB_PORT = 9080 +YOUTUBE_STUB_URL = 'http://127.0.0.1:{}/'.format(YOUTUBE_STUB_PORT) HTML5_SOURCES = [ 'http://localhost:{0}/gizmo.mp4'.format(VIDEO_SOURCE_PORT), @@ -25,6 +29,13 @@ HTML5_SOURCES_INCORRECT = [ ] +class YouTubeConfigError(Exception): + """ + Error occurred while configuring YouTube Stub Server. + """ + pass + + class VideoBaseTest(UniqueCourseTest): """ Base class for tests of the Video Player @@ -50,6 +61,10 @@ class VideoBaseTest(UniqueCourseTest): self.metadata = None self.assets = [] self.verticals = None + self.youtube_configuration = {} + + # reset youtube stub server + self.addCleanup(self._reset_youtube_stub_server) def navigate_to_video(self): """ Prepare the course and get to the video and render it """ @@ -76,6 +91,9 @@ class VideoBaseTest(UniqueCourseTest): self.course_fixture.add_children(chapter) self.course_fixture.install() + if len(self.youtube_configuration) > 0: + self._configure_youtube_stub_server(self.youtube_configuration) + def _add_course_verticals(self): """ Create XBlockFixtureDesc verticals @@ -126,6 +144,39 @@ class VideoBaseTest(UniqueCourseTest): self._navigate_to_courseware_video() self.video.wait_for_video_class() + def _configure_youtube_stub_server(self, config): + """ + Allow callers to configure the stub server using the /set_config URL. + :param config: Configuration dictionary. + The request should have PUT data, such that: + Each PUT parameter is the configuration key. + Each PUT value is a JSON-encoded string value for the configuration. + :raise YouTubeConfigError: + """ + youtube_stub_config_url = YOUTUBE_STUB_URL + 'set_config' + + config_data = {param: json.dumps(value) for param, value in config.items()} + response = requests.put(youtube_stub_config_url, data=config_data) + + if not response.ok: + raise YouTubeConfigError( + 'YouTube Server Configuration Failed. URL {0}, Configuration Data: {1}, Status was {2}'.format( + youtube_stub_config_url, config, response.status_code)) + + def _reset_youtube_stub_server(self): + """ + Reset YouTube Stub Server Configurations using the /del_config URL. + :raise YouTubeConfigError: + """ + youtube_stub_config_url = YOUTUBE_STUB_URL + 'del_config' + + response = requests.delete(youtube_stub_config_url) + + if not response.ok: + raise YouTubeConfigError( + 'YouTube Server Configuration Failed. URL: {0} Status was {1}'.format( + youtube_stub_config_url, response.status_code)) + def metadata_for_mode(self, player_mode, additional_data=None): """ Create a dictionary for video player configuration according to `player_mode` @@ -337,6 +388,55 @@ class YouTubeVideoTest(VideoBaseTest): # check if video aligned correctly without enabled transcript self.assertTrue(self.video.is_aligned(False)) + def test_video_rendering_with_default_response_time(self): + """ + Scenario: Video is rendered in Youtube mode when the YouTube Server responds quickly + Given the YouTube server response time less than 1.5 seconds + And the course has a Video component in "Youtube_HTML5" mode + Then the video has rendered in "Youtube" mode + """ + # configure youtube server + self.youtube_configuration['time_to_response'] = 0.4 + self.metadata = self.metadata_for_mode('youtube_html5') + + self.navigate_to_video() + + self.assertTrue(self.video.is_video_rendered('youtube')) + + def test_video_rendering_wo_default_response_time(self): + """ + Scenario: Video is rendered in HTML5 when the YouTube Server responds slowly + Given the YouTube server response time is greater than 1.5 seconds + And the course has a Video component in "Youtube_HTML5" mode + Then the video has rendered in "HTML5" mode + """ + # configure youtube server + self.youtube_configuration['time_to_response'] = 2.0 + self.metadata = self.metadata_for_mode('youtube_html5') + + self.navigate_to_video() + + self.assertTrue(self.video.is_video_rendered('html5')) + + def test_video_with_youtube_blocked(self): + """ + Scenario: Video is rendered in HTML5 mode when the YouTube API is blocked + Given the YouTube server response time is greater than 1.5 seconds + And the YouTube API is blocked + And the course has a Video component in "Youtube_HTML5" mode + Then the video has rendered in "HTML5" mode + """ + # configure youtube server + self.youtube_configuration.update({ + 'time_to_response': 2.0, + 'youtube_api_blocked': True, + }) + self.metadata = self.metadata_for_mode('youtube_html5') + + self.navigate_to_video() + + self.assertTrue(self.video.is_video_rendered('html5')) + class YouTubeHtml5VideoTest(VideoBaseTest): """ Test YouTube HTML5 Video Player """ diff --git a/lms/djangoapps/courseware/features/video.feature b/lms/djangoapps/courseware/features/video.feature index 9ba9464a13..ea70857370 100644 --- a/lms/djangoapps/courseware/features/video.feature +++ b/lms/djangoapps/courseware/features/video.feature @@ -9,27 +9,6 @@ Feature: LMS.Video component And all sources are correct # 2 - # Youtube testing - Scenario: Video component is fully rendered in the LMS in Youtube mode with HTML5 sources - Given youtube server is up and response time is 0.4 seconds - And the course has a Video component in "Youtube_HTML5" mode - When the video has rendered in "Youtube" mode - - # 3 - Scenario: Video component is not rendered in the LMS in Youtube mode with HTML5 sources - Given youtube server is up and response time is 2 seconds - And the course has a Video component in "Youtube_HTML5" mode - When the video has rendered in "HTML5" mode - - # 4 - Scenario: Video component is not rendered in the LMS in Youtube mode with HTML5 sources when YouTube API is blocked - Given youtube server is up and response time is 2 seconds - And youtube stub server blocks YouTube API - And the course has a Video component in "Youtube_HTML5" mode - And I wait "3" seconds - Then the video has rendered in "HTML5" mode - - # 5 Scenario: Multiple videos in sequentials all load and work, switching between sequentials Given I am registered for the course "test_course" And it has a video "A" in "Youtube" mode in position "1" of sequential @@ -51,7 +30,7 @@ Feature: LMS.Video component When I open video "A" Then video "A" should start playing at speed "2.0" - # 6 + # 3 Scenario: Video component stores speed correctly when each video is in separate sequence Given I am registered for the course "test_course" And it has a video "A" in "Youtube" mode in position "1" of sequential @@ -73,7 +52,7 @@ Feature: LMS.Video component When I open video "C" Then video "C" should start playing at speed "1.0" - # 7 + # 4 Scenario: Language menu works correctly in Video component Given I am registered for the course "test_course" And I have a "chinese_transcripts.srt" transcript file in assets @@ -88,7 +67,7 @@ Feature: LMS.Video component And I select language with code "en" And I see "Hi, welcome to Edx." text in the captions - # 8 + # 5 Scenario: Download Transcript button works correctly in Video component Given I am registered for the course "test_course" And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets @@ -128,7 +107,7 @@ Feature: LMS.Video component # "1:56" is the duration in the VCR timer before the video plays. # And I see duration "1:56" - # 9 + # 6 Scenario: Verify that each video in each sub-section includes a transcript for non-Youtube countries Given youtube server is up and response time is 2 seconds And I am registered for the course "test_course" @@ -169,7 +148,7 @@ Feature: LMS.Video component # And I click video button "play" # Then I see video slider at "0:10" position - # 10 + # 7 Scenario: End time works for Youtube video Given I am registered for the course "test_course" And it has a video in "Youtube" mode: @@ -179,7 +158,7 @@ Feature: LMS.Video component And I wait "5" seconds Then I see video slider at "0:02" position - # 11 + # 8 Scenario: Youtube video with end-time at 1:00 and the video starts playing at 0:58 Given I am registered for the course "test_course" And it has a video in "Youtube" mode: @@ -191,7 +170,7 @@ Feature: LMS.Video component And I wait "5" seconds Then I see video slider at "1:00" position - # 12 + # 9 Scenario: Start time and end time work together for Youtube video Given I am registered for the course "test_course" And it has a video in "Youtube" mode: @@ -202,7 +181,7 @@ Feature: LMS.Video component And I wait "5" seconds Then I see video slider at "0:12" position - # 13 + # 10 Scenario: Youtube video after pausing at end time video plays to the end from end time Given I am registered for the course "test_course" And it has a video in "Youtube" mode: @@ -217,7 +196,7 @@ Feature: LMS.Video component # The default video length is 00:01:55. Then I see video slider at "1:55" position - # 14 + # 11 Scenario: Youtube video with end-time at 0:32 and start-time at 0:30, the video starts playing from 0:28 Given I am registered for the course "test_course" And it has a video in "Youtube" mode: @@ -229,7 +208,7 @@ Feature: LMS.Video component And I wait "8" seconds Then I see video slider at "0:32" position - # 15 + # 12 Scenario: Youtube video with end-time at 1:00, the video starts playing from 1:52 Given I am registered for the course "test_course" And it has a video in "Youtube" mode: @@ -242,7 +221,7 @@ Feature: LMS.Video component # Video stops at the end. Then I see video slider at "1:55" position - # 16 + # 13 @skip_firefox Scenario: Quality button appears on play Given the course has a Video component in "Youtube" mode @@ -250,7 +229,7 @@ Feature: LMS.Video component And I click video button "play" Then I see video button "quality" is visible - # 17 + # 14 @skip_firefox Scenario: Quality button works correctly Given the course has a Video component in "Youtube" mode