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