Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: tools/telemetry/telemetry/page/page_runner.py

Issue 733303003: [Telemetry] Introduce shared_user_story_state for real. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 import logging
6 import optparse
7 import os
8 import random
9 import sys
10 import time
11
12 from telemetry import decorators
13 from telemetry.core import exceptions
14 from telemetry.core import util
15 from telemetry.core import wpr_modes
16 from telemetry.page import shared_page_state
17 from telemetry.page import page_test
18 from telemetry.page.actions import page_action
19 from telemetry.results import results_options
20 from telemetry.user_story import user_story_filter
21 from telemetry.util import cloud_storage
22 from telemetry.util import exception_formatter
23 from telemetry.value import failure
24 from telemetry.value import skip
25
26
27 def AddCommandLineArgs(parser):
28 user_story_filter.UserStoryFilter.AddCommandLineArgs(parser)
29 results_options.AddResultsOptions(parser)
30
31 # Page set options
32 group = optparse.OptionGroup(parser, 'Page set ordering and repeat options')
33 group.add_option('--pageset-shuffle', action='store_true',
34 dest='pageset_shuffle',
35 help='Shuffle the order of pages within a pageset.')
36 group.add_option('--pageset-shuffle-order-file',
37 dest='pageset_shuffle_order_file', default=None,
38 help='Filename of an output of a previously run test on the current '
39 'pageset. The tests will run in the same order again, overriding '
40 'what is specified by --page-repeat and --pageset-repeat.')
41 group.add_option('--page-repeat', default=1, type='int',
42 help='Number of times to repeat each individual page '
43 'before proceeding with the next page in the pageset.')
44 group.add_option('--pageset-repeat', default=1, type='int',
45 help='Number of times to repeat the entire pageset.')
46 group.add_option('--max-failures', default=None, type='int',
47 help='Maximum number of test failures before aborting '
48 'the run. Defaults to the number specified by the '
49 'PageTest.')
50 parser.add_option_group(group)
51
52 # WPR options
53 group = optparse.OptionGroup(parser, 'Web Page Replay options')
54 group.add_option('--use-live-sites',
55 dest='use_live_sites', action='store_true',
56 help='Run against live sites and ignore the Web Page Replay archives.')
57 parser.add_option_group(group)
58
59 parser.add_option('-d', '--also-run-disabled-tests',
60 dest='run_disabled_tests',
61 action='store_true', default=False,
62 help='Ignore @Disabled and @Enabled restrictions.')
63
64 def ProcessCommandLineArgs(parser, args):
65 user_story_filter.UserStoryFilter.ProcessCommandLineArgs(parser, args)
66 results_options.ProcessCommandLineArgs(parser, args)
67
68 # Page set options
69 if args.pageset_shuffle_order_file and not args.pageset_shuffle:
70 parser.error('--pageset-shuffle-order-file requires --pageset-shuffle.')
71
72 if args.page_repeat < 1:
73 parser.error('--page-repeat must be a positive integer.')
74 if args.pageset_repeat < 1:
75 parser.error('--pageset-repeat must be a positive integer.')
76
77
78 def _RunPageAndHandleExceptionIfNeeded(test, page_set, expectations,
79 page, results, state):
80 expectation = None
81 def ProcessError():
82 if expectation == 'fail':
83 msg = 'Expected exception while running %s' % page.url
84 exception_formatter.PrintFormattedException(msg=msg)
85 else:
86 msg = 'Exception while running %s' % page.url
87 results.AddValue(failure.FailureValue(page, sys.exc_info()))
88
89 try:
90 state.WillRunPage(page, page_set)
91 expectation, skip_value = state.GetPageExpectationAndSkipValue(expectations)
92 if expectation == 'skip':
93 assert skip_value
94 results.AddValue(skip_value)
95 return
96 state.RunPage(results)
97 except page_test.TestNotSupportedOnPlatformFailure:
98 raise
99 except (page_test.Failure, util.TimeoutException, exceptions.LoginException,
100 exceptions.ProfilingException):
101 ProcessError()
102 except exceptions.AppCrashException:
103 ProcessError()
104 state.TearDown(results)
105 if test.is_multi_tab_test:
106 logging.error('Aborting multi-tab test after browser or tab crashed at '
107 'page %s' % page.url)
108 test.RequestExit()
109 return
110 except page_action.PageActionNotSupported as e:
111 results.AddValue(skip.SkipValue(page, 'Unsupported page action: %s' % e))
112 except Exception:
113 exception_formatter.PrintFormattedException(
114 msg='Unhandled exception while running %s' % page.url)
115 results.AddValue(failure.FailureValue(page, sys.exc_info()))
116 else:
117 if expectation == 'fail':
118 logging.warning('%s was expected to fail, but passed.\n', page.url)
119 finally:
120 state.DidRunPage(results)
121
122
123 @decorators.Cache
124 def _UpdatePageSetArchivesIfChanged(page_set):
125 # Scan every serving directory for .sha1 files
126 # and download them from Cloud Storage. Assume all data is public.
127 all_serving_dirs = page_set.serving_dirs.copy()
128 # Add individual page dirs to all serving dirs.
129 for page in page_set:
130 if page.is_file:
131 all_serving_dirs.add(page.serving_dir)
132 # Scan all serving dirs.
133 for serving_dir in all_serving_dirs:
134 if os.path.splitdrive(serving_dir)[1] == '/':
135 raise ValueError('Trying to serve root directory from HTTP server.')
136 for dirpath, _, filenames in os.walk(serving_dir):
137 for filename in filenames:
138 path, extension = os.path.splitext(
139 os.path.join(dirpath, filename))
140 if extension != '.sha1':
141 continue
142 cloud_storage.GetIfChanged(path, page_set.bucket)
143
144
145 def Run(test, page_set, expectations, finder_options, results):
146 """Runs a given test against a given page_set with the given options."""
147 test.ValidatePageSet(page_set)
148
149 # Reorder page set based on options.
150 pages = _ShuffleAndFilterPageSet(page_set, finder_options)
151
152 if not finder_options.use_live_sites:
153 if finder_options.browser_options.wpr_mode != wpr_modes.WPR_RECORD:
154 _UpdatePageSetArchivesIfChanged(page_set)
155 pages = _CheckArchives(page_set, pages, results)
156
157 for page in list(pages):
158 if not test.CanRunForPage(page):
159 results.WillRunPage(page)
160 logging.debug('Skipping test: it cannot run for %s', page.url)
161 results.AddValue(skip.SkipValue(page, 'Test cannot run'))
162 results.DidRunPage(page)
163 pages.remove(page)
164
165 if not pages:
166 return
167
168 state = shared_page_state.SharedPageState(test, finder_options, page_set)
169 pages_with_discarded_first_result = set()
170 max_failures = finder_options.max_failures # command-line gets priority
171 if max_failures is None:
172 max_failures = test.max_failures # may be None
173
174 try:
175 test.WillRunTest(finder_options)
176 for _ in xrange(finder_options.pageset_repeat):
177 for page in pages:
178 if test.IsExiting():
179 break
180 for _ in xrange(finder_options.page_repeat):
181 results.WillRunPage(page)
182 try:
183 _WaitForThermalThrottlingIfNeeded(state.platform)
184 _RunPageAndHandleExceptionIfNeeded(
185 test, page_set, expectations, page, results, state)
186 except Exception:
187 # Tear down & restart the state for unhandled exceptions thrown by
188 # _RunPageAndHandleExceptionIfNeeded.
189 results.AddValue(failure.FailureValue(page, sys.exc_info()))
190 state.TearDown(results)
191 state = shared_page_state.SharedPageState(
192 test, finder_options, page_set)
193 finally:
194 _CheckThermalThrottling(state.platform)
195 discard_run = (test.discard_first_result and
196 page not in pages_with_discarded_first_result)
197 if discard_run:
198 pages_with_discarded_first_result.add(page)
199 results.DidRunPage(page, discard_run=discard_run)
200 if max_failures is not None and len(results.failures) > max_failures:
201 logging.error('Too many failures. Aborting.')
202 test.RequestExit()
203 finally:
204 state.TearDown(results)
205
206
207 def _ShuffleAndFilterPageSet(page_set, finder_options):
208 if finder_options.pageset_shuffle_order_file:
209 return page_set.ReorderPageSet(finder_options.pageset_shuffle_order_file)
210 pages = [page for page in page_set.pages[:]
211 if user_story_filter.UserStoryFilter.IsSelected(page)]
212 if finder_options.pageset_shuffle:
213 random.shuffle(pages)
214 return pages
215
216
217 def _CheckArchives(page_set, pages, results):
218 """Returns a subset of pages that are local or have WPR archives.
219
220 Logs warnings if any are missing.
221 """
222 # Warn of any problems with the entire page set.
223 if any(not p.is_local for p in pages):
224 if not page_set.archive_data_file:
225 logging.warning('The page set is missing an "archive_data_file" '
226 'property. Skipping any live sites. To include them, '
227 'pass the flag --use-live-sites.')
228 if not page_set.wpr_archive_info:
229 logging.warning('The archive info file is missing. '
230 'To fix this, either add svn-internal to your '
231 '.gclient using http://goto/read-src-internal, '
232 'or create a new archive using record_wpr.')
233
234 # Warn of any problems with individual pages and return valid pages.
235 pages_missing_archive_path = []
236 pages_missing_archive_data = []
237 valid_pages = []
238 for page in pages:
239 if not page.is_local and not page.archive_path:
240 pages_missing_archive_path.append(page)
241 elif not page.is_local and not os.path.isfile(page.archive_path):
242 pages_missing_archive_data.append(page)
243 else:
244 valid_pages.append(page)
245 if pages_missing_archive_path:
246 logging.warning('The page set archives for some pages do not exist. '
247 'Skipping those pages. To fix this, record those pages '
248 'using record_wpr. To ignore this warning and run '
249 'against live sites, pass the flag --use-live-sites.')
250 if pages_missing_archive_data:
251 logging.warning('The page set archives for some pages are missing. '
252 'Someone forgot to check them in, or they were deleted. '
253 'Skipping those pages. To fix this, record those pages '
254 'using record_wpr. To ignore this warning and run '
255 'against live sites, pass the flag --use-live-sites.')
256 for page in pages_missing_archive_path + pages_missing_archive_data:
257 results.WillRunPage(page)
258 results.AddValue(failure.FailureValue.FromMessage(
259 page, 'Page set archive doesn\'t exist.'))
260 results.DidRunPage(page)
261 return valid_pages
262
263
264 def _WaitForThermalThrottlingIfNeeded(platform):
265 if not platform.CanMonitorThermalThrottling():
266 return
267 thermal_throttling_retry = 0
268 while (platform.IsThermallyThrottled() and
269 thermal_throttling_retry < 3):
270 logging.warning('Thermally throttled, waiting (%d)...',
271 thermal_throttling_retry)
272 thermal_throttling_retry += 1
273 time.sleep(thermal_throttling_retry * 2)
274
275 if thermal_throttling_retry and platform.IsThermallyThrottled():
276 logging.warning('Device is thermally throttled before running '
277 'performance tests, results will vary.')
278
279
280 def _CheckThermalThrottling(platform):
281 if not platform.CanMonitorThermalThrottling():
282 return
283 if platform.HasBeenThermallyThrottled():
284 logging.warning('Device has been thermally throttled during '
285 'performance tests, results will vary.')
OLDNEW
« no previous file with comments | « tools/telemetry/telemetry/page/__init__.py ('k') | tools/telemetry/telemetry/page/page_runner_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698