1 # Copyright (c) 2011 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 """SiteCompare command to invoke the same page in two versions of a browser. 6 7 Does the easiest compatibility test: equality comparison between two different 8 versions of the same browser. Invoked with a series of command line options 9 that specify which URLs to check, which browser to use, where to store results, 10 etc. 11 """ 12 13 import os # Functions for walking the directory tree 14 import tempfile # Get a temporary directory to hold intermediates 15 16 import command_line 17 import drivers # Functions for driving keyboard/mouse/windows, OS-specific 18 import operators # Functions that, given two bitmaps as input, produce 19 # output depending on the performance of an operation 20 import scrapers # Functions that know how to capture a render from 21 # particular browsers 22 23 24 def CreateCommand(cmdline): 25 """Inserts the command and arguments into a command line for parsing.""" 26 cmd = cmdline.AddCommand( 27 ["compare2"], 28 "Compares the output of two browsers on the same URL or list of URLs", 29 ValidateCompare2, 30 ExecuteCompare2) 31 32 cmd.AddArgument( 33 ["-b1", "--browser1"], "Full path to first browser's executable", 34 type="readfile", metaname="PATH", required=True) 35 cmd.AddArgument( 36 ["-b2", "--browser2"], "Full path to second browser's executable", 37 type="readfile", metaname="PATH", required=True) 38 cmd.AddArgument( 39 ["-b", "--browser"], "Which browser to use", type="string", 40 default="chrome") 41 cmd.AddArgument( 42 ["-b1v", "--browser1ver"], "Version of first browser", metaname="VERSION") 43 cmd.AddArgument( 44 ["-b2v", "--browser2ver"], "Version of second browser", metaname="VERSION") 45 cmd.AddArgument( 46 ["-b1n", "--browser1name"], "Optional name for first browser (used in " 47 "directory to hold intermediate files)", metaname="NAME") 48 cmd.AddArgument( 49 ["-b2n", "--browser2name"], "Optional name for second browser (used in " 50 "directory to hold intermediate files)", metaname="NAME") 51 cmd.AddArgument( 52 ["-o", "--outdir"], "Directory to store scrape files", metaname="DIR") 53 cmd.AddArgument( 54 ["-u", "--url"], "URL to compare") 55 cmd.AddArgument( 56 ["-l", "--list"], "List of URLs to compare", type="readfile") 57 cmd.AddMutualExclusion(["--url", "--list"]) 58 cmd.AddArgument( 59 ["-s", "--startline"], "First line of URL list", type="int") 60 cmd.AddArgument( 61 ["-e", "--endline"], "Last line of URL list (exclusive)", type="int") 62 cmd.AddArgument( 63 ["-c", "--count"], "Number of lines of URL file to use", type="int") 64 cmd.AddDependency("--startline", "--list") 65 cmd.AddRequiredGroup(["--url", "--list"]) 66 cmd.AddDependency("--endline", "--list") 67 cmd.AddDependency("--count", "--list") 68 cmd.AddMutualExclusion(["--count", "--endline"]) 69 cmd.AddDependency("--count", "--startline") 70 cmd.AddArgument( 71 ["-t", "--timeout"], "Amount of time (seconds) to wait for browser to " 72 "finish loading", 73 type="int", default=60) 74 cmd.AddArgument( 75 ["-log", "--logfile"], "File to write output", type="string", required=True) 76 cmd.AddArgument( 77 ["-sz", "--size"], "Browser window size", default=(800, 600), type="coords") 78 cmd.AddArgument( 79 ["-m", "--maskdir"], "Path that holds masks to use for comparison") 80 cmd.AddArgument( 81 ["-d", "--diffdir"], "Path to hold the difference of comparisons that fail") 82 83 84 def ValidateCompare2(command): 85 """Validate the arguments to compare2. Raises ParseError if failed.""" 86 executables = [".exe", ".com", ".bat"] 87 if (os.path.splitext(command["--browser1"])[1].lower() not in executables or 88 os.path.splitext(command["--browser2"])[1].lower() not in executables): 89 raise command_line.ParseError("Browser filename must be an executable") 90 91 92 def ExecuteCompare2(command): 93 """Executes the Compare2 command.""" 94 if command["--url"]: 95 url_list = [command["--url"]] 96 else: 97 startline = command["--startline"] 98 if command["--count"]: 99 endline = startline+command["--count"] 100 else: 101 endline = command["--endline"] 102 url_list = [url.strip() for url in 103 open(command["--list"], "r").readlines()[startline:endline]] 104 105 log_file = open(command["--logfile"], "w") 106 107 outdir = command["--outdir"] 108 if not outdir: outdir = tempfile.gettempdir() 109 110 scrape_info_list = [] 111 112 class ScrapeInfo(object): 113 """Helper class to hold information about a scrape.""" 114 __slots__ = ["browser_path", "scraper", "outdir", "result"] 115 116 for index in xrange(1, 3): 117 scrape_info = ScrapeInfo() 118 scrape_info.browser_path = command["--browser%d" % index] 119 scrape_info.scraper = scrapers.GetScraper( 120 (command["--browser"], command["--browser%dver" % index])) 121 122 if command["--browser%dname" % index]: 123 scrape_info.outdir = os.path.join(outdir, 124 command["--browser%dname" % index]) 125 else: 126 scrape_info.outdir = os.path.join(outdir, str(index)) 127 128 drivers.windowing.PreparePath(scrape_info.outdir) 129 scrape_info_list.append(scrape_info) 130 131 compare = operators.GetOperator("equals_with_mask") 132 133 for url in url_list: 134 success = True 135 136 for scrape_info in scrape_info_list: 137 scrape_info.result = scrape_info.scraper.Scrape( 138 [url], scrape_info.outdir, command["--size"], (0, 0), 139 command["--timeout"], path=scrape_info.browser_path) 140 141 if not scrape_info.result: 142 scrape_info.result = "success" 143 else: 144 success = False 145 146 result = "unknown" 147 148 if success: 149 result = "equal" 150 151 file1 = drivers.windowing.URLtoFilename( 152 url, scrape_info_list[0].outdir, ".bmp") 153 file2 = drivers.windowing.URLtoFilename( 154 url, scrape_info_list[1].outdir, ".bmp") 155 156 comparison_result = compare.Compare(file1, file2, 157 maskdir=command["--maskdir"]) 158 159 if comparison_result is not None: 160 result = "not-equal" 161 162 if command["--diffdir"]: 163 comparison_result[1].save( 164 drivers.windowing.URLtoFilename(url, command["--diffdir"], ".bmp")) 165 166 # TODO(jhaas): maybe use the logging module rather than raw file writes 167 log_file.write("%s %s %s %s\n" % (url, 168 scrape_info_list[0].result, 169 scrape_info_list[1].result, 170 result)) 171