blob: be3bb51aca39bf3ab31127f50fcd213c734e2a99 [file] [log] [blame]
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import sys
from telemetry.page import block_page_measurement_results
from telemetry.page import buildbot_page_measurement_results
from telemetry.page import csv_page_measurement_results
from telemetry.page import html_page_measurement_results
from telemetry.page import page_measurement_results
from telemetry.page import page_test
class MeasurementFailure(page_test.Failure):
"""Exception that can be thrown from MeasurePage to indicate an undesired but
designed-for problem."""
pass
class PageMeasurement(page_test.PageTest):
"""Glue code for running a measurement across a set of pages.
To use this, subclass from the measurement and override MeasurePage. For
example:
class BodyChildElementMeasurement(PageMeasurement):
def MeasurePage(self, page, tab, results):
body_child_count = tab.EvaluateJavaScript(
'document.body.children.length')
results.Add('body_children', 'count', body_child_count)
if __name__ == '__main__':
page_measurement.Main(BodyChildElementMeasurement())
To add test-specific options:
class BodyChildElementMeasurement(PageMeasurement):
def AddCommandLineOptions(parser):
parser.add_option('--element', action='store', default='body')
def MeasurePage(self, page, tab, results):
body_child_count = tab.EvaluateJavaScript(
'document.querySelector('%s').children.length')
results.Add('children', 'count', child_count)
"""
def __init__(self,
action_name_to_run='',
needs_browser_restart_after_each_run=False,
discard_first_result=False,
clear_cache_before_each_run=False):
super(PageMeasurement, self).__init__(
'_RunTest',
action_name_to_run,
needs_browser_restart_after_each_run,
discard_first_result,
clear_cache_before_each_run)
def _RunTest(self, page, tab, results):
results.WillMeasurePage(page)
self.MeasurePage(page, tab, results)
results.DidMeasurePage()
def AddOutputOptions(self, parser):
super(PageMeasurement, self).AddOutputOptions(parser)
parser.add_option('-o', '--output',
dest='output_file',
help='Redirects output to a file. Defaults to stdout.')
parser.add_option('--output-trace-tag',
default='',
help='Append a tag to the key of each result trace.')
parser.add_option('--reset-html-results', action='store_true',
help='Delete all stored runs in HTML output')
@property
def output_format_choices(self):
return ['html', 'buildbot', 'block', 'csv', 'none']
def PrepareResults(self, options):
if hasattr(options, 'output_file') and options.output_file:
output_file = os.path.expanduser(options.output_file)
open(output_file, 'a').close() # Create file if it doesn't exist.
output_stream = open(output_file, 'r+')
else:
output_stream = sys.stdout
if not hasattr(options, 'output_format'):
options.output_format = self.output_format_choices[0]
if not hasattr(options, 'output_trace_tag'):
options.output_trace_tag = ''
if options.output_format == 'csv':
return csv_page_measurement_results.CsvPageMeasurementResults(
output_stream,
self.results_are_the_same_on_every_page)
elif options.output_format == 'block':
return block_page_measurement_results.BlockPageMeasurementResults(
output_stream)
elif options.output_format == 'buildbot':
return buildbot_page_measurement_results.BuildbotPageMeasurementResults(
trace_tag=options.output_trace_tag)
elif options.output_format == 'html':
return html_page_measurement_results.HtmlPageMeasurementResults(
output_stream, self.__class__.__name__, options.reset_html_results,
options.browser_type, trace_tag=options.output_trace_tag)
elif options.output_format == 'none':
return page_measurement_results.PageMeasurementResults(
trace_tag=options.output_trace_tag)
else:
# Should never be reached. The parser enforces the choices.
raise Exception('Invalid --output-format "%s". Valid choices are: %s'
% (options.output_format,
', '.join(self.output_format_choices)))
@property
def results_are_the_same_on_every_page(self):
"""By default, measurements are assumed to output the same values for every
page. This allows incremental output, for example in CSV. If, however, the
measurement discovers what values it can report as it goes, and those values
may vary from page to page, you need to override this function and return
False. Output will not appear in this mode until the entire pageset has
run."""
return True
def MeasurePage(self, page, tab, results):
"""Override to actually measure the page's performance.
page is a page_set.Page
tab is an instance of telemetry.core.Tab
Should call results.Add(name, units, value) for each result, or raise an
exception on failure. The name and units of each Add() call must be
the same across all iterations. The name 'url' must not be used.
Prefer field names that are in accordance with python variable style. E.g.
field_name.
Put together:
def MeasurePage(self, page, tab, results):
res = tab.EvaluateJavaScript('2+2')
if res != 4:
raise Exception('Oh, wow.')
results.Add('two_plus_two', 'count', res)
"""
raise NotImplementedError()