diff options
-rw-r--r-- | chrome/test/data/media/csv/testscenario.csv | 1 | ||||
-rw-r--r-- | chrome/test/data/media/html/media_event.html | 42 | ||||
-rw-r--r-- | chrome/test/data/media/html/player.js | 34 | ||||
-rwxr-xr-x | chrome/test/functional/media/media_event_test_base.py | 33 | ||||
-rwxr-xr-x | chrome/test/functional/media/media_test_base.py | 35 | ||||
-rw-r--r-- | chrome/test/functional/media/media_test_env_names.py | 6 | ||||
-rwxr-xr-x | chrome/test/functional/media/media_test_runner.py | 21 |
7 files changed, 143 insertions, 29 deletions
diff --git a/chrome/test/data/media/csv/testscenario.csv b/chrome/test/data/media/csv/testscenario.csv new file mode 100644 index 0000000..9e6363c --- /dev/null +++ b/chrome/test/data/media/csv/testscenario.csv @@ -0,0 +1 @@ +100,pause,0,5000,play,0
\ No newline at end of file diff --git a/chrome/test/data/media/html/media_event.html b/chrome/test/data/media/html/media_event.html index a7e3b24..654669c 100644 --- a/chrome/test/data/media/html/media_event.html +++ b/chrome/test/data/media/html/media_event.html @@ -1,31 +1,39 @@ -<!-- +<!-- This HTML file contains a player div which is used for event testing -(chrome/test/functional/media_event_*.py). +(chrome/test/functional/media_event_*.py). The query string should contain the following information: - tag (required): HTML video/audio tag. + tag (required): HTML video/audio tag. video file (required): video file name. - t (optional): add the "t" parameter to disable the media cache. + t (optional): add the "t" parameter to disable the media cache. + actions (optional): add a list of triples (time, action, action_argument) + delimited by '|'. For example, '3000|seek|5000' means 'at second 3, seek + to second 5'. Possible actions are 'play', 'pause', 'seek', or + 'ratechange'. Time and action_arugment is in milliseconds. 'play' and + 'pause' should have dummy action_argument, which is ignored. -Example: "media_event.html?tag=video&media=foo.webm&t=t" ---> +Example: "media_event.html?tag=video&media=foo.webm&t=t&actions=3000|seek|5000" +--> <html> <body> <div id='player_container'></div> <script type='text/javascript' src='player.js'></script> <script> -var events = ['loadstart', 'ratechange', 'waiting', 'ratechange', - 'durationchange', 'loadedmetadata', 'loadeddata', - 'canplay', 'canplaythrough', 'play', 'timeupdate', - 'pause', 'ended']; +var events = ['abort', 'canplay', 'canplaythrough', 'durationchange', 'emptied', + 'ended', 'error', 'load', 'loadeddata', 'loadedmetadata', + 'loadstart', 'pause', 'play', 'playing', 'progress', + 'ratechange', 'seeked', 'seeking', 'stalled', 'suspend', + 'timeupdate', 'volumechange', 'waiting'] + +var startTime = 0 var table = document.createElement('table'); table.id = 'event'; document.body.appendChild(table); -function incrementCounterForEvent(evt) { - // Convert the string to an integer. - var currentValue = document.getElementById(evt.type).innerHTML - 0; - document.getElementById(evt.type).innerHTML = currentValue + 1; +function recordEventTime(evt) { + // Record the time when an event happens. + var time = new Date().getTime() - startTime + document.getElementById(evt.type).innerHTML += time + ' ' } var player = document.getElementById('player'); @@ -35,17 +43,19 @@ for (var event in events) { var eventNameColumn = document.createElement('td'); eventNameColumn.innerHTML = events[event]; var eventValueColumn = document.createElement('td'); - eventValueColumn.innerHTML = 0; + eventValueColumn.innerHTML = ''; eventValueColumn.id = events[event]; row.appendChild(eventNameColumn); row.appendChild(eventValueColumn); table.appendChild(row) - player.addEventListener(events[event], incrementCounterForEvent, false); + player.addEventListener(events[event], recordEventTime, false); } if (ok) { + startTime = new Date().getTime(); player.play(); } </script> </body> </html> + diff --git a/chrome/test/data/media/html/player.js b/chrome/test/data/media/html/player.js index 064c0ab..8f28f44 100644 --- a/chrome/test/data/media/html/player.js +++ b/chrome/test/data/media/html/player.js @@ -50,6 +50,39 @@ if (tag != 'audio' && tag != 'video') { ok = false; } +function translateCommand(command, arg) { + // Translate command in 'actions' query string into corresponding JavaScript + // code. + if (command == 'seek') { + return 'player.currentTime=' + arg + ';'; + } else if (command == 'ratechange') { + return 'player.playbackRate=' + arg + ';'; + } else if (command == 'play' || command == 'pause') { + return 'player.' + command + '();'; + } else { + return 'ERROR - ' + command + ' is not a valid command.' + } +} + +if (queryString('actions')) { + // Action query string is a list of actions. An action consists of a + // time, action, action_argument triple (delimited by '|'). + // For example, '1000|seek|4000' means 'At second 1, seek to second 4.' + // Or '1000|pause|0|2000|play|0' means 'At second 1, pause the video. + // At second 2, play the video.' + var original_actions = queryString('actions').split('|'); + if ((original_actions.length % 3) != 0) { + // The action list is a list of triples. Otherwise, it fails. + document.title = 'FAIL'; + ok = false; + } + for (i = 0; i < original_actions.length / 3; i++) { + setTimeout(translateCommand(original_actions[3 * i + 1], + original_actions[3 * i + 2]), + parseInt(original_actions[3 * i])); + } +} + var container = document.getElementById('player_container'); container.innerHTML = '<' + tag + ' controls id="player"></' + tag + '>'; player = document.getElementById('player'); @@ -60,5 +93,4 @@ InstallEventHandler('error', InstallEventHandler('playing', 'document.title = "PLAYING"'); InstallEventHandler('ended', 'document.title = "END"'); -// Starts the player. player.src = media_url;
\ No newline at end of file diff --git a/chrome/test/functional/media/media_event_test_base.py b/chrome/test/functional/media/media_event_test_base.py index 6a59c49..18b0d69 100755 --- a/chrome/test/functional/media/media_event_test_base.py +++ b/chrome/test/functional/media/media_event_test_base.py @@ -17,16 +17,27 @@ from media_test_base import MediaTestBase class MediaEventTestBase(MediaTestBase): """Event test base for the HTML5 media tag.""" # This is a list of events to test during media playback. - EVENT_LIST = ['loadstart', 'ratechange', 'waiting', - 'ratechange', 'durationchange', 'loadedmetadata', - 'loadeddata', 'canplay', 'canplaythrough', - 'play', 'timeupdate', 'pause', 'ended'] + EVENT_LIST = ['abort', 'canplay', 'canplaythrough', 'durationchange', + 'emptied', 'ended', 'error', 'load', 'loadeddata', + 'loadedmetadata', 'loadstart', 'pause', 'play', 'playing', + 'progress', 'ratechange', 'seeked', 'seeking', 'stalled', + 'suspend', 'timeupdate', 'volumechange', 'waiting'] # These are event types that are not 1 at the end of video playback. # There are two types of events listed here: # 0: event occurrence is 0. # None: event occurrence is more than 1. + # The following are default values that may be overridden. event_expected_values = {'ratechange': 0, 'pause': 0, + 'suspend': 0, + 'load': 0, + 'abort': 0, + 'error': 0, + 'emptied': 0, + 'stalled': 0, + 'seeking': 0, + 'seeked': 0, + 'volumechange': 0, 'timeupdate': None} def _GetEventLog(self): @@ -38,8 +49,7 @@ class MediaEventTestBase(MediaTestBase): all_event_infos = {} for event_name in self.EVENT_LIST: loc = 'document.getElementById(\'%s\').innerHTML' % event_name - value = self.GetDOMValue(loc).strip() - all_event_infos[event_name] = int(value) + all_event_infos[event_name] = self.GetDOMValue(loc).strip() return all_event_infos def AssertEvent(self, all_event_infos): @@ -52,21 +62,22 @@ class MediaEventTestBase(MediaTestBase): occurrence counts. """ for event_name in self.EVENT_LIST: + event_occurrence = len(all_event_infos[event_name].split()) if event_name in self.event_expected_values: if self.event_expected_values[event_name] is None: self.assertTrue( - all_event_infos[event_name] > 1, + event_occurrence > 1, msg='the number of events should be more than 1 for %s' % event_name) else: self.assertEqual( - all_event_infos[event_name], + event_occurrence, self.event_expected_values[event_name], msg='the number of events is wrong for %s' % event_name) else: # Make sure the value is one. self.assertEqual( - all_event_infos[event_name], 1, + event_occurrence, 1, msg='the number of events should be 1 for %s' % event_name) def PostEachRunProcess(self, run_counter): @@ -80,7 +91,9 @@ class MediaEventTestBase(MediaTestBase): """ MediaTestBase.PostEachRunProcess(self, run_counter) all_event_infos = self._GetEventLog() - self.AssertEvent(all_event_infos) + # TODO(imasaki@chromium.org): adjust events based on actions. + if not self._test_scenarios: + self.AssertEvent(all_event_infos) def GetPlayerHTMLFileName(self): """A method to get the player HTML file name.""" diff --git a/chrome/test/functional/media/media_test_base.py b/chrome/test/functional/media/media_test_base.py index f9cf5b7..bd3a40e 100755 --- a/chrome/test/functional/media/media_test_base.py +++ b/chrome/test/functional/media/media_test_base.py @@ -13,6 +13,7 @@ media_test_runner.py is used for generating these variables (PyAuto does not support direct parameters). """ +import csv import os import time @@ -47,6 +48,7 @@ class MediaTestBase(pyauto.PyUITest): times = [] media_filename = '' media_filename_nickname = '' + _test_scenarios = [] def _GetMediaURLAndParameterString(self, media_filename): """Get media url and parameter string. @@ -97,6 +99,23 @@ class MediaTestBase(pyauto.PyUITest): extra_nickname) return url, parameter_str + def ReadTestScenarioFiles(self, test_scenario_filename): + """Read a test scenario CSV file with actions such as 'play'. + + In the CSV file, each row is a test scenario which consists of one + or more (time, action, action_argument) triples (time and action_argument + are in milliseconds). For example, the following CSV file contains 3 test + scenarios to be tested. + 500, pause, 0 + 1000, pause, 0, 2000, play, 0 + 1000, seek, 0, 2000, ratechange, 2 + """ + test_scenarios = [] + rows = csv.reader(open(test_scenario_filename)) + for row in rows: + test_scenarios.append('|'.join(row)) + return test_scenarios + def ExecuteTest(self): """Test HTML5 Media Tag.""" @@ -111,9 +130,23 @@ class MediaTestBase(pyauto.PyUITest): return self.GetDOMValue('document.title').strip() == 'END' self.PreAllRunsProcess() + test_scenario_filename = os.getenv( + MediaTestEnvNames.TEST_SCENARIO_FILE_ENV_NAME, '') + test_scenario = os.getenv( + MediaTestEnvNames.TEST_SCENARIO_ENV_NAME, '') + if test_scenario: + # Run test with the same action several times. + self._test_scenarios = [test_scenario] * self.number_of_runs + if test_scenario_filename: + self._test_scenarios = self.ReadTestScenarioFiles(test_scenario_filename) + # One run per test scenario. + self.number_of_runs = len(self._test_scenarios) for run_counter in range(self.number_of_runs): self.PreEachRunProcess(run_counter) - self.NavigateToURL(self.url) + url = self.url + if self._test_scenarios: + url += '&actions=' + self.test_scenarios[run_counter] + self.NavigateToURL(url) self.WaitUntil(lambda: _VideoEnded(), self.TIMEOUT) self.PostEachRunProcess(run_counter) diff --git a/chrome/test/functional/media/media_test_env_names.py b/chrome/test/functional/media/media_test_env_names.py index 43b3a24..6667f43 100644 --- a/chrome/test/functional/media/media_test_env_names.py +++ b/chrome/test/functional/media/media_test_env_names.py @@ -49,3 +49,9 @@ class MediaTestEnvNames: # Define the interval for the measurement. MEASURE_INTERVAL_ENV_NAME = 'MEASURE_INTERVALS' + + # Define the test scenario file, which contains all operations during tests. + TEST_SCENARIO_FILE_ENV_NAME = 'TEST_SCENARIO_FILE' + + # Define the test scenario, which contains operations during tests. + TEST_SCENARIO_ENV_NAME = 'TEST_SCENARIO' diff --git a/chrome/test/functional/media/media_test_runner.py b/chrome/test/functional/media/media_test_runner.py index 7348724..1af348f 100755 --- a/chrome/test/functional/media/media_test_runner.py +++ b/chrome/test/functional/media/media_test_runner.py @@ -98,15 +98,30 @@ def main(): default=True, # Currently default is True # since we want to test only 1 combination. help='Run only one parameter combination') + parser.add_option( + '-w', '--test_scenario_input_filename', + dest='test_scenario_input_filename', + default='', help='Test scenario file (CSV form)', metavar='FILE') + parser.add_option( + '-c', '--test_scenario', dest='test_scenario', + default='', help='Test scenario (action triples delimited by \'|\')') parser.add_option('-s', '--suite', dest='suite', help='Suite file') + parser.add_option('-e', '--media_file', dest='media_file', + default='', + help=('Media file to be played using player.html. ', + 'The relative path needs to be specified starting ', + 'from data/html/ directory.')) + options, args = parser.parse_args() if args: parser.print_help() sys.exit(1) test_data_list = [] - if options.input_matrix_filename is None: + if options.media_file: + test_data_list.append(['video', options.media_file, options.media_file]) + elif options.input_matrix_filename is None: file = open(options.input_filename, 'rb') test_data_list = csv.reader(file) # First line contains headers that can be skipped. @@ -151,6 +166,10 @@ def main(): REMOVE_FIRST_RESULT, MediaTestEnvNames.MEASURE_INTERVAL_ENV_NAME: str(options.measure_intervals), + MediaTestEnvNames.TEST_SCENARIO_FILE_ENV_NAME: + options.test_scenario_input_filename, + MediaTestEnvNames.TEST_SCENARIO_ENV_NAME: + options.test_scenario, } envs.update(parent_envs) if options.suite is None and options.test_prog_name is not None: |