1#!/usr/bin/env python 2# Copyright 2015 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import logging 7import os 8import shutil 9import stat 10import subprocess 11import sys 12import tempfile 13import time 14import urllib2 15import zipfile 16 17# URL on omahaproxy.appspot.com which lists cloud storage buckets. 18OMAHA_URL = 'https://omahaproxy.appspot.com/all?os=%s&channel=stable' 19 20# URL in cloud storage to download Chrome zip from. 21CLOUDSTORAGE_URL = ('https://commondatastorage.googleapis.com/chrome-unsigned' 22 '/desktop-W15K3Y/%s/%s/chrome-%s.zip') 23 24# Mapping of sys.platform -> platform-specific names and paths. 25PLATFORM_MAPPING = { 26 'linux2': { 27 'omaha': 'linux', 28 'cs_dir': 'precise64', 29 'cs_filename': 'precise64', 30 'chromepath': 'chrome-precise64/chrome', 31 'use_xfvb': True, 32 }, 33 'win32': { 34 'omaha': 'win', 35 'cs_dir': 'win', 36 'cs_filename': 'win', 37 'chromepath': 'Chrome-bin\\chrome.exe', 38 'installer_url': ('https://commondatastorage.googleapis.com/' 39 'chrome-signed/desktop-W15K3Y/%VERSION%/win/' 40 '%VERSION%_chrome_installer.exe'), 41 }, 42 'darwin': { 43 'omaha': 'mac', 44 'cs_dir': 'mac64', 45 'cs_filename': 'mac', 46 'chromepath': ('chrome-mac/Google Chrome.app/' 47 'Contents/MacOS/Google Chrome'), 48 'additional_paths': [ 49 ('chrome-mac/Google Chrome.app/Contents/Versions/%VERSION%/' 50 'Google Chrome Helper.app/Contents/MacOS/Google Chrome Helper'), 51 ], 52 }, 53} 54 55 56def StartXvfb(): 57 display = ':99' 58 xvfb_command = [ 59 'Xvfb', 60 display, 61 '-screen', 62 '0', 63 '1024x769x24', 64 '-ac' 65 ] 66 xvfb_process = subprocess.Popen( 67 xvfb_command, stdout=open(os.devnull), stderr=open(os.devnull)) 68 time.sleep(0.2) 69 returncode = xvfb_process.poll() 70 if returncode is None: 71 os.environ['DISPLAY'] = display 72 else: 73 logging.error('Xvfb did not start, returncode: %s', returncode) 74 75 76def IsDepotToolsPath(path): 77 return os.path.isfile(os.path.join(path, 'gclient')) 78 79 80def FindDepotTools(): 81 # Check if depot_tools is already in PYTHONPATH 82 for path in sys.path: 83 if path.rstrip(os.sep).endswith('depot_tools') and IsDepotToolsPath(path): 84 return path 85 86 # Check if depot_tools is in the path 87 for path in os.environ['PATH'].split(os.pathsep): 88 if IsDepotToolsPath(path): 89 return path.rstrip(os.sep) 90 91 return None 92 93 94def DownloadSignedWinChromeStable(url, version): 95 """On Windows, use signed Chrome since it may be more stable.""" 96 url = url.replace('%VERSION%', version) 97 tmpdir = tempfile.mkdtemp() 98 installer_path = os.path.join(tmpdir, url[url.rindex('/') + 1:]) 99 with open(installer_path, 'wb') as local_file: 100 local_file.write(urllib2.urlopen(url).read()) 101 depot_tools_path = FindDepotTools() 102 path_7z = os.path.join(depot_tools_path, 'win_toolchain', '7z', '7z.exe') 103 command_7z = [path_7z, 'x', '-o' + tmpdir, installer_path] 104 process_7z = subprocess.Popen( 105 command_7z, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 106 out_7z, err_7z = process_7z.communicate() 107 command_7z = [path_7z, 'x', '-o' + tmpdir, os.path.join(tmpdir, 'chrome.7z')] 108 process_7z = subprocess.Popen( 109 command_7z, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 110 out_7z, err_7z = process_7z.communicate() 111 return tmpdir, version 112 113 114def DownloadChromeStable(): 115 platform_data = PLATFORM_MAPPING[sys.platform] 116 omaha_platform = platform_data['omaha'] 117 omaha_url = OMAHA_URL % omaha_platform 118 response = urllib2.urlopen(omaha_url) 119 version = response.readlines()[1].split(',')[2] 120 if 'installer_url' in platform_data: 121 return DownloadSignedWinChromeStable( 122 platform_data['installer_url'], version) 123 cs_url = CLOUDSTORAGE_URL % ( 124 version, 125 platform_data['cs_dir'], 126 platform_data['cs_filename']) 127 tmpdir = tempfile.mkdtemp() 128 zip_path = os.path.join(tmpdir, 'chrome.zip') 129 with open(zip_path, 'wb') as local_file: 130 local_file.write(urllib2.urlopen(cs_url).read()) 131 zf = zipfile.ZipFile(zip_path) 132 zf.extractall(path=tmpdir) 133 return tmpdir, version 134 135 136def main(): 137 try: 138 platform_data = PLATFORM_MAPPING[sys.platform] 139 if platform_data.get('use_xfvb'): 140 StartXvfb() 141 user_data_dir = tempfile.mkdtemp() 142 tmpdir, version = DownloadChromeStable() 143 server_path = os.path.join(os.path.dirname( 144 os.path.abspath(__file__)), os.pardir, 'run_dev_server') 145 server_command = [server_path, '--no-install-hooks'] 146 if sys.platform.startswith('win'): 147 server_command = ['python.exe'] + server_command 148 server_process = subprocess.Popen( 149 server_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 150 time.sleep(5) 151 152 chrome_path = os.path.join( 153 tmpdir, platform_data['chromepath']) 154 os.chmod(chrome_path, os.stat(chrome_path).st_mode | stat.S_IEXEC) 155 if platform_data.get('additional_paths'): 156 for path in platform_data.get('additional_paths'): 157 path = path.replace('%VERSION%', version) 158 path = os.path.join(tmpdir, path) 159 os.chmod(path, os.stat(path).st_mode | stat.S_IEXEC) 160 chrome_command = [ 161 chrome_path, 162 '--user-data-dir=%s' % user_data_dir, 163 '--no-sandbox', 164 '--no-experiments', 165 '--no-first-run', 166 '--noerrdialogs', 167 'http://localhost:8003/base/tests.html?headless=true&testTypeToRun=all', 168 ] 169 chrome_process = subprocess.Popen( 170 chrome_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 171 server_out, server_err = server_process.communicate() 172 chrome_process.kill() 173 if server_process.returncode != 0: 174 logging.error('Tests failed!') 175 logging.error('Server stderr:') 176 logging.error(server_err) 177 logging.error('Server stdout:') 178 logging.error(server_out) 179 else: 180 print server_out 181 finally: 182 # Wait for Chrome to be killed before deleting temp Chrome dir. 183 time.sleep(5) 184 shutil.rmtree(tmpdir) 185 shutil.rmtree(user_data_dir) 186 187 sys.exit(server_process.returncode) 188 189 190 191if __name__ == "__main__": 192 main() 193