15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""SiteCompare command to time page loads
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Loads a series of URLs in a series of browsers (and browser versions)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)and measures how long the page takes to load in each. Outputs a
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)comma-delimited file. The first line is "URL,[browser names", each
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)additional line is a URL follored by comma-delimited times (in seconds),
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)or the string "timeout" or "crashed".
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os            # Functions for walking the directory tree
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile      # Get a temporary directory to hold intermediates
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import command_line
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import drivers       # Functions for driving keyboard/mouse/windows, OS-specific
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import operators     # Functions that, given two bitmaps as input, produce
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     # output depending on the performance of an operation
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import scrapers      # Functions that know how to capture a render from
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     # particular browsers
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreateCommand(cmdline):
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Inserts the command and arguments into a command line for parsing."""
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd = cmdline.AddCommand(
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["timeload"],
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Measures how long a series of URLs takes to load in one or more browsers.",
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    None,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExecuteTimeLoad)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-b", "--browsers"], "List of browsers to use. Comma-separated",
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type="string", required=True)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-bp", "--browserpaths"], "List of paths to browsers. Comma-separated",
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type="string", required=False)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-bv", "--browserversions"],
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "List of versions of browsers. Comma-separated",
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type="string", required=False)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-u", "--url"], "URL to time")
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-l", "--list"], "List of URLs to time", type="readfile")
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddMutualExclusion(["--url", "--list"])
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-s", "--startline"], "First line of URL list", type="int")
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-e", "--endline"], "Last line of URL list (exclusive)", type="int")
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-c", "--count"], "Number of lines of URL file to use", type="int")
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddDependency("--startline", "--list")
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddRequiredGroup(["--url", "--list"])
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddDependency("--endline", "--list")
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddDependency("--count", "--list")
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddMutualExclusion(["--count", "--endline"])
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddDependency("--count", "--startline")
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-t", "--timeout"], "Amount of time (seconds) to wait for browser to "
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "finish loading",
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type="int", default=60)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-log", "--logfile"], "File to write output", type="string", required=True)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd.AddArgument(
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ["-sz", "--size"], "Browser window size", default=(800, 600), type="coords")
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExecuteTimeLoad(command):
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Executes the TimeLoad command."""
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browsers = command["--browsers"].split(",")
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  num_browsers = len(browsers)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if command["--browserversions"]:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_versions = command["--browserversions"].split(",")
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_versions = [None] * num_browsers
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if command["--browserpaths"]:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_paths = command["--browserpaths"].split(",")
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_paths = [None] * num_browsers
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(browser_versions) != num_browsers:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise ValueError(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "--browserversions must be same length as --browser_paths")
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(browser_paths) != num_browsers:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise ValueError(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "--browserversions must be same length as --browser_paths")
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if [b for b in browsers if b not in ["chrome", "ie", "firefox"]]:
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise ValueError("unknown browsers: %r" % b)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scraper_list = []
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for b in xrange(num_browsers):
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    version = browser_versions[b]
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not version: version = None
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scraper = scrapers.GetScraper( (browsers[b], version) )
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not scraper:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ValueError("could not find scraper for (%r, %r)" %
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (browsers[b], version))
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scraper_list.append(scraper)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if command["--url"]:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_list = [command["--url"]]
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    startline = command["--startline"]
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if command["--count"]:
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      endline = startline+command["--count"]
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      endline = command["--endline"]
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url_list = [url.strip() for url in
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                open(command["--list"], "r").readlines()[startline:endline]]
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log_file = open(command["--logfile"], "w")
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log_file.write("URL")
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for b in xrange(num_browsers):
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log_file.write(",%s" % browsers[b])
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if browser_versions[b]: log_file.write(" %s" % browser_versions[b])
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  log_file.write("\n")
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results = {}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for url in url_list:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    results[url] = [None] * num_browsers
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for b in xrange(num_browsers):
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = scraper_list[b].Time(url_list, command["--size"],
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      command["--timeout"],
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path=browser_paths[b])
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (url, time) in result:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      results[url][b] = time
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # output the results
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for url in url_list:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    log_file.write(url)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for b in xrange(num_browsers):
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_file.write(",%r" % results[url][b])
145