page_test_runner.py revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4import os 5import sys 6 7from telemetry import test as test_module 8from telemetry.core import browser_options 9from telemetry.core import discover 10from telemetry.core import profile_types 11from telemetry.page import page_test as page_test_module 12from telemetry.page import page_runner 13from telemetry.page import page_set 14 15def Main(base_dir, page_set_filenames): 16 """Turns a PageTest into a command-line program. 17 18 Args: 19 base_dir: Path to directory containing tests and ProfileCreators. 20 """ 21 runner = PageTestRunner() 22 sys.exit(runner.Run(base_dir, page_set_filenames)) 23 24class PageTestRunner(object): 25 def __init__(self): 26 self._parser = None 27 self._options = None 28 self._args = None 29 30 @property 31 def test_class(self): 32 return page_test_module.PageTest 33 34 @property 35 def test_class_name(self): 36 return 'test' 37 38 def Run(self, base_dir, page_set_filenames): 39 test, ps = self.ParseCommandLine(sys.argv, base_dir, page_set_filenames) 40 results = page_runner.Run(test, ps, self._options) 41 results.PrintSummary() 42 return min(255, len(results.failures + results.errors)) 43 44 def FindTestConstructors(self, base_dir): 45 # Look for both Tests and PageTests, but Tests get priority, because 46 test_constructors = discover.DiscoverClasses( 47 base_dir, base_dir, self.test_class) 48 test_constructors.update(discover.DiscoverClasses( 49 base_dir, base_dir, test_module.Test, index_by_class_name=True)) 50 return test_constructors 51 52 def FindTestName(self, test_constructors, args): 53 """Find the test name in an arbitrary argument list. 54 55 We can't use the optparse parser, because the test may add its own 56 command-line options. If the user passed in any of those, the 57 optparse parsing will fail. 58 59 Returns: 60 test_name or None 61 """ 62 test_name = None 63 for arg in [self.GetModernizedTestName(a) for a in args]: 64 if arg in test_constructors: 65 test_name = arg 66 67 return test_name 68 69 def GetModernizedTestName(self, arg): 70 """Sometimes tests change names but buildbots keep calling the old name. 71 72 If arg matches an old test name, return the new test name instead. 73 Otherwise, return the arg. 74 """ 75 return arg 76 77 def GetPageSet(self, test, page_set_filenames): 78 ps = test.CreatePageSet(self._args, self._options) 79 if ps: 80 return ps 81 82 if len(self._args) < 2: 83 page_set_list = ',\n'.join( 84 sorted([os.path.relpath(f) for f in page_set_filenames])) 85 self.PrintParseError( 86 'No page set, file, or URL specified.\n' 87 'Available page sets:\n' 88 '%s' % page_set_list) 89 90 page_set_arg = self._args[1] 91 92 # We've been given a URL. Create a page set with just that URL. 93 if (page_set_arg.startswith('http://') or 94 page_set_arg.startswith('https://')): 95 self._options.allow_live_sites = True 96 return page_set.PageSet.FromDict({ 97 'pages': [{'url': page_set_arg}] 98 }, os.path.dirname(__file__)) 99 100 # We've been given a page set JSON. Load it. 101 if page_set_arg.endswith('.json'): 102 return page_set.PageSet.FromFile(page_set_arg) 103 104 # We've been given a file or directory. Create a page set containing it. 105 if os.path.exists(page_set_arg): 106 page_set_dict = {'pages': []} 107 108 def _AddFile(file_path): 109 page_set_dict['pages'].append({'url': 'file://' + file_path}) 110 111 def _AddDir(dir_path): 112 for path in os.listdir(dir_path): 113 path = os.path.join(dir_path, path) 114 _AddPath(path) 115 116 def _AddPath(path): 117 if os.path.isdir(path): 118 _AddDir(path) 119 else: 120 _AddFile(path) 121 122 _AddPath(page_set_arg) 123 return page_set.PageSet.FromDict(page_set_dict, os.getcwd() + os.sep) 124 125 raise Exception('Did not understand "%s". Pass a page set, file or URL.' % 126 page_set_arg) 127 128 def ParseCommandLine(self, args, base_dir, page_set_filenames): 129 # Need to collect profile creators before creating command line parser. 130 profile_types.FindProfileCreators(base_dir, base_dir) 131 132 self._options = browser_options.BrowserOptions() 133 self._parser = self._options.CreateParser( 134 '%%prog [options] %s page_set' % self.test_class_name) 135 136 test_constructors = self.FindTestConstructors(base_dir) 137 test_name = self.FindTestName(test_constructors, args) 138 test = None 139 if test_name: 140 test = test_constructors[test_name]() 141 if isinstance(test, test_module.Test): 142 page_test = test.test() 143 else: 144 page_test = test 145 page_test.AddOutputOptions(self._parser) 146 page_test.AddCommandLineOptions(self._parser) 147 page_runner.AddCommandLineOptions(self._parser) 148 149 _, self._args = self._parser.parse_args() 150 151 if len(self._args) < 1: 152 error_message = 'No %s specified.\nAvailable %ss:\n' % ( 153 self.test_class_name, self.test_class_name) 154 test_list_string = ',\n'.join(sorted(test_constructors.keys())) 155 self.PrintParseError(error_message + test_list_string) 156 157 if not test: 158 error_message = 'No %s named %s.\nAvailable %ss:\n' % ( 159 self.test_class_name, self._args[0], self.test_class_name) 160 test_list_string = ',\n'.join(sorted(test_constructors.keys())) 161 self.PrintParseError(error_message + test_list_string) 162 163 if isinstance(test, test_module.Test): 164 ps = test.CreatePageSet(self._options) 165 else: 166 ps = self.GetPageSet(test, page_set_filenames) 167 168 if len(self._args) > 2: 169 self.PrintParseError('Too many arguments.') 170 171 return page_test, ps 172 173 def PrintParseError(self, message): 174 self._parser.error(message) 175