Home | History | Annotate | Download | only in build
      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 
      6 import logging
      7 import os
      8 import shutil
      9 import stat
     10 import subprocess
     11 import sys
     12 import tempfile
     13 import time
     14 import urllib2
     15 import zipfile
     16 
     17 # URL on omahaproxy.appspot.com which lists cloud storage buckets.
     18 OMAHA_URL = 'https://omahaproxy.appspot.com/all?os=%s&channel=stable'
     19 
     20 # URL in cloud storage to download Chrome zip from.
     21 CLOUDSTORAGE_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.
     25 PLATFORM_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 
     56 def 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 
     76 def IsDepotToolsPath(path):
     77   return os.path.isfile(os.path.join(path, 'gclient'))
     78 
     79 
     80 def 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 
     94 def 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 
    114 def 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 
    136 def 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 
    191 if __name__ == "__main__":
    192     main()
    193