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