blob: 348fa6d82245d9dcdc90b9768105674f4cae5b80 [file] [log] [blame]
beepsbff9f9d2013-12-06 11:14:08 -08001#!/usr/bin/python
2# Copyright (c) 2013 The Chromium OS 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 httplib2
7import json
beeps023afc62014-02-04 16:59:22 -08008import logging
beepsbff9f9d2013-12-06 11:14:08 -08009import os
10import re
11import shutil
12import urllib2
13
14import common
15
beepsf860bd12014-01-23 18:06:06 -080016from autotest_lib.client.common_lib import autotemp
beepsbff9f9d2013-12-06 11:14:08 -080017from autotest_lib.client.common_lib import utils
18
beepsbff9f9d2013-12-06 11:14:08 -080019
20TEST_EXTENSION_ID = 'hfaagokkkhdbgiakmmlclaapfelnkoah'
21UPDATE_CHECK_URL = ('https://clients2.google.com/service/update2/')
22UPDATE_CHECK_PARAMETER = ('crx?x=id%%3D%s%%26v%%3D0%%26uc')
23MANIFEST_KEY = ('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+hlN5FB+tjCsBszmBIvI'
24 'cD/djLLQm2zZfFygP4U4/o++ZM91EWtgII10LisoS47qT2TIOg4Un4+G57e'
25 'lZ9PjEIhcJfANqkYrD3t9dpEzMNr936TLB2u683B5qmbB68Nq1Eel7KVc+F'
26 '0BqhBondDqhvDvGPEV0vBsbErJFlNH7SQIDAQAB')
27
28
beepsf860bd12014-01-23 18:06:06 -080029class SonicDownloaderException(Exception):
30 """Generic sonic dowloader exception."""
31 pass
32
33
beepsbff9f9d2013-12-06 11:14:08 -080034def get_download_url_from_omaha(extension_id):
35 """Retrieves an update url from omaha for the specified extension id.
36
37 @param extension_id: The extension id of the chromecast extension.
38
39 @return: A url to download the extension from.
40
41 @raises IOError: If the response returned by the omaha server is invalid.
42 """
43 update_check_link = '%s%s' % (UPDATE_CHECK_URL,
44 UPDATE_CHECK_PARAMETER % extension_id)
45 response_xml = httplib2.Http().request(update_check_link, 'GET')[1]
46 codebase_match = re.compile(r'codebase="(.*crx)"').search(response_xml)
47 if codebase_match is not None:
beeps023afc62014-02-04 16:59:22 -080048 logging.info('Omaha response while downloading extension: %s',
49 response_xml)
beepsbff9f9d2013-12-06 11:14:08 -080050 return codebase_match.groups()[0]
51 raise IOError('Omaha response is invalid %s.' % response_xml)
52
53
54def download_extension(dest_file):
55 """Retrieve the extension into a destination crx file.
56
57 @param dest_file: Path to a destination file for the extension.
58 """
59 download_url = get_download_url_from_omaha(TEST_EXTENSION_ID)
beeps023afc62014-02-04 16:59:22 -080060 logging.info('Downloading extension from %s', download_url)
beepsbff9f9d2013-12-06 11:14:08 -080061 response = urllib2.urlopen(download_url)
62 with open(dest_file, 'w') as f:
63 f.write(response.read())
64
65
66def fix_public_key(extracted_extension_folder):
67 """Modifies the manifest.json to include a public key.
68
69 This function will erase the content in the original manifest
70 and replace it with a new manifest that contains the key.
71
72 @param extracted_extension_folder: The folder containing
73 the extracted extension.
74 """
75 manifest_json_file = os.path.join(extracted_extension_folder,
76 'manifest.json')
77 with open(manifest_json_file, 'r') as f:
78 manifest_json = json.loads(f.read())
79
80 manifest_json['key'] = MANIFEST_KEY
81
82 with open(manifest_json_file, 'w') as f:
83 f.write(json.dumps(manifest_json))
84
85
beepsf860bd12014-01-23 18:06:06 -080086def setup_extension(unzipped_crx_dir):
beepsbff9f9d2013-12-06 11:14:08 -080087 """Setup for tests that need a chromecast extension.
88
89 Download the extension from an omaha server, unzip it and modify its
90 manifest.json to include a public key.
91
beepsf860bd12014-01-23 18:06:06 -080092 @param unzipped_crx_dir: Destination directory for the unzipped extension.
beepsbff9f9d2013-12-06 11:14:08 -080093
94 @raises CmdTimeoutError: If we timeout unzipping the extension.
95 """
beepsf860bd12014-01-23 18:06:06 -080096 output_crx_dir = autotemp.tempdir()
97 output_crx = os.path.join(output_crx_dir.name, 'sonic_extension.crx')
98 try:
99 download_extension(output_crx)
100 unzip_cmd = 'unzip -o "%s" -d "%s"' % (output_crx, unzipped_crx_dir)
beepsbff9f9d2013-12-06 11:14:08 -0800101
beepsf860bd12014-01-23 18:06:06 -0800102 # The unzip command will return a non-zero exit status if there are
103 # extra bytes at the start/end of the zipfile. This is not a critical
104 # failure and the extension will still work.
105 cmd_output = utils.run(unzip_cmd, ignore_status=True, timeout=1)
106 except Exception as e:
107 if os.path.exists(unzipped_crx_dir):
108 shutil.rmtree()
109 raise SonicDownloaderException(e)
110 finally:
111 if os.path.exists(output_crx):
112 os.remove(output_crx)
113 output_crx_dir.clean()
114
beepsbff9f9d2013-12-06 11:14:08 -0800115 if not os.path.exists(unzipped_crx_dir):
beepsf860bd12014-01-23 18:06:06 -0800116 raise SonicDownloaderException('Unable to download sonic extension.')
beeps023afc62014-02-04 16:59:22 -0800117 logging.info('Sonic extension successfully downloaded into %s.',
118 unzipped_crx_dir)
beepsbff9f9d2013-12-06 11:14:08 -0800119
120 # TODO(beeps): crbug.com/325869, investigate the limits of component
121 # extensions. For now this is ok because even sonic testing inlines a
122 # public key for their test extension.
beepsf860bd12014-01-23 18:06:06 -0800123 try:
124 fix_public_key(unzipped_crx_dir)
125 except Exception as e:
126 shutil.rmtree(unzipped_crx_dir)
127 raise SonicDownloaderException(e)