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.
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
):
23 super(RecorderPageTest
, self
).__init
__()
26 def CustomizeBrowserOptions(self
, options
):
28 self
.page_test
.CustomizeBrowserOptions(options
)
30 def WillStartBrowser(self
, browser
):
32 self
.page_test
.WillStartBrowser(browser
)
34 def DidStartBrowser(self
, browser
):
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)
42 self
.page_test
.WillNavigateToPage(page
, tab
)
44 def DidNavigateToPage(self
, page
, tab
):
46 self
.page_test
.DidNavigateToPage(page
, tab
)
47 tab
.WaitForDocumentReadyStateToBeComplete()
48 util
.WaitFor(tab
.HasReachedQuiescence
, 30)
50 def CleanUpAfterPage(self
, page
, tab
):
52 self
.page_test
.CleanUpAfterPage(page
, tab
)
54 def ValidateAndMeasurePage(self
, page
, tab
, results
):
56 self
.page_test
.ValidateAndMeasurePage(page
, tab
, results
)
58 def RunNavigateSteps(self
, page
, tab
):
60 self
.page_test
.RunNavigateSteps(page
, tab
)
62 super(RecorderPageTest
, self
).RunNavigateSteps(page
, tab
)
65 def _GetSubclasses(base_dir
, cls
):
66 """ Return all subclasses of |cls| in |base_dir|.
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
):
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
87 classes
= _GetSubclasses(base_dir
, benchmark
.Benchmark
)
88 output_stream
.write('Available benchmarks\' names:\n\n')
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
)
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
,
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(
119 if self
._options
.page_set_base_dir
:
120 page_set_base_dir
= self
._options
.page_set_base_dir
122 page_set_base_dir
= base_dir
123 self
._page
_set
= self
._GetPageSet
(page_set_base_dir
, target
)
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
135 def CreateResults(self
):
136 if self
._benchmark
is not None:
137 benchmark_metadata
= self
._benchmark
.GetMetadata()
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',
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
)
170 self
._parser
.print_usage()
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.
196 parser
= argparse
.ArgumentParser(
197 usage
='Record a benchmark or a user story (page set).')
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.'),
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
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
))