testing/marionette/update-smoketests/smoketest.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 import json
michael@0 6 import os
michael@0 7 import subprocess
michael@0 8 import sys
michael@0 9 import tempfile
michael@0 10 import threading
michael@0 11 import zipfile
michael@0 12
michael@0 13 from ConfigParser import ConfigParser
michael@0 14
michael@0 15 this_dir = os.path.abspath(os.path.dirname(__file__))
michael@0 16 marionette_dir = os.path.dirname(this_dir)
michael@0 17 marionette_client_dir = os.path.join(marionette_dir, 'client', 'marionette')
michael@0 18
michael@0 19 def find_b2g():
michael@0 20 sys.path.append(marionette_client_dir)
michael@0 21 from b2gbuild import B2GBuild
michael@0 22 return B2GBuild()
michael@0 23
michael@0 24 class DictObject(dict):
michael@0 25 def __getattr__(self, item):
michael@0 26 try:
michael@0 27 return self.__getitem__(item)
michael@0 28 except KeyError:
michael@0 29 raise AttributeError(item)
michael@0 30
michael@0 31 def __getitem__(self, item):
michael@0 32 value = dict.__getitem__(self, item)
michael@0 33 if isinstance(value, dict):
michael@0 34 return DictObject(value)
michael@0 35 return value
michael@0 36
michael@0 37 class SmokeTestError(Exception):
michael@0 38 pass
michael@0 39
michael@0 40 class SmokeTestConfigError(SmokeTestError):
michael@0 41 def __init__(self, message):
michael@0 42 SmokeTestError.__init__(self, 'smoketest-config.json: ' + message)
michael@0 43
michael@0 44 class SmokeTestConfig(DictObject):
michael@0 45 TOP_LEVEL_REQUIRED = ('devices', 'public_key', 'private_key')
michael@0 46 DEVICE_REQUIRED = ('system_fs_type', 'system_location', 'data_fs_type',
michael@0 47 'data_location', 'sdcard', 'sdcard_recovery',
michael@0 48 'serials')
michael@0 49
michael@0 50 def __init__(self, build_dir):
michael@0 51 self.top_dir = build_dir
michael@0 52 self.build_data = {}
michael@0 53 self.flash_template = None
michael@0 54
michael@0 55 with open(os.path.join(build_dir, 'smoketest-config.json')) as f:
michael@0 56 DictObject.__init__(self, json.loads(f.read()))
michael@0 57
michael@0 58 for required in self.TOP_LEVEL_REQUIRED:
michael@0 59 if required not in self:
michael@0 60 raise SmokeTestConfigError('No "%s" found' % required)
michael@0 61
michael@0 62 if len(self.devices) == 0:
michael@0 63 raise SmokeTestConfigError('No devices found')
michael@0 64
michael@0 65 for name, device in self.devices.iteritems():
michael@0 66 for required in self.DEVICE_REQUIRED:
michael@0 67 if required not in device:
michael@0 68 raise SmokeTestConfigError('No "%s" found in device "%s"' % (required, name))
michael@0 69
michael@0 70 def get_build_data(self, device, build_id):
michael@0 71 if device in self.build_data:
michael@0 72 if build_id in self.build_data[device]:
michael@0 73 return self.build_data[device][build_id]
michael@0 74 else:
michael@0 75 self.build_data[device] = {}
michael@0 76
michael@0 77 build_dir = os.path.join(self.top_dir, device, build_id)
michael@0 78 flash_zip = os.path.join(build_dir, 'flash.zip')
michael@0 79 with zipfile.ZipFile(flash_zip) as zip:
michael@0 80 app_ini = ConfigParser()
michael@0 81 app_ini.readfp(zip.open('system/b2g/application.ini'))
michael@0 82 platform_ini = ConfigParser()
michael@0 83 platform_ini.readfp(zip.open('system/b2g/platform.ini'))
michael@0 84
michael@0 85 build_data = self.build_data[device][build_id] = DictObject({
michael@0 86 'app_version': app_ini.get('App', 'version'),
michael@0 87 'app_build_id': app_ini.get('App', 'buildid'),
michael@0 88 'platform_build_id': platform_ini.get('Build', 'buildid'),
michael@0 89 'platform_milestone': platform_ini.get('Build', 'milestone'),
michael@0 90 'complete_mar': os.path.join(build_dir, 'complete.mar'),
michael@0 91 'flash_script': os.path.join(build_dir, 'flash.sh')
michael@0 92 })
michael@0 93
michael@0 94 return build_data
michael@0 95
michael@0 96 class SmokeTestRunner(object):
michael@0 97 DEVICE_TIMEOUT = 30
michael@0 98
michael@0 99 def __init__(self, config, b2g, run_dir=None):
michael@0 100 self.config = config
michael@0 101 self.b2g = b2g
michael@0 102 self.run_dir = run_dir or tempfile.mkdtemp()
michael@0 103
michael@0 104 update_tools = self.b2g.import_update_tools()
michael@0 105 self.b2g_config = update_tools.B2GConfig()
michael@0 106
michael@0 107 def run_b2g_update_test(self, serial, testvars, tests):
michael@0 108 b2g_update_test = os.path.join(marionette_client_dir,
michael@0 109 'venv_b2g_update_test.sh')
michael@0 110
michael@0 111 if not tests:
michael@0 112 tests = [os.path.join(marionette_client_dir, 'tests',
michael@0 113 'update-tests.ini')]
michael@0 114
michael@0 115 args = ['bash', b2g_update_test, sys.executable,
michael@0 116 '--homedir', self.b2g.homedir,
michael@0 117 '--address', 'localhost:2828',
michael@0 118 '--type', 'b2g+smoketest',
michael@0 119 '--device', serial,
michael@0 120 '--testvars', testvars]
michael@0 121 args.extend(tests)
michael@0 122
michael@0 123 print ' '.join(args)
michael@0 124 subprocess.check_call(args)
michael@0 125
michael@0 126 def build_testvars(self, device, start_id, finish_id):
michael@0 127 run_dir = os.path.join(self.run_dir, device, start_id, finish_id)
michael@0 128 if not os.path.exists(run_dir):
michael@0 129 os.makedirs(run_dir)
michael@0 130
michael@0 131 start_data = self.config.get_build_data(device, start_id)
michael@0 132 finish_data = self.config.get_build_data(device, finish_id)
michael@0 133
michael@0 134 partial_mar = os.path.join(run_dir, 'partial.mar')
michael@0 135 if not os.path.exists(partial_mar):
michael@0 136 build_gecko_mar = os.path.join(self.b2g.update_tools,
michael@0 137 'build-gecko-mar.py')
michael@0 138 subprocess.check_call([sys.executable, build_gecko_mar,
michael@0 139 '--from', start_data.complete_mar,
michael@0 140 '--to', finish_data.complete_mar,
michael@0 141 partial_mar])
michael@0 142 finish_data['partial_mar'] = partial_mar
michael@0 143
michael@0 144 testvars = os.path.join(run_dir, 'testvars.json')
michael@0 145 if not os.path.exists(testvars):
michael@0 146 open(testvars, 'w').write(json.dumps({
michael@0 147 'start': start_data,
michael@0 148 'finish': finish_data
michael@0 149 }))
michael@0 150
michael@0 151 return testvars
michael@0 152
michael@0 153 def wait_for_device(self, device):
michael@0 154 for serial in self.config.devices[device].serials:
michael@0 155 proc = subprocess.Popen([self.b2g.adb_path, '-s', serial,
michael@0 156 'wait-for-device'])
michael@0 157 def wait_for_adb():
michael@0 158 proc.communicate()
michael@0 159
michael@0 160 thread = threading.Thread(target=wait_for_adb)
michael@0 161 thread.start()
michael@0 162 thread.join(self.DEVICE_TIMEOUT)
michael@0 163
michael@0 164 if thread.isAlive():
michael@0 165 print >>sys.stderr, '%s device %s is not recognized by ADB, ' \
michael@0 166 'trying next device' % (device, serial)
michael@0 167 proc.kill()
michael@0 168 thread.join()
michael@0 169 continue
michael@0 170
michael@0 171 return serial
michael@0 172 return None
michael@0 173
michael@0 174 def run_smoketests_for_device(self, device, start_id, finish_id, tests):
michael@0 175 testvars = self.build_testvars(device, start_id, finish_id)
michael@0 176 serial = self.wait_for_device(device)
michael@0 177 if not serial:
michael@0 178 raise SmokeTestError('No connected serials for device "%s" could ' \
michael@0 179 'be found' % device)
michael@0 180
michael@0 181 try:
michael@0 182 self.run_b2g_update_test(serial, testvars, tests)
michael@0 183 except subprocess.CalledProcessError:
michael@0 184 print >>sys.stderr, 'SMOKETEST-FAIL | START=%s | FINISH=%s | ' \
michael@0 185 'DEVICE=%s/%s | %s' % (start_id, finish_id,
michael@0 186 device, serial, testvars)
michael@0 187
michael@0 188 def run_smoketests(self, build_ids, tests):
michael@0 189 build_ids.sort()
michael@0 190
michael@0 191 latest_build_id = build_ids.pop(-1)
michael@0 192 for build_id in build_ids:
michael@0 193 for device in self.config.devices:
michael@0 194 self.run_smoketests_for_device(device, build_id,
michael@0 195 latest_build_id, tests)

mercurial