• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3# found in the LICENSE file.
4
5import json
6import logging
7import os
8import time
9from distutils.version import LooseVersion
10from PIL import Image
11
12from ..common import cloud_bucket
13from ..common import ispy_utils
14
15
16class ChromeUtils(object):
17  """A utility for using ISpy with Chrome."""
18
19  def __init__(self, cloud_bucket, version_file, screenshot_func):
20    """Initializes the utility class.
21
22    Args:
23      cloud_bucket: a BaseCloudBucket in which to the version file,
24          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    """
30    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)
34    with open(
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
38  def UpdateExpectationVersion(self, chrome_version):
39    """Updates the most recent expectation version to the Chrome version.
40
41    Should be called after generating a new set of expectations.
42
43    Args:
44      chrome_version: the chrome version as a string of the form "31.0.123.4".
45    """
46    insert_pos = 0
47    expectation_versions = []
48    try:
49      expectation_versions = self._GetExpectationVersionList()
50      if expectation_versions:
51        try:
52          version = self._GetExpectationVersion(
53              chrome_version, expectation_versions)
54          if version == chrome_version:
55            return
56          insert_pos = expectation_versions.index(version)
57        except:
58          insert_pos = len(expectation_versions)
59    except cloud_bucket.FileNotFoundError:
60      pass
61    expectation_versions.insert(insert_pos, chrome_version)
62    logging.info('Updating expectation version...')
63    self._cloud_bucket.UploadFile(
64        self._version_file, json.dumps(expectation_versions),
65        'application/json')
66
67  def _GetExpectationVersion(self, chrome_version, expectation_versions):
68    """Returns the expectation version for the given Chrome version.
69
70    Args:
71      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
73        expectations exist, as stored in the version file.
74
75    Returns:
76      Expectation version string.
77    """
78    # Find the closest version that is not greater than the chrome version.
79    for version in expectation_versions:
80      if LooseVersion(version) <= LooseVersion(chrome_version):
81        return version
82    raise Exception('No expectation exists for Chrome %s' % chrome_version)
83
84  def _GetExpectationVersionList(self):
85    """Gets the list of expectation versions from google storage."""
86    return json.loads(self._cloud_bucket.DownloadFile(self._version_file))
87
88  def _GetExpectationNameWithVersion(self, device_type, expectation,
89                                     chrome_version):
90    """Get the expectation to be used with the current Chrome version.
91
92    Args:
93      device_type: string identifier for the device type.
94      expectation: name for the expectation to generate.
95      chrome_version: the chrome version as a string of the form "31.0.123.4".
96
97    Returns:
98      Version as an integer.
99    """
100    version = self._GetExpectationVersion(
101        chrome_version, self._GetExpectationVersionList())
102    return self._CreateExpectationName(device_type, expectation, version)
103
104  def _CreateExpectationName(self, device_type, expectation, version):
105    """Create the full expectation name from the expectation and version.
106
107    Args:
108      device_type: string identifier for the device type, example: mako
109      expectation: base name for the expectation, example: google.com
110      version: expectation version, example: 31.0.23.1
111
112    Returns:
113      Full expectation name as a string, example: mako:google.com(31.0.23.1)
114    """
115    return '%s:%s(%s)' % (device_type, expectation, version)
116
117  def GenerateExpectation(self, device_type, expectation, chrome_version):
118    """Take screenshots and store as an expectation in I-Spy.
119
120    Args:
121      device_type: string identifier for the device type.
122      expectation: name for the expectation to generate.
123      chrome_version: the chrome version as a string of the form "31.0.123.4".
124    """
125    # https://code.google.com/p/chromedriver/issues/detail?id=463
126    time.sleep(1)
127    expectation_with_version = self._CreateExpectationName(
128        device_type, expectation, chrome_version)
129    if self._ispy.ExpectationExists(expectation_with_version):
130      logging.warning(
131          'I-Spy expectation \'%s\' already exists, overwriting.',
132          expectation_with_version)
133    screenshots = [self._screenshot_func() for _ in range(8)]
134    logging.info('Generating I-Spy expectation...')
135    self._ispy.GenerateExpectation(expectation_with_version, screenshots)
136
137  def PerformComparison(self, test_run, device_type, expectation,
138                        chrome_version):
139    """Take a screenshot and compare it with the given expectation in I-Spy.
140
141    Args:
142      test_run: name for the test run.
143      device_type: string identifier for the device type.
144      expectation: name for the expectation to compare against.
145      chrome_version: the chrome version as a string of the form "31.0.123.4".
146    """
147    # 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...')
151    self._ispy.PerformComparison(
152        test_run,
153        self._GetExpectationNameWithVersion(
154            device_type, expectation, chrome_version),
155        screenshot)
156
157  def GetScriptToWaitForUnchangingDOM(self):
158    """Returns a JavaScript script that waits for the DOM to stop changing."""
159    return self._wait_for_unchanging_dom_script
160
161