1 # Copyright (c) 2013 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.
11 from telemetry import decorators
12 from telemetry.core import browser_finder
13 from telemetry.core import repeat_options
14 from telemetry.core import util
15 from telemetry.page import page_runner
16 from telemetry.page import cloud_storage
17 from telemetry.page import page_set
18 from telemetry.page import page_test
19 from telemetry.page import test_expectations
22 Disabled = decorators.Disabled
23 Enabled = decorators.Enabled
27 """Base class for a Telemetry test or benchmark.
29 A test packages a PageTest/PageMeasurement and a PageSet together.
35 name = cls.__module__.split('.')[-1]
36 if hasattr(cls, 'tag'):
38 if hasattr(cls, 'page_set'):
39 name += '.' + os.path.basename(os.path.splitext(cls.page_set)[0])
42 def Run(self, options):
43 """Run this test with the given options."""
44 assert hasattr(self, 'test'), 'This test has no "test" attribute.'
45 assert issubclass(self.test, page_test.PageTest), (
46 '"%s" is not a PageTest.' % self.test.__name__)
48 for key, value in self.options.iteritems():
49 setattr(options, key, value)
51 if hasattr(self, '_disabled_strings'):
52 self.test._disabled_strings = self._disabled_strings
53 if hasattr(self, '_enabled_strings'):
54 self.test._enabled_strings = self._enabled_strings
56 options.repeat_options = self._CreateRepeatOptions(options)
57 self.CustomizeBrowserOptions(options)
60 test.__name__ = self.__class__.__name__
61 ps = self.CreatePageSet(options)
62 expectations = self.CreateExpectations(ps)
64 # Ensure the test's default options are set if needed.
65 parser = options.CreateParser()
66 test.AddCommandLineOptions(parser)
67 options.MergeDefaultValues(parser.get_default_values())
69 self._DownloadGeneratedProfileArchive(options)
71 results = page_runner.Run(test, ps, expectations, options)
72 results.PrintSummary()
73 return len(results.failures) + len(results.errors)
75 def _CreateRepeatOptions(self, options):
76 return repeat_options.RepeatOptions(
77 getattr(options, 'page_repeat_secs', None),
78 getattr(options, 'pageset_repeat_secs', None),
79 getattr(options, 'page_repeat_iters', 1),
80 getattr(options, 'pageset_repeat_iters', 1),
83 def _DownloadGeneratedProfileArchive(self, options):
84 """Download and extract profile directory archive if one exists."""
85 archive_name = getattr(self, 'generated_profile_archive', None)
87 # If attribute not specified, nothing to do.
91 # If profile dir specified on command line, nothing to do.
92 if options.browser_options.profile_dir:
93 logging.warning("Profile directory specified on command line: %s, this"
94 "overrides the benchmark's default profile directory.",
95 options.browser_options.profile_dir)
98 # Download profile directory from cloud storage.
99 found_browser = browser_finder.FindBrowser(options)
100 test_data_dir = os.path.join(util.GetChromiumSrcDir(), 'tools', 'perf',
101 'generated_profiles',
102 found_browser.target_os)
103 generated_profile_archive_path = os.path.normpath(
104 os.path.join(test_data_dir, archive_name))
107 cloud_storage.GetIfChanged(generated_profile_archive_path,
108 cloud_storage.PUBLIC_BUCKET)
109 except (cloud_storage.CredentialsError,
110 cloud_storage.PermissionError) as e:
111 if os.path.exists(generated_profile_archive_path):
112 # If the profile directory archive exists, assume the user has their
113 # own local copy simply warn.
114 logging.warning('Could not download Profile archive: %s',
115 generated_profile_archive_path)
117 # If the archive profile directory doesn't exist, this is fatal.
118 logging.error('Can not run without required profile archive: %s. '
119 'If you believe you have credentials, follow the '
120 'instructions below.',
121 generated_profile_archive_path)
125 # Unzip profile directory.
126 extracted_profile_dir_path = (
127 os.path.splitext(generated_profile_archive_path)[0])
128 if not os.path.isfile(generated_profile_archive_path):
129 raise Exception("Profile directory archive not downloaded: ",
130 generated_profile_archive_path)
131 with zipfile.ZipFile(generated_profile_archive_path) as f:
133 f.extractall(os.path.dirname(generated_profile_archive_path))
135 # Cleanup any leftovers from unzipping.
136 if os.path.exists(extracted_profile_dir_path):
137 shutil.rmtree(extracted_profile_dir_path)
138 logging.error("Error extracting profile directory zip file: %s", e)
141 # Run with freshly extracted profile directory.
142 logging.info("Using profile archive directory: %s",
143 extracted_profile_dir_path)
144 options.browser_options.profile_dir = extracted_profile_dir_path
146 def CreatePageSet(self, options): # pylint: disable=W0613
147 """Get the page set this test will run on.
149 By default, it will create a page set from the file at this test's
150 page_set attribute. Override to generate a custom page set.
152 assert hasattr(self, 'page_set'), 'This test has no "page_set" attribute.'
153 return page_set.PageSet.FromFile(
154 os.path.join(util.GetBaseDir(), self.page_set))
156 def CreateExpectations(self, ps): # pylint: disable=W0613
157 """Get the expectations this test will run with.
159 By default, it will create an empty expectations set. Override to generate
162 if hasattr(self, 'expectations'):
163 return self.expectations
165 return test_expectations.TestExpectations()
168 def AddCommandLineOptions(parser):
169 page_runner.AddCommandLineOptions(parser)
172 def AddTestCommandLineOptions(parser):
173 """Override to accept custom command line options."""
176 def CustomizeBrowserOptions(self, options):
177 """Add browser options that are required by this benchmark."""