cc: Make a FakeResourceProvider and use it in tests to construct.
[chromium-blink-merge.git] / tools / telemetry / telemetry / record_wpr.py
blob0899a3d7a8c2620fac5a7e8246c3dbc9ccc479fc
1 # Copyright 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.
5 import argparse
6 import logging
7 import sys
9 from telemetry import benchmark
10 from telemetry.core import browser_options
11 from telemetry.core import discover
12 from telemetry.core import util
13 from telemetry.core import wpr_modes
14 from telemetry.internal import story_runner
15 from telemetry.page import page_set
16 from telemetry.page import page_test
17 from telemetry.page import test_expectations
18 from telemetry.results import results_options
21 class RecorderPageTest(page_test.PageTest):
22 def __init__(self):
23 super(RecorderPageTest, self).__init__()
24 self.page_test = None
26 def CustomizeBrowserOptions(self, options):
27 if self.page_test:
28 self.page_test.CustomizeBrowserOptions(options)
30 def WillStartBrowser(self, browser):
31 if self.page_test:
32 self.page_test.WillStartBrowser(browser)
34 def DidStartBrowser(self, browser):
35 if self.page_test:
36 self.page_test.DidStartBrowser(browser)
38 def WillNavigateToPage(self, page, tab):
39 """Override to ensure all resources are fetched from network."""
40 tab.ClearCache(force=False)
41 if self.page_test:
42 self.page_test.WillNavigateToPage(page, tab)
44 def DidNavigateToPage(self, page, tab):
45 if self.page_test:
46 self.page_test.DidNavigateToPage(page, tab)
47 tab.WaitForDocumentReadyStateToBeComplete()
48 util.WaitFor(tab.HasReachedQuiescence, 30)
50 def CleanUpAfterPage(self, page, tab):
51 if self.page_test:
52 self.page_test.CleanUpAfterPage(page, tab)
54 def ValidateAndMeasurePage(self, page, tab, results):
55 if self.page_test:
56 self.page_test.ValidateAndMeasurePage(page, tab, results)
58 def RunNavigateSteps(self, page, tab):
59 if self.page_test:
60 self.page_test.RunNavigateSteps(page, tab)
61 else:
62 super(RecorderPageTest, self).RunNavigateSteps(page, tab)
65 def _GetSubclasses(base_dir, cls):
66 """ Return all subclasses of |cls| in |base_dir|.
67 Args:
68 cls: a class
69 Returns:
71 """
72 return discover.DiscoverClasses(base_dir, base_dir, cls,
73 index_by_class_name=True)
76 def _MaybeGetInstanceOfClass(target, base_dir, cls):
77 if isinstance(target, cls):
78 return target
79 classes = _GetSubclasses(base_dir, cls)
80 return classes[target]() if target in classes else None
83 def _PrintAllBenchmarks(base_dir, output_stream):
84 # TODO: reuse the logic of finding supported benchmarks in benchmark_runner.py
85 # so this only prints out benchmarks that are supported by the recording
86 # platform.
87 classes = _GetSubclasses(base_dir, benchmark.Benchmark)
88 output_stream.write('Available benchmarks\' names:\n\n')
89 for k in classes:
90 output_stream.write('%s\n' % k)
93 def _PrintAllUserStories(base_dir, output_stream):
94 output_stream.write('Available page sets\' names:\n\n')
95 # TODO: actually print all user stories once record_wpr support general
96 # user stories recording.
97 classes = _GetSubclasses(base_dir, page_set.PageSet)
98 for k in classes:
99 output_stream.write('%s\n' % k)
102 class WprRecorder(object):
104 def __init__(self, base_dir, target, args=None):
105 self._record_page_test = RecorderPageTest()
106 self._options = self._CreateOptions()
108 self._benchmark = _MaybeGetInstanceOfClass(target, base_dir,
109 benchmark.Benchmark)
110 self._parser = self._options.CreateParser(usage='See %prog --help')
111 self._AddCommandLineArgs()
112 self._ParseArgs(args)
113 self._ProcessCommandLineArgs()
114 if self._benchmark is not None:
115 # This must be called after the command line args are added.
116 self._record_page_test.page_test = self._benchmark.CreatePageTest(
117 self.options)
119 if self._options.page_set_base_dir:
120 page_set_base_dir = self._options.page_set_base_dir
121 else:
122 page_set_base_dir = base_dir
123 self._page_set = self._GetPageSet(page_set_base_dir, target)
125 @property
126 def options(self):
127 return self._options
129 def _CreateOptions(self):
130 options = browser_options.BrowserFinderOptions()
131 options.browser_options.wpr_mode = wpr_modes.WPR_RECORD
132 options.browser_options.no_proxy_server = True
133 return options
135 def CreateResults(self):
136 if self._benchmark is not None:
137 benchmark_metadata = self._benchmark.GetMetadata()
138 else:
139 benchmark_metadata = benchmark.BenchmarkMetadata('record_wpr')
141 return results_options.CreateResults(benchmark_metadata, self._options)
143 def _AddCommandLineArgs(self):
144 self._parser.add_option('--page-set-base-dir', action='store',
145 type='string')
146 story_runner.AddCommandLineArgs(self._parser)
147 if self._benchmark is not None:
148 self._benchmark.AddCommandLineArgs(self._parser)
149 self._benchmark.SetArgumentDefaults(self._parser)
150 self._parser.add_option('--upload', action='store_true')
151 self._SetArgumentDefaults()
153 def _SetArgumentDefaults(self):
154 self._parser.set_defaults(**{'output_formats': ['none']})
156 def _ParseArgs(self, args=None):
157 args_to_parse = sys.argv[1:] if args is None else args
158 self._parser.parse_args(args_to_parse)
160 def _ProcessCommandLineArgs(self):
161 story_runner.ProcessCommandLineArgs(self._parser, self._options)
162 if self._benchmark is not None:
163 self._benchmark.ProcessCommandLineArgs(self._parser, self._options)
165 def _GetPageSet(self, base_dir, target):
166 if self._benchmark is not None:
167 return self._benchmark.CreatePageSet(self._options)
168 ps = _MaybeGetInstanceOfClass(target, base_dir, page_set.PageSet)
169 if ps is None:
170 self._parser.print_usage()
171 sys.exit(1)
172 return ps
174 def Record(self, results):
175 assert self._page_set.wpr_archive_info, (
176 'Pageset archive_data_file path must be specified.')
177 self._page_set.wpr_archive_info.AddNewTemporaryRecording()
178 self._record_page_test.CustomizeBrowserOptions(self._options)
179 story_runner.Run(self._record_page_test, self._page_set,
180 test_expectations.TestExpectations(), self._options, results)
182 def HandleResults(self, results, upload_to_cloud_storage):
183 if results.failures or results.skipped_values:
184 logging.warning('Some pages failed and/or were skipped. The recording '
185 'has not been updated for these pages.')
186 results.PrintSummary()
187 self._page_set.wpr_archive_info.AddRecordedUserStories(
188 results.pages_that_succeeded,
189 upload_to_cloud_storage)
192 # TODO(nednguyen): use benchmark.Environment instead of base_dir for discovering
193 # benchmark & user story classes.
194 def Main(base_dir):
196 parser = argparse.ArgumentParser(
197 usage='Record a benchmark or a user story (page set).')
198 parser.add_argument(
199 'benchmark', type=str,
200 help=('benchmark name. This argument is optional. If both benchmark name '
201 'and user story name are specified, this takes precedence as the '
202 'target of the recording.'),
203 nargs='?')
204 parser.add_argument('--story', dest='story', type=str,
205 help='user story (page set) name')
206 parser.add_argument('--list-stories', dest='list_stories',
207 action='store_true', help='list all user story names.')
208 parser.add_argument('--list-benchmarks', dest='list_benchmarks',
209 action='store_true', help='list all benchmark names.')
210 parser.add_argument('--upload', action='store_true',
211 help='upload to cloud storage.')
212 args, extra_args = parser.parse_known_args()
214 if args.list_benchmarks:
215 _PrintAllBenchmarks(base_dir, sys.stderr)
216 elif args.list_stories:
217 _PrintAllUserStories(base_dir, sys.stderr)
219 target = args.benchmark or args.story
221 if not target:
222 return 0
224 # TODO(nednguyen): update WprRecorder so that it handles the difference
225 # between recording a benchmark vs recording a user story better based on
226 # the distinction between args.benchmark & args.story
227 wpr_recorder = WprRecorder(base_dir, target, extra_args)
228 results = wpr_recorder.CreateResults()
229 wpr_recorder.Record(results)
230 wpr_recorder.HandleResults(results, args.upload)
231 return min(255, len(results.failures))