Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: chrome/test/functional/ispy/common/chrome_utils.py

Issue 106523003: [I-Spy] Add support for rebaselining expectations from the web UI. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add missing dom.py Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import json 5 import json
6 import logging 6 import logging
7 import os 7 import os
8 import time
9 from distutils.version import LooseVersion 8 from distutils.version import LooseVersion
10 from PIL import Image 9 from PIL import Image
11 10
12 from ..common import cloud_bucket 11 import cloud_bucket
13 from ..common import ispy_utils 12 import ispy_utils
14 13
15 14
16 class ChromeUtils(object): 15 class ChromeUtils(object):
17 """A utility for using ISpy with Chrome.""" 16 """A utility for using ISpy with Chrome."""
18 17
19 def __init__(self, cloud_bucket, version_file, screenshot_func): 18 def __init__(self, cloud_bucket):
20 """Initializes the utility class. 19 """Initializes the utility class.
21 20
22 Args: 21 Args:
23 cloud_bucket: a BaseCloudBucket in which to the version file, 22 cloud_bucket: a BaseCloudBucket in which to the version file,
24 expectations and results are to be stored. 23 expectations and results are to be stored.
25 version_file: path to the version file in the cloud bucket. The version
26 file contains a json list of ordered Chrome versions for which
27 expectations exist.
28 screenshot_func: a function that returns a PIL.Image.
29 """ 24 """
30 self._cloud_bucket = cloud_bucket 25 self._cloud_bucket = cloud_bucket
31 self._version_file = version_file
32 self._screenshot_func = screenshot_func
33 self._ispy = ispy_utils.ISpyUtils(self._cloud_bucket) 26 self._ispy = ispy_utils.ISpyUtils(self._cloud_bucket)
34 with open( 27 self._rebaselineable_cache = {}
35 os.path.join(os.path.dirname(__file__), 'wait_on_ajax.js'), 'r') as f:
36 self._wait_for_unchanging_dom_script = f.read()
37 28
38 def UpdateExpectationVersion(self, chrome_version): 29 def UpdateExpectationVersion(self, chrome_version, version_file):
39 """Updates the most recent expectation version to the Chrome version. 30 """Updates the most recent expectation version to the Chrome version.
40 31
41 Should be called after generating a new set of expectations. 32 Should be called after generating a new set of expectations.
42 33
43 Args: 34 Args:
44 chrome_version: the chrome version as a string of the form "31.0.123.4". 35 chrome_version: the chrome version as a string of the form "31.0.123.4".
36 version_file: path to the version file in the cloud bucket. The version
37 file contains a json list of ordered Chrome versions for which
38 expectations exist.
45 """ 39 """
46 insert_pos = 0 40 insert_pos = 0
47 expectation_versions = [] 41 expectation_versions = []
48 try: 42 try:
49 expectation_versions = self._GetExpectationVersionList() 43 expectation_versions = self._GetExpectationVersionList(version_file)
50 if expectation_versions: 44 if expectation_versions:
51 try: 45 try:
52 version = self._GetExpectationVersion( 46 version = self._GetExpectationVersion(
53 chrome_version, expectation_versions) 47 chrome_version, expectation_versions)
54 if version == chrome_version: 48 if version == chrome_version:
55 return 49 return
56 insert_pos = expectation_versions.index(version) 50 insert_pos = expectation_versions.index(version)
57 except: 51 except:
58 insert_pos = len(expectation_versions) 52 insert_pos = len(expectation_versions)
59 except cloud_bucket.FileNotFoundError: 53 except cloud_bucket.FileNotFoundError:
60 pass 54 pass
61 expectation_versions.insert(insert_pos, chrome_version) 55 expectation_versions.insert(insert_pos, chrome_version)
62 logging.info('Updating expectation version...') 56 logging.info('Updating expectation version...')
63 self._cloud_bucket.UploadFile( 57 self._cloud_bucket.UploadFile(
64 self._version_file, json.dumps(expectation_versions), 58 version_file, json.dumps(expectation_versions),
65 'application/json') 59 'application/json')
66 60
67 def _GetExpectationVersion(self, chrome_version, expectation_versions): 61 def _GetExpectationVersion(self, chrome_version, expectation_versions):
68 """Returns the expectation version for the given Chrome version. 62 """Returns the expectation version for the given Chrome version.
69 63
70 Args: 64 Args:
71 chrome_version: the chrome version as a string of the form "31.0.123.4". 65 chrome_version: the chrome version as a string of the form "31.0.123.4".
72 expectation_versions: Ordered list of Chrome versions for which 66 expectation_versions: Ordered list of Chrome versions for which
73 expectations exist, as stored in the version file. 67 expectations exist, as stored in the version file.
74 68
75 Returns: 69 Returns:
76 Expectation version string. 70 Expectation version string.
77 """ 71 """
78 # Find the closest version that is not greater than the chrome version. 72 # Find the closest version that is not greater than the chrome version.
79 for version in expectation_versions: 73 for version in expectation_versions:
80 if LooseVersion(version) <= LooseVersion(chrome_version): 74 if LooseVersion(version) <= LooseVersion(chrome_version):
81 return version 75 return version
82 raise Exception('No expectation exists for Chrome %s' % chrome_version) 76 raise Exception('No expectation exists for Chrome %s' % chrome_version)
83 77
84 def _GetExpectationVersionList(self): 78 def _GetExpectationVersionList(self, version_file):
85 """Gets the list of expectation versions from google storage.""" 79 """Gets the list of expectation versions from google storage.
86 return json.loads(self._cloud_bucket.DownloadFile(self._version_file)) 80
81 Args:
82 version_file: path to the version file in the cloud bucket. The version
83 file contains a json list of ordered Chrome versions for which
84 expectations exist.
85
86 Returns:
87 Ordered list of Chrome versions.
88 """
89 return json.loads(self._cloud_bucket.DownloadFile(version_file))
87 90
88 def _GetExpectationNameWithVersion(self, device_type, expectation, 91 def _GetExpectationNameWithVersion(self, device_type, expectation,
89 chrome_version): 92 chrome_version, version_file):
90 """Get the expectation to be used with the current Chrome version. 93 """Get the expectation to be used with the current Chrome version.
91 94
92 Args: 95 Args:
93 device_type: string identifier for the device type. 96 device_type: string identifier for the device type.
94 expectation: name for the expectation to generate. 97 expectation: name for the expectation to generate.
95 chrome_version: the chrome version as a string of the form "31.0.123.4". 98 chrome_version: the chrome version as a string of the form "31.0.123.4".
96 99
97 Returns: 100 Returns:
98 Version as an integer. 101 Version as an integer.
99 """ 102 """
100 version = self._GetExpectationVersion( 103 version = self._GetExpectationVersion(
101 chrome_version, self._GetExpectationVersionList()) 104 chrome_version, self._GetExpectationVersionList(version_file))
102 return self._CreateExpectationName(device_type, expectation, version) 105 return self._CreateExpectationName(device_type, expectation, version)
103 106
104 def _CreateExpectationName(self, device_type, expectation, version): 107 def _CreateExpectationName(self, device_type, expectation, version):
105 """Create the full expectation name from the expectation and version. 108 """Create the full expectation name from the expectation and version.
106 109
107 Args: 110 Args:
108 device_type: string identifier for the device type, example: mako 111 device_type: string identifier for the device type, example: mako
109 expectation: base name for the expectation, example: google.com 112 expectation: base name for the expectation, example: google.com
110 version: expectation version, example: 31.0.23.1 113 version: expectation version, example: 31.0.23.1
111 114
112 Returns: 115 Returns:
113 Full expectation name as a string, example: mako:google.com(31.0.23.1) 116 Full expectation name as a string, example: mako:google.com(31.0.23.1)
114 """ 117 """
115 return '%s:%s(%s)' % (device_type, expectation, version) 118 return '%s:%s(%s)' % (device_type, expectation, version)
116 119
117 def GenerateExpectation(self, device_type, expectation, chrome_version): 120 def GenerateExpectation(self, device_type, expectation, chrome_version,
118 """Take screenshots and store as an expectation in I-Spy. 121 version_file, screenshots):
122 """Create an expectation for I-Spy.
119 123
120 Args: 124 Args:
121 device_type: string identifier for the device type. 125 device_type: string identifier for the device type.
122 expectation: name for the expectation to generate. 126 expectation: name for the expectation to generate.
123 chrome_version: the chrome version as a string of the form "31.0.123.4". 127 chrome_version: the chrome version as a string of the form "31.0.123.4".
128 screenshots: a list of similar PIL.Images.
124 """ 129 """
125 # https://code.google.com/p/chromedriver/issues/detail?id=463 130 # https://code.google.com/p/chromedriver/issues/detail?id=463
126 time.sleep(1)
127 expectation_with_version = self._CreateExpectationName( 131 expectation_with_version = self._CreateExpectationName(
128 device_type, expectation, chrome_version) 132 device_type, expectation, chrome_version)
129 if self._ispy.ExpectationExists(expectation_with_version): 133 if self._ispy.ExpectationExists(expectation_with_version):
130 logging.warning( 134 logging.warning(
131 'I-Spy expectation \'%s\' already exists, overwriting.', 135 'I-Spy expectation \'%s\' already exists, overwriting.',
132 expectation_with_version) 136 expectation_with_version)
133 screenshots = [self._screenshot_func() for _ in range(8)]
134 logging.info('Generating I-Spy expectation...') 137 logging.info('Generating I-Spy expectation...')
135 self._ispy.GenerateExpectation(expectation_with_version, screenshots) 138 self._ispy.GenerateExpectation(expectation_with_version, screenshots)
136 139
137 def PerformComparison(self, test_run, device_type, expectation, 140 def PerformComparison(self, test_run, device_type, expectation,
138 chrome_version): 141 chrome_version, version_file, screenshot):
139 """Take a screenshot and compare it with the given expectation in I-Spy. 142 """Compare a screenshot with the given expectation in I-Spy.
140 143
141 Args: 144 Args:
142 test_run: name for the test run. 145 test_run: name for the test run.
143 device_type: string identifier for the device type. 146 device_type: string identifier for the device type.
144 expectation: name for the expectation to compare against. 147 expectation: name for the expectation to compare against.
145 chrome_version: the chrome version as a string of the form "31.0.123.4". 148 chrome_version: the chrome version as a string of the form "31.0.123.4".
149 screenshot: a PIL.Image to compare.
146 """ 150 """
147 # https://code.google.com/p/chromedriver/issues/detail?id=463 151 # https://code.google.com/p/chromedriver/issues/detail?id=463
148 time.sleep(1)
149 screenshot = self._screenshot_func()
150 logging.info('Performing I-Spy comparison...') 152 logging.info('Performing I-Spy comparison...')
151 self._ispy.PerformComparison( 153 self._ispy.PerformComparison(
152 test_run, 154 test_run,
153 self._GetExpectationNameWithVersion( 155 self._GetExpectationNameWithVersion(
154 device_type, expectation, chrome_version), 156 device_type, expectation, chrome_version, version_file),
155 screenshot) 157 screenshot)
156 158
157 def GetScriptToWaitForUnchangingDOM(self): 159 def CanRebaselineToTestRun(self, test_run):
158 """Returns a JavaScript script that waits for the DOM to stop changing.""" 160 """Returns whether the test run has associated expectations.
159 return self._wait_for_unchanging_dom_script
160 161
162 Returns:
163 True if RebaselineToTestRun() can be called for this test run.
164 """
165 if test_run in self._rebaselineable_cache:
166 return True
167 return self._cloud_bucket.FileExists(
168 ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt'))
169
170 def RebaselineToTestRun(self, test_run):
171 """Update the version file to use expectations associated with |test_run|.
172
173 Args:
174 test_run: The name of the test run to rebaseline.
175 """
176 rebaseline_path = ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt')
177 rebaseline_attrib = json.loads(
178 self._cloud_bucket.DownloadFile(rebaseline_path))
179 self.UpdateExpectationVersion(
180 rebaseline_attrib['version'], rebaseline_attrib['version_file'])
181 self._cloud_bucket.RemoveFile(rebaseline_path)
182
183 def _SetTestRunRebaselineable(self, test_run, chrome_version, version_file):
184 """Writes a JSON file containing the data needed to rebaseline.
185
186 Args:
187 test_run: The name of the test run to add the rebaseline file to.
188 chrome_version: the chrome version that can be rebaselined to (must have
189 associated Expectations).
190 version_file: the path of the version file associated with the test run.
191 """
192 self._rebaselineable_cache[test_run] = True
193 self._cloud_bucket.UploadFile(
194 ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt'),
195 json.dumps({
196 'version': chrome_version,
197 'version_file': version_file}),
198 'application/json')
199
200 def PerformComparisonAndPrepareExpectation(self, test_run, device_type,
201 expectation, chrome_version,
202 version_file, screenshots):
203 """Perform comparison and generate an expectation that can used later.
204
205 The test run web UI will have a button to set the Expectations generated for
206 this version as the expectation for comparison with later versions.
207
208 Args:
209 test_run: The name of the test run to add the rebaseline file to.
210 device_type: string identifier for the device type.
211 chrome_version: the chrome version that can be rebaselined to (must have
212 associated Expectations).
213 version_file: the path of the version file associated with the test run.
214 screenshot: a list of similar PIL.Images.
215 """
216 if not self.CanRebaselineToTestRun(test_run):
217 self._SetTestRunRebaselineable(test_run, chrome_version, version_file)
218 expectation_with_version = self._CreateExpectationName(
219 device_type, expectation, chrome_version)
220 self._ispy.GenerateExpectation(expectation_with_version, screenshots)
221 self._ispy.PerformComparison(
222 test_run,
223 self._GetExpectationNameWithVersion(
224 device_type, expectation, chrome_version, version_file),
225 screenshots[-1])
226
OLDNEW
« no previous file with comments | « chrome/test/functional/ispy/client/dom.py ('k') | chrome/test/functional/ispy/common/chrome_utils_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698