| #!/usr/bin/env python |
| # Copyright 2015 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import os |
| import shutil |
| import stat |
| import subprocess |
| import sys |
| import tempfile |
| import time |
| import urllib2 |
| import zipfile |
| |
| # URL on omahaproxy.appspot.com which lists cloud storage buckets. |
| OMAHA_URL = 'https://omahaproxy.appspot.com/all?os=%s&channel=stable' |
| |
| # URL in cloud storage to download Chrome zip from. |
| CLOUDSTORAGE_URL = ('https://commondatastorage.googleapis.com/chrome-unsigned' |
| '/desktop-W15K3Y/%s/%s/chrome-%s.zip') |
| |
| # Mapping of sys.platform -> platform-specific names and paths. |
| PLATFORM_MAPPING = { |
| 'linux2': { |
| 'omaha': 'linux', |
| 'cs_dir': 'precise64', |
| 'cs_filename': 'precise64', |
| 'chromepath': 'chrome-precise64/chrome', |
| 'use_xfvb': True, |
| }, |
| 'win32': { |
| 'omaha': 'win', |
| 'cs_dir': 'win', |
| 'cs_filename': 'win', |
| 'chromepath': 'Chrome-bin\\chrome.exe', |
| 'installer_url': ('https://commondatastorage.googleapis.com/' |
| 'chrome-signed/desktop-W15K3Y/%VERSION%/win/' |
| '%VERSION%_chrome_installer.exe'), |
| }, |
| 'darwin': { |
| 'omaha': 'mac', |
| 'cs_dir': 'mac64', |
| 'cs_filename': 'mac', |
| 'chromepath': ('chrome-mac/Google Chrome.app/' |
| 'Contents/MacOS/Google Chrome'), |
| 'additional_paths': [ |
| ('chrome-mac/Google Chrome.app/Contents/Versions/%VERSION%/' |
| 'Google Chrome Helper.app/Contents/MacOS/Google Chrome Helper'), |
| ], |
| }, |
| } |
| |
| |
| def StartXvfb(): |
| display = ':99' |
| xvfb_command = [ |
| 'Xvfb', |
| display, |
| '-screen', |
| '0', |
| '1024x769x24', |
| '-ac' |
| ] |
| xvfb_process = subprocess.Popen( |
| xvfb_command, stdout=open(os.devnull), stderr=open(os.devnull)) |
| time.sleep(0.2) |
| returncode = xvfb_process.poll() |
| if returncode is None: |
| os.environ['DISPLAY'] = display |
| else: |
| logging.error('Xvfb did not start, returncode: %s', returncode) |
| |
| |
| def IsDepotToolsPath(path): |
| return os.path.isfile(os.path.join(path, 'gclient')) |
| |
| |
| def FindDepotTools(): |
| # Check if depot_tools is already in PYTHONPATH |
| for path in sys.path: |
| if path.rstrip(os.sep).endswith('depot_tools') and IsDepotToolsPath(path): |
| return path |
| |
| # Check if depot_tools is in the path |
| for path in os.environ['PATH'].split(os.pathsep): |
| if IsDepotToolsPath(path): |
| return path.rstrip(os.sep) |
| |
| return None |
| |
| |
| def DownloadSignedWinChromeStable(url, version): |
| """On Windows, use signed Chrome since it may be more stable.""" |
| url = url.replace('%VERSION%', version) |
| tmpdir = tempfile.mkdtemp() |
| installer_path = os.path.join(tmpdir, url[url.rindex('/') + 1:]) |
| with open(installer_path, 'wb') as local_file: |
| local_file.write(urllib2.urlopen(url).read()) |
| depot_tools_path = FindDepotTools() |
| path_7z = os.path.join(depot_tools_path, 'win_toolchain', '7z', '7z.exe') |
| command_7z = [path_7z, 'x', '-o' + tmpdir, installer_path] |
| process_7z = subprocess.Popen( |
| command_7z, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| out_7z, err_7z = process_7z.communicate() |
| command_7z = [path_7z, 'x', '-o' + tmpdir, os.path.join(tmpdir, 'chrome.7z')] |
| process_7z = subprocess.Popen( |
| command_7z, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| out_7z, err_7z = process_7z.communicate() |
| return tmpdir, version |
| |
| |
| def DownloadChromeStable(): |
| platform_data = PLATFORM_MAPPING[sys.platform] |
| omaha_platform = platform_data['omaha'] |
| omaha_url = OMAHA_URL % omaha_platform |
| response = urllib2.urlopen(omaha_url) |
| version = response.readlines()[1].split(',')[2] |
| if 'installer_url' in platform_data: |
| return DownloadSignedWinChromeStable( |
| platform_data['installer_url'], version) |
| cs_url = CLOUDSTORAGE_URL % ( |
| version, |
| platform_data['cs_dir'], |
| platform_data['cs_filename']) |
| tmpdir = tempfile.mkdtemp() |
| zip_path = os.path.join(tmpdir, 'chrome.zip') |
| with open(zip_path, 'wb') as local_file: |
| local_file.write(urllib2.urlopen(cs_url).read()) |
| zf = zipfile.ZipFile(zip_path) |
| zf.extractall(path=tmpdir) |
| return tmpdir, version |
| |
| |
| def main(): |
| try: |
| platform_data = PLATFORM_MAPPING[sys.platform] |
| if platform_data.get('use_xfvb'): |
| StartXvfb() |
| user_data_dir = tempfile.mkdtemp() |
| tmpdir, version = DownloadChromeStable() |
| server_path = os.path.join(os.path.dirname( |
| os.path.abspath(__file__)), os.pardir, 'run_dev_server') |
| server_command = [server_path, '--no-install-hooks'] |
| if sys.platform.startswith('win'): |
| server_command = ['python.exe'] + server_command |
| server_process = subprocess.Popen( |
| server_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| time.sleep(5) |
| |
| chrome_path = os.path.join( |
| tmpdir, platform_data['chromepath']) |
| os.chmod(chrome_path, os.stat(chrome_path).st_mode | stat.S_IEXEC) |
| if platform_data.get('additional_paths'): |
| for path in platform_data.get('additional_paths'): |
| path = path.replace('%VERSION%', version) |
| path = os.path.join(tmpdir, path) |
| os.chmod(path, os.stat(path).st_mode | stat.S_IEXEC) |
| chrome_command = [ |
| chrome_path, |
| '--user-data-dir=%s' % user_data_dir, |
| '--no-sandbox', |
| '--no-experiments', |
| '--no-first-run', |
| '--noerrdialogs', |
| 'http://localhost:8003/base/tests.html?headless=true&testTypeToRun=all', |
| ] |
| chrome_process = subprocess.Popen( |
| chrome_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| server_out, server_err = server_process.communicate() |
| chrome_process.kill() |
| if server_process.returncode != 0: |
| logging.error('Tests failed!') |
| logging.error('Server stderr:') |
| logging.error(server_err) |
| logging.error('Server stdout:') |
| logging.error(server_out) |
| else: |
| print server_out |
| finally: |
| # Wait for Chrome to be killed before deleting temp Chrome dir. |
| time.sleep(5) |
| shutil.rmtree(tmpdir) |
| shutil.rmtree(user_data_dir) |
| |
| sys.exit(server_process.returncode) |
| |
| |
| |
| if __name__ == "__main__": |
| main() |