Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / test / ispy / ispy_api.py
1 # Copyright 2014 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 import json
6 import logging
7 import os
8 from distutils.version import LooseVersion
9 from PIL import Image
10
11 from common import cloud_bucket
12 from common import ispy_utils
13
14
15 class ISpyApi(object):
16   """The public API for interacting with ISpy."""
17
18   def __init__(self, cloud_bucket):
19     """Initializes the utility class.
20
21     Args:
22       cloud_bucket: a BaseCloudBucket in which to the version file,
23           expectations and results are to be stored.
24     """
25     self._cloud_bucket = cloud_bucket
26     self._ispy = ispy_utils.ISpyUtils(self._cloud_bucket)
27     self._rebaselineable_cache = {}
28
29   def UpdateExpectationVersion(self, chrome_version, version_file):
30     """Updates the most recent expectation version to the Chrome version.
31
32     Should be called after generating a new set of expectations.
33
34     Args:
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.
39     """
40     insert_pos = 0
41     expectation_versions = []
42     try:
43       expectation_versions = self._GetExpectationVersionList(version_file)
44       if expectation_versions:
45         try:
46           version = self._GetExpectationVersion(
47               chrome_version, expectation_versions)
48           if version == chrome_version:
49             return
50           insert_pos = expectation_versions.index(version)
51         except:
52           insert_pos = len(expectation_versions)
53     except cloud_bucket.FileNotFoundError:
54       pass
55     expectation_versions.insert(insert_pos, chrome_version)
56     logging.info('Updating expectation version...')
57     self._cloud_bucket.UploadFile(
58         version_file, json.dumps(expectation_versions),
59         'application/json')
60
61   def _GetExpectationVersion(self, chrome_version, expectation_versions):
62     """Returns the expectation version for the given Chrome version.
63
64     Args:
65       chrome_version: the chrome version as a string of the form "31.0.123.4".
66       expectation_versions: Ordered list of Chrome versions for which
67         expectations exist, as stored in the version file.
68
69     Returns:
70       Expectation version string.
71     """
72     # Find the closest version that is not greater than the chrome version.
73     for version in expectation_versions:
74       if LooseVersion(version) <= LooseVersion(chrome_version):
75         return version
76     raise Exception('No expectation exists for Chrome %s' % chrome_version)
77
78   def _GetExpectationVersionList(self, version_file):
79     """Gets the list of expectation versions from google storage.
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     try:
90       return json.loads(self._cloud_bucket.DownloadFile(version_file))
91     except:
92       return []
93
94   def _GetExpectationNameWithVersion(self, device_type, expectation,
95                                      chrome_version, version_file):
96     """Get the expectation to be used with the current Chrome version.
97
98     Args:
99       device_type: string identifier for the device type.
100       expectation: name for the expectation to generate.
101       chrome_version: the chrome version as a string of the form "31.0.123.4".
102
103     Returns:
104       Version as an integer.
105     """
106     version = self._GetExpectationVersion(
107         chrome_version, self._GetExpectationVersionList(version_file))
108     return self._CreateExpectationName(device_type, expectation, version)
109
110   def _CreateExpectationName(self, device_type, expectation, version):
111     """Create the full expectation name from the expectation and version.
112
113     Args:
114       device_type: string identifier for the device type, example: mako
115       expectation: base name for the expectation, example: google.com
116       version: expectation version, example: 31.0.23.1
117
118     Returns:
119       Full expectation name as a string, example: mako:google.com(31.0.23.1)
120     """
121     return '%s:%s(%s)' % (device_type, expectation, version)
122
123   def GenerateExpectation(self, device_type, expectation, chrome_version,
124                           version_file, screenshots):
125     """Create an expectation for I-Spy.
126
127     Args:
128       device_type: string identifier for the device type.
129       expectation: name for the expectation to generate.
130       chrome_version: the chrome version as a string of the form "31.0.123.4".
131       screenshots: a list of similar PIL.Images.
132     """
133     # https://code.google.com/p/chromedriver/issues/detail?id=463
134     expectation_with_version = self._CreateExpectationName(
135         device_type, expectation, chrome_version)
136     if self._ispy.ExpectationExists(expectation_with_version):
137       logging.warning(
138           'I-Spy expectation \'%s\' already exists, overwriting.',
139           expectation_with_version)
140     logging.info('Generating I-Spy expectation...')
141     self._ispy.GenerateExpectation(expectation_with_version, screenshots)
142
143   def PerformComparison(self, test_run, device_type, expectation,
144                         chrome_version, version_file, screenshot):
145     """Compare a screenshot with the given expectation in I-Spy.
146
147     Args:
148       test_run: name for the test run.
149       device_type: string identifier for the device type.
150       expectation: name for the expectation to compare against.
151       chrome_version: the chrome version as a string of the form "31.0.123.4".
152       screenshot: a PIL.Image to compare.
153     """
154     # https://code.google.com/p/chromedriver/issues/detail?id=463
155     logging.info('Performing I-Spy comparison...')
156     self._ispy.PerformComparison(
157         test_run,
158         self._GetExpectationNameWithVersion(
159             device_type, expectation, chrome_version, version_file),
160         screenshot)
161
162   def CanRebaselineToTestRun(self, test_run):
163     """Returns whether the test run has associated expectations.
164
165     Returns:
166       True if RebaselineToTestRun() can be called for this test run.
167     """
168     if test_run in self._rebaselineable_cache:
169       return True
170     return self._cloud_bucket.FileExists(
171         ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt'))
172
173   def RebaselineToTestRun(self, test_run):
174     """Update the version file to use expectations associated with |test_run|.
175
176     Args:
177       test_run: The name of the test run to rebaseline.
178     """
179     rebaseline_path = ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt')
180     rebaseline_attrib = json.loads(
181         self._cloud_bucket.DownloadFile(rebaseline_path))
182     self.UpdateExpectationVersion(
183         rebaseline_attrib['version'], rebaseline_attrib['version_file'])
184     self._cloud_bucket.RemoveFile(rebaseline_path)
185
186   def _SetTestRunRebaselineable(self, test_run, chrome_version, version_file):
187     """Writes a JSON file containing the data needed to rebaseline.
188
189     Args:
190       test_run: The name of the test run to add the rebaseline file to.
191       chrome_version: the chrome version that can be rebaselined to (must have
192         associated Expectations).
193       version_file: the path of the version file associated with the test run.
194     """
195     self._rebaselineable_cache[test_run] = True
196     self._cloud_bucket.UploadFile(
197         ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt'),
198         json.dumps({
199             'version': chrome_version,
200             'version_file': version_file}),
201         'application/json')
202
203   def PerformComparisonAndPrepareExpectation(self, test_run, device_type,
204                                              expectation, chrome_version,
205                                              version_file, screenshots):
206     """Perform comparison and generate an expectation that can used later.
207
208     The test run web UI will have a button to set the Expectations generated for
209     this version as the expectation for comparison with later versions.
210
211     Args:
212       test_run: The name of the test run to add the rebaseline file to.
213       device_type: string identifier for the device type.
214       chrome_version: the chrome version that can be rebaselined to (must have
215         associated Expectations).
216       version_file: the path of the version file associated with the test run.
217       screenshot: a list of similar PIL.Images.
218     """
219     if not self.CanRebaselineToTestRun(test_run):
220       self._SetTestRunRebaselineable(test_run, chrome_version, version_file)
221     expectation_with_version = self._CreateExpectationName(
222         device_type, expectation, chrome_version)
223     self._ispy.GenerateExpectation(expectation_with_version, screenshots)
224     self._ispy.PerformComparison(
225         test_run,
226         self._GetExpectationNameWithVersion(
227             device_type, expectation, chrome_version, version_file),
228         screenshots[-1])
229