| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 | |
| 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 """Dart2js buildbot steps | |
| 8 | |
| 9 Runs tests for the dart2js compiler. | |
| 10 """ | |
| 11 | |
| 12 import platform | |
| 13 import optparse | |
| 14 import os | |
| 15 import re | |
| 16 import shutil | |
| 17 import subprocess | |
| 18 import sys | |
| 19 | |
| 20 BUILDER_NAME = 'BUILDBOT_BUILDERNAME' | |
| 21 BUILDER_CLOBBER = 'BUILDBOT_CLOBBER' | |
| 22 | |
| 23 | |
| 24 DART_PATH = os.path.dirname( | |
| 25 os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| 26 | |
| 27 DART2JS_BUILDER = ( | |
| 28 r'dart2js-(linux|mac|windows)(-(jsshell))?-(debug|release)(-(checked|host-ch
ecked))?(-(host-checked))?-?(\d*)-?(\d*)') | |
| 29 WEB_BUILDER = ( | |
| 30 r'dart2js-(ie9|ie10|ff|safari|chrome|opera)-(win7|win8|mac|linux)(-(all|html
))?') | |
| 31 | |
| 32 NO_COLOR_ENV = dict(os.environ) | |
| 33 NO_COLOR_ENV['TERM'] = 'nocolor' | |
| 34 | |
| 35 class BuildInfo(object): | |
| 36 """ Encapsulation of build information. | |
| 37 - compiler: 'dart2js' or None when the builder has an incorrect name | |
| 38 - runtime: 'd8', 'ie', 'ff', 'safari', 'chrome', 'opera' | |
| 39 - mode: 'debug' or 'release' | |
| 40 - system: 'linux', 'mac', or 'win7' | |
| 41 - checked: True if we should run in checked mode, otherwise False | |
| 42 - host_checked: True if we should run in host checked mode, otherwise False | |
| 43 - shard_index: The shard we are running, None when not specified. | |
| 44 - total_shards: The total number of shards, None when not specified. | |
| 45 - is_buildbot: True if we are on a buildbot (or emulating it). | |
| 46 - test_set: Specification of a non standard test set, default None | |
| 47 """ | |
| 48 def __init__(self, compiler, runtime, mode, system, checked=False, | |
| 49 host_checked=False, shard_index=None, total_shards=None, | |
| 50 is_buildbot=False, test_set=None): | |
| 51 self.compiler = compiler | |
| 52 self.runtime = runtime | |
| 53 self.mode = mode | |
| 54 self.system = system | |
| 55 self.checked = checked | |
| 56 self.host_checked = host_checked | |
| 57 self.shard_index = shard_index | |
| 58 self.total_shards = total_shards | |
| 59 self.is_buildbot = is_buildbot | |
| 60 self.test_set = test_set | |
| 61 | |
| 62 def PrintBuildInfo(self): | |
| 63 shard_description = "" | |
| 64 if self.shard_index: | |
| 65 shard_description = " shard %s of %s" % (self.shard_index, | |
| 66 self.total_shards) | |
| 67 print ("compiler: %s, runtime: %s mode: %s, system: %s," | |
| 68 " checked: %s, host-checked: %s, test-set: %s%s" | |
| 69 ) % (self.compiler, self.runtime, self.mode, self.system, | |
| 70 self.checked, self.host_checked, self.test_set, | |
| 71 shard_description) | |
| 72 | |
| 73 | |
| 74 def GetBuildInfo(): | |
| 75 """Returns a BuildInfo object for the current buildbot based on the | |
| 76 name of the builder. | |
| 77 """ | |
| 78 parser = optparse.OptionParser() | |
| 79 parser.add_option('-n', '--name', dest='name', help='The name of the build' | |
| 80 'bot you would like to emulate (ex: web-chrome-win7)', default=None) | |
| 81 args, _ = parser.parse_args() | |
| 82 | |
| 83 compiler = None | |
| 84 runtime = None | |
| 85 mode = None | |
| 86 system = None | |
| 87 builder_name = os.environ.get(BUILDER_NAME) | |
| 88 checked = False | |
| 89 host_checked = False | |
| 90 shard_index = None | |
| 91 total_shards = None | |
| 92 is_buildbot = True | |
| 93 test_set = None | |
| 94 | |
| 95 if not builder_name: | |
| 96 # We are not running on a buildbot. | |
| 97 is_buildbot = False | |
| 98 if args.name: | |
| 99 builder_name = args.name | |
| 100 else: | |
| 101 print 'Use -n $BUILDBOT_NAME for the bot you would like to emulate.' | |
| 102 sys.exit(1) | |
| 103 | |
| 104 if builder_name: | |
| 105 dart2js_pattern = re.match(DART2JS_BUILDER, builder_name) | |
| 106 web_pattern = re.match(WEB_BUILDER, builder_name) | |
| 107 | |
| 108 if web_pattern: | |
| 109 compiler = 'dart2js' | |
| 110 runtime = web_pattern.group(1) | |
| 111 system = web_pattern.group(2) | |
| 112 mode = 'release' | |
| 113 test_set = web_pattern.group(4) | |
| 114 elif dart2js_pattern: | |
| 115 compiler = 'dart2js' | |
| 116 system = dart2js_pattern.group(1) | |
| 117 runtime = 'd8' | |
| 118 if dart2js_pattern.group(3) == 'jsshell': | |
| 119 runtime = 'jsshell' | |
| 120 mode = dart2js_pattern.group(4) | |
| 121 # The valid naming parts for checked and host-checked are: | |
| 122 # Empty: checked=False, host_checked=False | |
| 123 # -checked: checked=True, host_checked=False | |
| 124 # -host-checked: checked=False, host_checked=True | |
| 125 # -checked-host-checked: checked=True, host_checked=True | |
| 126 if dart2js_pattern.group(6) == 'checked': | |
| 127 checked = True | |
| 128 if dart2js_pattern.group(6) == 'host-checked': | |
| 129 host_checked = True | |
| 130 if dart2js_pattern.group(8) == 'host-checked': | |
| 131 host_checked = True | |
| 132 shard_index = dart2js_pattern.group(9) | |
| 133 total_shards = dart2js_pattern.group(10) | |
| 134 | |
| 135 if system == 'windows': | |
| 136 system = 'win7' | |
| 137 | |
| 138 if (system == 'win7' and platform.system() != 'Windows') or ( | |
| 139 system == 'mac' and platform.system() != 'Darwin') or ( | |
| 140 system == 'linux' and platform.system() != 'Linux'): | |
| 141 print ('Error: You cannot emulate a buildbot with a platform different ' | |
| 142 'from your own.') | |
| 143 sys.exit(1) | |
| 144 return BuildInfo(compiler, runtime, mode, system, checked, host_checked, | |
| 145 shard_index, total_shards, is_buildbot, test_set) | |
| 146 | |
| 147 | |
| 148 def NeedsXterm(compiler, runtime): | |
| 149 return runtime in ['ie', 'chrome', 'safari', 'opera', 'ff', 'drt'] | |
| 150 | |
| 151 | |
| 152 def TestStepName(name, flags): | |
| 153 # Filter out flags with '=' as this breaks the /stats feature of the | |
| 154 # build bot. | |
| 155 flags = [x for x in flags if not '=' in x] | |
| 156 return ('%s tests %s' % (name, ' '.join(flags))).strip() | |
| 157 | |
| 158 | |
| 159 def TestStep(name, mode, system, compiler, runtime, targets, flags): | |
| 160 step_name = TestStepName(name, flags) | |
| 161 print '@@@BUILD_STEP %s@@@' % step_name | |
| 162 sys.stdout.flush() | |
| 163 if NeedsXterm(compiler, runtime) and system == 'linux': | |
| 164 cmd = ['xvfb-run', '-a'] | |
| 165 else: | |
| 166 cmd = [] | |
| 167 | |
| 168 user_test = os.environ.get('USER_TEST', 'no') | |
| 169 | |
| 170 cmd.extend([sys.executable, | |
| 171 os.path.join(os.curdir, 'tools', 'test.py'), | |
| 172 '--step_name=' + step_name, | |
| 173 '--mode=' + mode, | |
| 174 '--compiler=' + compiler, | |
| 175 '--runtime=' + runtime, | |
| 176 '--time', | |
| 177 '--use-sdk', | |
| 178 '--report']) | |
| 179 | |
| 180 if user_test == 'yes': | |
| 181 cmd.append('--progress=color') | |
| 182 else: | |
| 183 cmd.extend(['--progress=buildbot', '-v']) | |
| 184 | |
| 185 if flags: | |
| 186 cmd.extend(flags) | |
| 187 cmd.extend(targets) | |
| 188 | |
| 189 print 'running %s' % (' '.join(cmd)) | |
| 190 exit_code = subprocess.call(cmd, env=NO_COLOR_ENV) | |
| 191 if exit_code != 0: | |
| 192 print '@@@STEP_FAILURE@@@' | |
| 193 return exit_code | |
| 194 | |
| 195 | |
| 196 def BuildSDK(mode, system): | |
| 197 """ build the SDK. | |
| 198 Args: | |
| 199 - mode: either 'debug' or 'release' | |
| 200 - system: either 'linux', 'mac', or 'win7' | |
| 201 """ | |
| 202 os.chdir(DART_PATH) | |
| 203 | |
| 204 args = [sys.executable, './tools/build.py', '--mode=' + mode, 'create_sdk'] | |
| 205 print 'running %s' % (' '.join(args)) | |
| 206 return subprocess.call(args, env=NO_COLOR_ENV) | |
| 207 | |
| 208 | |
| 209 def TestCompiler(runtime, mode, system, flags, is_buildbot, test_set): | |
| 210 """ test the compiler. | |
| 211 Args: | |
| 212 - runtime: either 'd8', 'jsshell', or one of the browsers, see GetBuildInfo | |
| 213 - mode: either 'debug' or 'release' | |
| 214 - system: either 'linux', 'mac', or 'win7' | |
| 215 - flags: extra flags to pass to test.dart | |
| 216 - is_buildbot: true if we are running on a real buildbot instead of | |
| 217 emulating one. | |
| 218 - test_set: Specification of a non standard test set, default None | |
| 219 """ | |
| 220 | |
| 221 # Make sure we are in the dart directory | |
| 222 os.chdir(DART_PATH) | |
| 223 | |
| 224 if system.startswith('win') and runtime == 'ie': | |
| 225 # There should not be more than one InternetExplorerDriver instance | |
| 226 # running at a time. For details, see | |
| 227 # http://code.google.com/p/selenium/wiki/InternetExplorerDriver. | |
| 228 flags += ['-j1'] | |
| 229 | |
| 230 def GetPath(runtime): | |
| 231 """ Helper to get the path to the Chrome or Firefox executable for a | |
| 232 particular platform on the buildbot. Throws a KeyError if runtime is not | |
| 233 either 'chrome' or 'ff'.""" | |
| 234 if system == 'mac': | |
| 235 partDict = {'chrome': 'Google\\ Chrome', 'ff': 'Firefox'} | |
| 236 mac_path = '/Applications/%s.app/Contents/MacOS/%s' | |
| 237 path_dict = {'chrome': mac_path % (partDict[runtime], partDict[runtime]), | |
| 238 'ff': mac_path % (partDict[runtime], partDict[runtime].lower())} | |
| 239 elif system == 'linux': | |
| 240 path_dict = {'ff': 'firefox', 'chrome': 'google-chrome'} | |
| 241 else: | |
| 242 # Windows. | |
| 243 path_dict = {'ff': os.path.join('C:/', 'Program Files (x86)', | |
| 244 'Mozilla Firefox', 'firefox.exe'), | |
| 245 'chrome': os.path.join('C:/', 'Users', 'chrome-bot', 'AppData', | |
| 246 'Local', 'Google', 'Chrome', 'Application', 'chrome.exe')} | |
| 247 return path_dict[runtime] | |
| 248 | |
| 249 if system == 'linux' and runtime == 'chrome': | |
| 250 # TODO(ngeoffray): We should install selenium on the buildbot. | |
| 251 runtime = 'drt' | |
| 252 elif (runtime == 'ff' or runtime == 'chrome') and is_buildbot: | |
| 253 # Print out browser version numbers if we're running on the buildbot (where | |
| 254 # we know the paths to these browser installations). | |
| 255 version_query_string = '"%s" --version' % GetPath(runtime) | |
| 256 if runtime == 'ff' and system == 'win7': | |
| 257 version_query_string += '| more' | |
| 258 elif runtime == 'chrome' and system == 'win7': | |
| 259 version_query_string = ('''reg query "HKCU\\Software\\Microsoft\\''' + | |
| 260 '''Windows\\CurrentVersion\\Uninstall\\Google Chrome" /v Version''') | |
| 261 p = subprocess.Popen(version_query_string, | |
| 262 stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) | |
| 263 output, stderr = p.communicate() | |
| 264 output = output.split() | |
| 265 try: | |
| 266 print 'Version of %s: %s' % (runtime, output[-1]) | |
| 267 except IndexError: | |
| 268 # Failed to obtain version information. Continue running tests. | |
| 269 pass | |
| 270 | |
| 271 if runtime == 'd8': | |
| 272 # The dart2js compiler isn't self-hosted (yet) so we run its | |
| 273 # unit tests on the VM. We avoid doing this on the builders | |
| 274 # that run the browser tests to cut down on the cycle time. | |
| 275 TestStep("dart2js_unit", mode, system, 'none', 'vm', ['dart2js'], flags) | |
| 276 | |
| 277 if not (system.startswith('win') and runtime == 'ie'): | |
| 278 # Run the default set of test suites. | |
| 279 TestStep("dart2js", mode, system, 'dart2js', runtime, [], flags) | |
| 280 | |
| 281 # TODO(kasperl): Consider running peg and css tests too. | |
| 282 extras = ['dart2js_extra', 'dart2js_native', 'dart2js_foreign'] | |
| 283 TestStep("dart2js_extra", mode, system, 'dart2js', runtime, extras, flags) | |
| 284 else: | |
| 285 # TODO(ricow): Enable standard sharding for IE bots when we have more vms. | |
| 286 if test_set == 'html': | |
| 287 TestStep("dart2js", mode, system, 'dart2js', runtime, ['html'], flags) | |
| 288 elif test_set == 'all': | |
| 289 TestStep("dart2js", mode, system, 'dart2js', runtime, ['dartc', | |
| 290 'samples', 'standalone', 'corelib', 'co19', 'language', 'isolate', | |
| 291 'vm', 'json', 'benchmark_smoke', 'dartdoc', 'utils', 'pub', 'lib'], | |
| 292 flags) | |
| 293 extras = ['dart2js_extra', 'dart2js_native', 'dart2js_foreign'] | |
| 294 TestStep("dart2js_extra", mode, system, 'dart2js', runtime, extras, | |
| 295 flags) | |
| 296 | |
| 297 return 0 | |
| 298 | |
| 299 def _DeleteTempWebdriverProfiles(directory): | |
| 300 """Find all the firefox profiles in a particular directory and delete them.""" | |
| 301 for f in os.listdir(directory): | |
| 302 item = os.path.join(directory, f) | |
| 303 if os.path.isdir(item) and (f.startswith('tmp') or f.startswith('opera')): | |
| 304 subprocess.Popen('rm -rf %s' % item, shell=True) | |
| 305 | |
| 306 def CleanUpTemporaryFiles(system, browser): | |
| 307 """For some browser (selenium) tests, the browser creates a temporary profile | |
| 308 on each browser session start. On Windows, generally these files are | |
| 309 automatically deleted when all python processes complete. However, since our | |
| 310 buildbot slave script also runs on python, we never get the opportunity to | |
| 311 clear out the temp files, so we do so explicitly here. Our batch browser | |
| 312 testing will make this problem occur much less frequently, but will still | |
| 313 happen eventually unless we do this. | |
| 314 | |
| 315 This problem also occurs with batch tests in Firefox. For some reason selenium | |
| 316 automatically deletes the temporary profiles for Firefox for one browser, | |
| 317 but not multiple ones when we have many open batch tasks running. This | |
| 318 behavior has not been reproduced outside of the buildbots. | |
| 319 | |
| 320 Args: | |
| 321 - system: either 'linux', 'mac', or 'win7' | |
| 322 - browser: one of the browsers, see GetBuildInfo | |
| 323 """ | |
| 324 if system == 'win7': | |
| 325 shutil.rmtree('C:\\Users\\chrome-bot\\AppData\\Local\\Temp', | |
| 326 ignore_errors=True) | |
| 327 elif browser == 'ff' or 'opera': | |
| 328 # Note: the buildbots run as root, so we can do this without requiring a | |
| 329 # password. The command won't actually work on regular machines without | |
| 330 # root permissions. | |
| 331 _DeleteTempWebdriverProfiles('/tmp') | |
| 332 _DeleteTempWebdriverProfiles('/var/tmp') | |
| 333 | |
| 334 def ClobberBuilder(mode): | |
| 335 """ Clobber the builder before we do the build. | |
| 336 Args: | |
| 337 - mode: either 'debug' or 'release' | |
| 338 """ | |
| 339 cmd = [sys.executable, | |
| 340 './tools/clean_output_directory.py', | |
| 341 '--mode=' + mode] | |
| 342 print 'Clobbering %s' % (' '.join(cmd)) | |
| 343 return subprocess.call(cmd, env=NO_COLOR_ENV) | |
| 344 | |
| 345 def GetShouldClobber(): | |
| 346 return os.environ.get(BUILDER_CLOBBER) == "1" | |
| 347 | |
| 348 def GetHasHardCodedCheckedMode(build_info): | |
| 349 # TODO(ricow): We currently run checked mode tests on chrome on linux and | |
| 350 # on the slow (all) IE windows bots. This is a hack and we should use the | |
| 351 # normal sharding and checked splitting functionality when we get more | |
| 352 # vms for testing this. | |
| 353 if (build_info.system == 'linux' and build_info.runtime == 'chrome'): | |
| 354 return True | |
| 355 if (build_info.system == 'win7' and build_info.runtime == 'ie' and | |
| 356 build_info.test_set == 'all'): | |
| 357 return True | |
| 358 return False | |
| 359 | |
| 360 def main(): | |
| 361 if len(sys.argv) == 0: | |
| 362 print 'Script pathname not known, giving up.' | |
| 363 return 1 | |
| 364 | |
| 365 build_info = GetBuildInfo() | |
| 366 | |
| 367 # Print out the buildinfo for easy debugging. | |
| 368 build_info.PrintBuildInfo() | |
| 369 | |
| 370 if build_info.compiler is None: | |
| 371 return 1 | |
| 372 | |
| 373 if GetShouldClobber(): | |
| 374 print '@@@BUILD_STEP Clobber@@@' | |
| 375 status = ClobberBuilder(build_info.mode) | |
| 376 if status != 0: | |
| 377 print '@@@STEP_FAILURE@@@' | |
| 378 return status | |
| 379 | |
| 380 print '@@@BUILD_STEP build sdk@@@' | |
| 381 status = BuildSDK(build_info.mode, build_info.system) | |
| 382 if status != 0: | |
| 383 print '@@@STEP_FAILURE@@@' | |
| 384 return status | |
| 385 | |
| 386 test_flags = [] | |
| 387 if build_info.shard_index: | |
| 388 test_flags = ['--shards=%s' % build_info.total_shards, | |
| 389 '--shard=%s' % build_info.shard_index] | |
| 390 | |
| 391 if build_info.checked: test_flags += ['--checked'] | |
| 392 | |
| 393 if build_info.host_checked: test_flags += ['--host-checked'] | |
| 394 | |
| 395 status = TestCompiler(build_info.runtime, build_info.mode, | |
| 396 build_info.system, list(test_flags), | |
| 397 build_info.is_buildbot, build_info.test_set) | |
| 398 | |
| 399 # See comment in GetHasHardCodedCheckedMode, this is a hack. | |
| 400 if (status == 0 and GetHasHardCodedCheckedMode(build_info)): | |
| 401 status = TestCompiler(build_info.runtime, build_info.mode, | |
| 402 build_info.system, | |
| 403 test_flags + ['--checked'], | |
| 404 build_info.is_buildbot, | |
| 405 build_info.test_set) | |
| 406 | |
| 407 if build_info.runtime != 'd8': CleanUpTemporaryFiles(build_info.system, | |
| 408 build_info.runtime) | |
| 409 if status != 0: print '@@@STEP_FAILURE@@@' | |
| 410 return status | |
| 411 | |
| 412 if __name__ == '__main__': | |
| 413 sys.exit(main()) | |
| OLD | NEW |