1 # Copyright 2014 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.
12 from telemetry import decorators
13 from telemetry.core import browser_finder
14 from telemetry.core import command_line
15 from telemetry.core import util
16 from telemetry.page import page_runner
17 from telemetry.page import page_set
18 from telemetry.page import page_test
19 from telemetry.page import test_expectations
20 from telemetry.results import results_options
21 from telemetry.util import cloud_storage
23 Disabled = decorators.Disabled
24 Enabled = decorators.Enabled
27 class BenchmarkMetadata(object):
28 def __init__(self, name):
35 class Benchmark(command_line.Command):
36 """Base class for a Telemetry benchmark.
38 A test packages a PageTest and a PageSet together.
44 name = cls.__module__.split('.')[-1]
45 if hasattr(cls, 'tag'):
47 if hasattr(cls, 'page_set'):
48 name += '.' + cls.page_set.Name()
52 def AddCommandLineArgs(cls, parser):
53 cls.PageTestClass().AddCommandLineArgs(parser)
55 if hasattr(cls, 'AddTestCommandLineArgs'):
56 group = optparse.OptionGroup(parser, '%s test options' % cls.Name())
57 cls.AddTestCommandLineArgs(group)
58 parser.add_option_group(group)
61 def SetArgumentDefaults(cls, parser):
62 cls.PageTestClass().SetArgumentDefaults(parser)
63 parser.set_defaults(**cls.options)
66 def ProcessCommandLineArgs(cls, parser, args):
67 cls.PageTestClass().ProcessCommandLineArgs(parser, args)
69 def CustomizeBrowserOptions(self, options):
70 """Add browser options that are required by this benchmark."""
72 def GetMetadata(self):
73 return BenchmarkMetadata(self.Name())
75 def Run(self, finder_options):
76 """Run this test with the given options."""
77 self.CustomizeBrowserOptions(finder_options.browser_options)
79 pt = self.PageTestClass()()
80 pt.__name__ = self.__class__.__name__
82 if hasattr(self, '_disabled_strings'):
83 pt._disabled_strings = self._disabled_strings
84 if hasattr(self, '_enabled_strings'):
85 pt._enabled_strings = self._enabled_strings
87 ps = self.CreatePageSet(finder_options)
88 expectations = self.CreateExpectations(ps)
90 self._DownloadGeneratedProfileArchive(finder_options)
92 results = results_options.CreateResults(self.GetMetadata(), finder_options)
94 page_runner.Run(pt, ps, expectations, finder_options, results)
95 except page_test.TestNotSupportedOnPlatformFailure as failure:
96 logging.warning(str(failure))
98 results.PrintSummary()
99 return len(results.failures)
101 def _DownloadGeneratedProfileArchive(self, options):
102 """Download and extract profile directory archive if one exists."""
103 archive_name = getattr(self, 'generated_profile_archive', None)
105 # If attribute not specified, nothing to do.
109 # If profile dir specified on command line, nothing to do.
110 if options.browser_options.profile_dir:
111 logging.warning("Profile directory specified on command line: %s, this"
112 "overrides the benchmark's default profile directory.",
113 options.browser_options.profile_dir)
116 # Download profile directory from cloud storage.
117 found_browser = browser_finder.FindBrowser(options)
118 test_data_dir = os.path.join(util.GetChromiumSrcDir(), 'tools', 'perf',
119 'generated_profiles',
120 found_browser.target_os)
121 generated_profile_archive_path = os.path.normpath(
122 os.path.join(test_data_dir, archive_name))
125 cloud_storage.GetIfChanged(generated_profile_archive_path,
126 cloud_storage.PUBLIC_BUCKET)
127 except (cloud_storage.CredentialsError,
128 cloud_storage.PermissionError) as e:
129 if os.path.exists(generated_profile_archive_path):
130 # If the profile directory archive exists, assume the user has their
131 # own local copy simply warn.
132 logging.warning('Could not download Profile archive: %s',
133 generated_profile_archive_path)
135 # If the archive profile directory doesn't exist, this is fatal.
136 logging.error('Can not run without required profile archive: %s. '
137 'If you believe you have credentials, follow the '
138 'instructions below.',
139 generated_profile_archive_path)
140 logging.error(str(e))
143 # Unzip profile directory.
144 extracted_profile_dir_path = (
145 os.path.splitext(generated_profile_archive_path)[0])
146 if not os.path.isfile(generated_profile_archive_path):
147 raise Exception("Profile directory archive not downloaded: ",
148 generated_profile_archive_path)
149 with zipfile.ZipFile(generated_profile_archive_path) as f:
151 f.extractall(os.path.dirname(generated_profile_archive_path))
153 # Cleanup any leftovers from unzipping.
154 if os.path.exists(extracted_profile_dir_path):
155 shutil.rmtree(extracted_profile_dir_path)
156 logging.error("Error extracting profile directory zip file: %s", e)
159 # Run with freshly extracted profile directory.
160 logging.info("Using profile archive directory: %s",
161 extracted_profile_dir_path)
162 options.browser_options.profile_dir = extracted_profile_dir_path
165 def PageTestClass(cls):
166 """Get the PageTest for this Benchmark.
168 If the Benchmark has no PageTest, raises NotImplementedError.
170 if not hasattr(cls, 'test'):
171 raise NotImplementedError('This test has no "test" attribute.')
172 if not issubclass(cls.test, page_test.PageTest):
173 raise TypeError('"%s" is not a PageTest.' % cls.test.__name__)
177 def PageSetClass(cls):
178 """Get the PageSet for this Benchmark.
180 If the Benchmark has no PageSet, raises NotImplementedError.
182 if not hasattr(cls, 'page_set'):
183 raise NotImplementedError('This test has no "page_set" attribute.')
184 if not issubclass(cls.page_set, page_set.PageSet):
185 raise TypeError('"%s" is not a PageSet.' % cls.page_set.__name__)
189 def CreatePageSet(cls, options): # pylint: disable=W0613
190 """Get the page set this test will run on.
192 By default, it will create a page set from the file at this test's
193 page_set attribute. Override to generate a custom page set.
195 return cls.PageSetClass()()
198 def CreateExpectations(cls, ps): # pylint: disable=W0613
199 """Get the expectations this test will run with.
201 By default, it will create an empty expectations set. Override to generate
204 return test_expectations.TestExpectations()
207 def AddCommandLineArgs(parser):
208 page_runner.AddCommandLineArgs(parser)
211 def ProcessCommandLineArgs(parser, args):
212 page_runner.ProcessCommandLineArgs(parser, args)