Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cms/envs/bok_choy.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,9 @@

# Unfortunately, we need to use debug mode to serve staticfiles
DEBUG = True

# Point the URL used to test YouTube availability to our stub YouTube server
YOUTUBE_PORT = 9080
YOUTUBE['API'] = "127.0.0.1:{0}/get_youtube_api/".format(YOUTUBE_PORT)
YOUTUBE['TEST_URL'] = "127.0.0.1:{0}/test_youtube/".format(YOUTUBE_PORT)
YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YOUTUBE_PORT)
11 changes: 11 additions & 0 deletions common/djangoapps/terrain/stubs/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ def path_only(self):
else:
return path

def do_DELETE(self): # pylint: disable=C0103
"""
Allow callers to delete all the server configurations using the /del_config URL.
"""
if self.path == "/del_config" or self.path == "/del_config/":
self.server.config = dict()
self.log_message("Reset Server Configuration.")
self.send_response(200)
else:
self.send_response(404)

def do_PUT(self):
"""
Allow callers to configure the stub server using the /set_config URL.
Expand Down
4 changes: 4 additions & 0 deletions common/djangoapps/terrain/stubs/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import sys
import time
import requests
import logging
from .comments import StubCommentsService
from .xqueue import StubXQueueService
Expand Down Expand Up @@ -87,6 +88,9 @@ def main():
print "Starting stub service '{0}' on port {1}...".format(service_name, port_num)

server = SERVICES[service_name](port_num=port_num)
if service_name == 'youtube':
config_dict['youtube_api_response'] = requests.get('http://www.youtube.com/iframe_api')

server.config.update(config_dict)

try:
Expand Down
20 changes: 20 additions & 0 deletions common/djangoapps/terrain/stubs/tests/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def setUp(self):
self.server = StubHttpService()
self.addCleanup(self.server.shutdown)
self.url = "http://127.0.0.1:{0}/set_config".format(self.server.port)
self.reset_config_url = "http://127.0.0.1:{0}/del_config".format(self.server.port)

def test_configure(self):
"""
Expand Down Expand Up @@ -63,6 +64,25 @@ def test_unknown_path(self):
)
self.assertEqual(response.status_code, 404)

def test_reset_configuration(self):
# JSON-encode parameter
post_params = {'test_reset': json.dumps('This is a reset config test')}
requests.put(self.url, data=post_params)

# ensure that there is some data in server config dict
self.assertEqual(self.server.config.get('test_reset'), 'This is a reset config test')

# reset server configuration
response = requests.delete(self.reset_config_url)
self.assertEqual(response.status_code, 200)

# ensure that server config dict is empty after successful reset
self.assertEqual(self.server.config, {})

def test_reset_config_unknown_path(self):
response = requests.delete("http://127.0.0.1:{0}/invalid_url".format(self.server.port))
self.assertEqual(response.status_code, 404)


class RequireRequestHandler(StubHttpRequestHandler):
@require_params('GET', 'test_param')
Expand Down
14 changes: 14 additions & 0 deletions common/djangoapps/terrain/stubs/tests/test_youtube_stub.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,17 @@ def test_transcript_url_not_equal(self):
def test_transcript_not_found(self):
response = requests.get(self.url + 'test_transcripts_youtube/some_id')
self.assertEqual(404, response.status_code)

def test_reset_configuration(self):

reset_config_url = self.url + 'del_config'

# add some configuration data
self.server.config['test_reset'] = 'This is a reset config test'

# reset server configuration
response = requests.delete(reset_config_url)
self.assertEqual(response.status_code, 200)

# ensure that server config dict is set to initial values after successful reset
self.assertTrue('youtube_api_response' in self.server.config)
12 changes: 12 additions & 0 deletions common/djangoapps/terrain/stubs/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ class StubYouTubeHandler(StubHttpRequestHandler):
# Default number of seconds to delay the response to simulate network latency.
DEFAULT_DELAY_SEC = 0.5

def do_DELETE(self): # pylint: disable=C0103
"""
Allow callers to delete all the server configurations using the /del_config URL.
"""
if self.path == "/del_config" or self.path == "/del_config/":
self.server.config = dict()
self.server.config['youtube_api_response'] = requests.get('http://www.youtube.com/iframe_api')
self.log_message("Reset Server Configuration.")
self.send_response(200)
else:
self.send_response(404)

def do_GET(self):
"""
Handle a GET request from the client and sends response back.
Expand Down
101 changes: 101 additions & 0 deletions common/test/acceptance/tests/test_video_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
Acceptance tests for Video.
"""

import time
import json
import requests
from .helpers import UniqueCourseTest
from ..pages.lms.video import VideoPage
from ..pages.lms.tab_nav import TabNavPage
Expand All @@ -13,6 +16,8 @@
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),
Expand All @@ -25,6 +30,13 @@
]


class YouTubeConfigError(Exception):
"""
Error occurred while configuring YouTube Stub Server.
"""
pass


class VideoBaseTest(UniqueCourseTest):
"""
Base class for tests of the Video Player
Expand All @@ -50,6 +62,10 @@ def setUp(self):
self.metadata = None
self.assets = []
self.verticals = None
self.youtube_configuraton = {}

# 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 """
Expand All @@ -76,6 +92,9 @@ def _install_course_fixture(self):
self.course_fixture.add_children(chapter)
self.course_fixture.install()

if self.youtube_configuraton:
self._configure_youtube_stub_server()

def _add_course_verticals(self):
"""
Create XBlockFixtureDesc verticals
Expand Down Expand Up @@ -126,6 +145,38 @@ def _navigate_to_courseware_video_no_render(self):
self._navigate_to_courseware_video()
self.video.wait_for_video_class()

def _configure_youtube_stub_server(self):
"""
Allow callers to configure the stub server using the /set_config URL.
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 self.youtube_configuraton.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, self.youtube_configuraton, 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`
Expand Down Expand Up @@ -337,6 +388,56 @@ def test_fullscreen_video_alignment_on_transcript_toggle(self):
# check if video aligned correctly without enabled transcript
self.assertTrue(self.video.is_aligned(False))

def test_video_rendered_with_html5_sources(self):
"""
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
Then the video has rendered in "Youtube" mode
"""
# configure youtube server
self.youtube_configuraton['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_not_rendered_with_html5_sources(self):
"""
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
Then the video has rendered in "HTML5" mode
"""
# configure youtube server
self.youtube_configuraton['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_api_blocked(self):
"""
Scenario: Video 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 so that video module completely switch to HTML5
Then the video has rendered in "HTML5" mode
"""
# configure youtube server
self.youtube_configuraton['time_to_response'] = 2.0
self.youtube_configuraton['youtube_api_blocked'] = True
self.metadata = self.metadata_for_mode('youtube_html5')

self.navigate_to_video()

time.sleep(3.0)

self.assertTrue(self.video.is_video_rendered('html5'))


class YouTubeHtml5VideoTest(VideoBaseTest):
""" Test YouTube HTML5 Video Player """
Expand Down
2 changes: 1 addition & 1 deletion lms/envs/acceptance.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,6 @@ def seed():
}

# Point the URL used to test YouTube availability to our stub YouTube server
YOUTUBE['API'] = 'youtube.com/iframe_api'
YOUTUBE['API'] = "127.0.0.1:{0}/get_youtube_api/".format(YOUTUBE_PORT)
YOUTUBE['TEST_URL'] = "127.0.0.1:{0}/test_youtube/".format(YOUTUBE_PORT)
YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YOUTUBE_PORT)
7 changes: 7 additions & 0 deletions lms/envs/bok_choy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
from path import path


CONFIG_ROOT = path(__file__).abspath().dirname() # pylint: disable=E1120
TEST_ROOT = CONFIG_ROOT.dirname().dirname() / "test_root"

Expand Down Expand Up @@ -60,3 +61,9 @@

# Unfortunately, we need to use debug mode to serve staticfiles
DEBUG = True

# Point the URL used to test YouTube availability to our stub YouTube server
YOUTUBE_PORT = 9080
YOUTUBE['API'] = "127.0.0.1:{0}/get_youtube_api/".format(YOUTUBE_PORT)
YOUTUBE['TEST_URL'] = "127.0.0.1:{0}/test_youtube/".format(YOUTUBE_PORT)
YOUTUBE['TEXT_API']['url'] = "127.0.0.1:{0}/test_transcripts_youtube/".format(YOUTUBE_PORT)
7 changes: 7 additions & 0 deletions rakelib/bok_choy.rake
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,14 @@ BOK_CHOY_STUBS = {
:port => 8777,
:log => File.join(BOK_CHOY_LOG_DIR, "bok_choy_video_sources.log"),
:config => "root_dir=#{VIDEO_SOURCE_DIR}"
},

:youtube => {

:port => 9080,
:log => File.join(BOK_CHOY_LOG_DIR, "bok_choy_youtube.log")
}

}

# For the time being, stubs are used by both the bok-choy and lettuce acceptance tests
Expand Down