1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4""" 5These transforms construct a task description to run the given test, based on a 6test description. The implementation here is shared among all test kinds, but 7contains specific support for how we run tests in Gecko (via mozharness, 8invoked in particular ways). 9 10This is a good place to translate a test-description option such as 11`single-core: true` to the implementation of that option in a task description 12(worker options, mozharness commandline, environment variables, etc.) 13 14The test description should be fully formed by the time it reaches these 15transforms, and these transforms should not embody any specific knowledge about 16what should run where. this is the wrong place for special-casing platforms, 17for example - use `all_tests.py` instead. 18""" 19 20from __future__ import absolute_import, print_function, unicode_literals 21 22from taskgraph.transforms.base import TransformSequence 23from taskgraph.util.schema import resolve_keyed_by, OptimizationSchema 24from taskgraph.util.treeherder import split_symbol, join_symbol, add_suffix 25from taskgraph.util.platforms import platform_family 26from taskgraph.util.schema import ( 27 optionally_keyed_by, 28 Schema, 29) 30from taskgraph.util.taskcluster import get_artifact_path 31from mozbuild.schedules import INCLUSIVE_COMPONENTS 32 33from voluptuous import ( 34 Any, 35 Optional, 36 Required, 37 Exclusive, 38) 39 40import copy 41import logging 42 43# default worker types keyed by instance-size 44LINUX_WORKER_TYPES = { 45 'large': 'aws-provisioner-v1/gecko-t-linux-large', 46 'xlarge': 'aws-provisioner-v1/gecko-t-linux-xlarge', 47 'default': 'aws-provisioner-v1/gecko-t-linux-large', 48} 49 50# windows worker types keyed by test-platform and virtualization 51WINDOWS_WORKER_TYPES = { 52 'windows7-32': { 53 'virtual': 'aws-provisioner-v1/gecko-t-win7-32', 54 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu', 55 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 56 }, 57 'windows7-32-pgo': { 58 'virtual': 'aws-provisioner-v1/gecko-t-win7-32', 59 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu', 60 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 61 }, 62 'windows7-32-nightly': { 63 'virtual': 'aws-provisioner-v1/gecko-t-win7-32', 64 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu', 65 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 66 }, 67 'windows7-32-devedition': { 68 'virtual': 'aws-provisioner-v1/gecko-t-win7-32', 69 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win7-32-gpu', 70 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 71 }, 72 'windows10-64': { 73 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 74 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 75 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 76 }, 77 'windows10-64-ccov': { 78 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 79 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 80 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 81 }, 82 'windows10-64-pgo': { 83 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 84 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 85 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 86 }, 87 'windows10-64-devedition': { 88 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 89 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 90 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 91 }, 92 'windows10-64-nightly': { 93 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 94 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 95 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 96 }, 97 'windows10-64-asan': { 98 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 99 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 100 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 101 }, 102 'windows10-64-qr': { 103 'virtual': 'aws-provisioner-v1/gecko-t-win10-64', 104 'virtual-with-gpu': 'aws-provisioner-v1/gecko-t-win10-64-gpu', 105 'hardware': 'releng-hardware/gecko-t-win10-64-hw', 106 }, 107} 108 109# os x worker types keyed by test-platform 110MACOSX_WORKER_TYPES = { 111 'macosx64': 'releng-hardware/gecko-t-osx-1010', 112} 113 114logger = logging.getLogger(__name__) 115 116transforms = TransformSequence() 117 118# Schema for a test description 119# 120# *****WARNING***** 121# 122# This is a great place for baffling cruft to accumulate, and that makes 123# everyone move more slowly. Be considerate of your fellow hackers! 124# See the warnings in taskcluster/docs/how-tos.rst 125# 126# *****WARNING***** 127test_description_schema = Schema({ 128 # description of the suite, for the task metadata 129 'description': basestring, 130 131 # test suite name, or <suite>/<flavor> 132 Required('suite'): optionally_keyed_by( 133 'test-platform', 134 basestring), 135 136 # the name by which this test suite is addressed in try syntax; defaults to 137 # the test-name. This will translate to the `unittest_try_name` or 138 # `talos_try_name` attribute. 139 Optional('try-name'): basestring, 140 141 # additional tags to mark up this type of test 142 Optional('tags'): {basestring: object}, 143 144 # the symbol, or group(symbol), under which this task should appear in 145 # treeherder. 146 'treeherder-symbol': basestring, 147 148 # the value to place in task.extra.treeherder.machine.platform; ideally 149 # this is the same as build-platform, and that is the default, but in 150 # practice it's not always a match. 151 Optional('treeherder-machine-platform'): basestring, 152 153 # attributes to appear in the resulting task (later transforms will add the 154 # common attributes) 155 Optional('attributes'): {basestring: object}, 156 157 # relative path (from config.path) to the file task was defined in 158 Optional('job-from'): basestring, 159 160 # The `run_on_projects` attribute, defaulting to "all". This dictates the 161 # projects on which this task should be included in the target task set. 162 # See the attributes documentation for details. 163 # 164 # Note that the special case 'built-projects', the default, uses the parent 165 # build task's run-on-projects, meaning that tests run only on platforms 166 # that are built. 167 Optional('run-on-projects'): optionally_keyed_by( 168 'test-platform', 169 Any([basestring], 'built-projects')), 170 171 # the sheriffing tier for this task (default: set based on test platform) 172 Optional('tier'): optionally_keyed_by( 173 'test-platform', 174 Any(int, 'default')), 175 176 # number of chunks to create for this task. This can be keyed by test 177 # platform by passing a dictionary in the `by-test-platform` key. If the 178 # test platform is not found, the key 'default' will be tried. 179 Required('chunks'): optionally_keyed_by( 180 'test-platform', 181 int), 182 183 # the time (with unit) after which this task is deleted; default depends on 184 # the branch (see below) 185 Optional('expires-after'): basestring, 186 187 # Whether to run this task with e10s (desktop-test only). If false, run 188 # without e10s; if true, run with e10s; if 'both', run one task with and 189 # one task without e10s. E10s tasks have "-e10s" appended to the test name 190 # and treeherder group. 191 Required('e10s'): optionally_keyed_by( 192 'test-platform', 'project', 193 Any(bool, 'both')), 194 195 # Whether the task should run with WebRender enabled or not. 196 Optional('webrender'): bool, 197 198 # The EC2 instance size to run these tests on. 199 Required('instance-size'): optionally_keyed_by( 200 'test-platform', 201 Any('default', 'large', 'xlarge')), 202 203 # type of virtualization or hardware required by test. 204 Required('virtualization'): optionally_keyed_by( 205 'test-platform', 206 Any('virtual', 'virtual-with-gpu', 'hardware')), 207 208 # Whether the task requires loopback audio or video (whatever that may mean 209 # on the platform) 210 Required('loopback-audio'): bool, 211 Required('loopback-video'): bool, 212 213 # Whether the test can run using a software GL implementation on Linux 214 # using the GL compositor. May not be used with "legacy" sized instances 215 # due to poor LLVMPipe performance (bug 1296086). Defaults to true for 216 # unit tests on linux platforms and false otherwise 217 Optional('allow-software-gl-layers'): bool, 218 219 # For tasks that will run in docker-worker or docker-engine, this is the 220 # name of the docker image or in-tree docker image to run the task in. If 221 # in-tree, then a dependency will be created automatically. This is 222 # generally `desktop-test`, or an image that acts an awful lot like it. 223 Required('docker-image'): optionally_keyed_by( 224 'test-platform', 225 Any( 226 # a raw Docker image path (repo/image:tag) 227 basestring, 228 # an in-tree generated docker image (from `taskcluster/docker/<name>`) 229 {'in-tree': basestring}, 230 # an indexed docker image 231 {'indexed': basestring}, 232 ) 233 ), 234 235 # seconds of runtime after which the task will be killed. Like 'chunks', 236 # this can be keyed by test pltaform. 237 Required('max-run-time'): optionally_keyed_by( 238 'test-platform', 239 int), 240 241 # the exit status code that indicates the task should be retried 242 Optional('retry-exit-status'): [int], 243 244 # Whether to perform a gecko checkout. 245 Required('checkout'): bool, 246 247 # Wheter to perform a machine reboot after test is done 248 Optional('reboot'): 249 Any(False, 'always', 'on-exception', 'on-failure'), 250 251 # What to run 252 Required('mozharness'): { 253 # the mozharness script used to run this task 254 Required('script'): optionally_keyed_by( 255 'test-platform', 256 basestring), 257 258 # the config files required for the task 259 Required('config'): optionally_keyed_by( 260 'test-platform', 261 [basestring]), 262 263 # mochitest flavor for mochitest runs 264 Optional('mochitest-flavor'): basestring, 265 266 # any additional actions to pass to the mozharness command 267 Optional('actions'): [basestring], 268 269 # additional command-line options for mozharness, beyond those 270 # automatically added 271 Required('extra-options'): optionally_keyed_by( 272 'test-platform', 273 [basestring]), 274 275 # the artifact name (including path) to test on the build task; this is 276 # generally set in a per-kind transformation 277 Optional('build-artifact-name'): basestring, 278 279 # If true, tooltool downloads will be enabled via relengAPIProxy. 280 Required('tooltool-downloads'): bool, 281 282 # Add --blob-upload-branch=<project> mozharness parameter 283 Optional('include-blob-upload-branch'): bool, 284 285 # The setting for --download-symbols (if omitted, the option will not 286 # be passed to mozharness) 287 Optional('download-symbols'): Any(True, 'ondemand'), 288 289 # If set, then MOZ_NODE_PATH=/usr/local/bin/node is included in the 290 # environment. This is more than just a helpful path setting -- it 291 # causes xpcshell tests to start additional servers, and runs 292 # additional tests. 293 Required('set-moz-node-path'): bool, 294 295 # If true, include chunking information in the command even if the number 296 # of chunks is 1 297 Required('chunked'): optionally_keyed_by( 298 'test-platform', 299 bool), 300 301 # The chunking argument format to use 302 Required('chunking-args'): Any( 303 # Use the usual --this-chunk/--total-chunk arguments 304 'this-chunk', 305 # Use --test-suite=<suite>-<chunk-suffix>; see chunk-suffix, below 306 'test-suite-suffix', 307 ), 308 309 # the string to append to the `--test-suite` arugment when 310 # chunking-args = test-suite-suffix; "<CHUNK>" in this string will 311 # be replaced with the chunk number. 312 Optional('chunk-suffix'): basestring, 313 314 Required('requires-signed-builds'): optionally_keyed_by( 315 'test-platform', 316 bool), 317 }, 318 319 # The current chunk; this is filled in by `all_kinds.py` 320 Optional('this-chunk'): int, 321 322 # os user groups for test task workers; required scopes, will be 323 # added automatically 324 Optional('os-groups'): optionally_keyed_by( 325 'test-platform', 326 [basestring]), 327 328 Optional('run-as-administrator'): optionally_keyed_by( 329 'test-platform', 330 bool), 331 332 # -- values supplied by the task-generation infrastructure 333 334 # the platform of the build this task is testing 335 'build-platform': basestring, 336 337 # the label of the build task generating the materials to test 338 'build-label': basestring, 339 340 # the label of the signing task generating the materials to test. 341 # Signed builds are used in xpcshell tests on Windows, for instance. 342 Optional('build-signing-label'): basestring, 343 344 # the build's attributes 345 'build-attributes': {basestring: object}, 346 347 # the platform on which the tests will run 348 'test-platform': basestring, 349 350 # the name of the test (the key in tests.yml) 351 'test-name': basestring, 352 353 # the product name, defaults to firefox 354 Optional('product'): basestring, 355 356 # conditional files to determine when these tests should be run 357 Exclusive(Optional('when'), 'optimization'): { 358 Optional('files-changed'): [basestring], 359 }, 360 361 # Optimization to perform on this task during the optimization phase. 362 # Optimizations are defined in taskcluster/taskgraph/optimize.py. 363 Exclusive(Optional('optimization'), 'optimization'): OptimizationSchema, 364 365 # The SCHEDULES component for this task; this defaults to the suite 366 # (not including the flavor) but can be overridden here. 367 Exclusive(Optional('schedules-component'), 'optimization'): basestring, 368 369 Optional('worker-type'): optionally_keyed_by( 370 'test-platform', 371 Any(basestring, None), 372 ), 373 374 Optional( 375 'require-signed-extensions', 376 description="Whether the build being tested requires extensions be signed.", 377 ): optionally_keyed_by('release-type', 'test-platform', bool), 378 379 # The target name, specifying the build artifact to be tested. 380 # If None or not specified, a transform sets the target based on OS: 381 # target.dmg (Mac), target.apk (Android), target.tar.bz2 (Linux), 382 # or target.zip (Windows). 383 Optional('target'): optionally_keyed_by( 384 'test-platform', 385 Any(basestring, None), 386 ), 387 388 # A list of artifacts to install from 'fetch' tasks. 389 Optional('fetches'): { 390 basestring: [basestring], 391 }, 392}, required=True) 393 394 395@transforms.add 396def handle_keyed_by_mozharness(config, tests): 397 """Resolve a mozharness field if it is keyed by something""" 398 for test in tests: 399 resolve_keyed_by(test, 'mozharness', item_name=test['test-name']) 400 yield test 401 402 403@transforms.add 404def set_defaults(config, tests): 405 for test in tests: 406 build_platform = test['build-platform'] 407 if build_platform.startswith('android'): 408 # all Android test tasks download internal objects from tooltool 409 test['mozharness']['tooltool-downloads'] = True 410 test['mozharness']['actions'] = ['get-secrets'] 411 # Android doesn't do e10s 412 test['e10s'] = False 413 # loopback-video is always true for Android, but false for other 414 # platform phyla 415 test['loopback-video'] = True 416 else: 417 # all non-android tests want to run the bits that require node 418 test['mozharness']['set-moz-node-path'] = True 419 test.setdefault('e10s', True) 420 421 # software-gl-layers is only meaningful on linux unittests, where it defaults to True 422 if test['test-platform'].startswith('linux') and test['suite'] != 'talos': 423 test.setdefault('allow-software-gl-layers', True) 424 else: 425 test['allow-software-gl-layers'] = False 426 427 # Enable WebRender by default on the QuantumRender test platforms, since 428 # the whole point of QuantumRender is to run with WebRender enabled. 429 # This currently matches linux64-qr and windows10-64-qr; both of these 430 # have /opt and /debug variants. 431 if "-qr/" in test['test-platform']: 432 test['webrender'] = True 433 else: 434 test.setdefault('webrender', False) 435 436 test.setdefault('try-name', test['test-name']) 437 438 test.setdefault('os-groups', []) 439 test.setdefault('run-as-administrator', False) 440 test.setdefault('chunks', 1) 441 test.setdefault('run-on-projects', 'built-projects') 442 test.setdefault('instance-size', 'default') 443 test.setdefault('max-run-time', 3600) 444 test.setdefault('reboot', False) 445 test.setdefault('virtualization', 'virtual') 446 test.setdefault('loopback-audio', False) 447 test.setdefault('loopback-video', False) 448 test.setdefault('docker-image', {'in-tree': 'desktop1604-test'}) 449 test.setdefault('checkout', False) 450 test.setdefault('require-signed-extensions', False) 451 452 test['mozharness'].setdefault('extra-options', []) 453 test['mozharness'].setdefault('requires-signed-builds', False) 454 test['mozharness'].setdefault('tooltool-downloads', False) 455 test['mozharness'].setdefault('set-moz-node-path', False) 456 test['mozharness'].setdefault('chunked', False) 457 test['mozharness'].setdefault('chunking-args', 'this-chunk') 458 yield test 459 460 461transforms.add_validate(test_description_schema) 462 463 464@transforms.add 465def resolve_keys(config, tests): 466 for test in tests: 467 resolve_keyed_by( 468 test, 'require-signed-extensions', 469 item_name=test['test-name'], 470 **{ 471 'release-type': config.params['release_type'], 472 } 473 ) 474 yield test 475 476 477@transforms.add 478def setup_talos(config, tests): 479 """Add options that are specific to talos jobs (identified by suite=talos)""" 480 for test in tests: 481 if test['suite'] != 'talos': 482 yield test 483 continue 484 485 extra_options = test.setdefault('mozharness', {}).setdefault('extra-options', []) 486 extra_options.append('--use-talos-json') 487 # win7 needs to test skip 488 if test['build-platform'].startswith('win32'): 489 extra_options.append('--add-option') 490 extra_options.append('--setpref,gfx.direct2d.disabled=true') 491 492 yield test 493 494 495@transforms.add 496def handle_artifact_prefix(config, tests): 497 """Handle translating `artifact_prefix` appropriately""" 498 for test in tests: 499 if test['build-attributes'].get('artifact_prefix'): 500 test.setdefault("attributes", {}).setdefault( 501 'artifact_prefix', test['build-attributes']['artifact_prefix'] 502 ) 503 yield test 504 505 506@transforms.add 507def set_target(config, tests): 508 for test in tests: 509 build_platform = test['build-platform'] 510 target = None 511 if 'target' in test: 512 resolve_keyed_by(test, 'target', item_name=test['test-name']) 513 target = test['target'] 514 if not target: 515 if build_platform.startswith('macosx'): 516 target = 'target.dmg' 517 elif build_platform.startswith('android'): 518 target = 'target.apk' 519 elif build_platform.startswith('win'): 520 target = 'target.zip' 521 else: 522 target = 'target.tar.bz2' 523 test['mozharness']['build-artifact-name'] = get_artifact_path(test, target) 524 525 yield test 526 527 528@transforms.add 529def set_treeherder_machine_platform(config, tests): 530 """Set the appropriate task.extra.treeherder.machine.platform""" 531 translation = { 532 # Linux64 build platforms for asan and pgo are specified differently to 533 # treeherder. 534 'linux64-asan/opt': 'linux64/asan', 535 'linux64-pgo/opt': 'linux64/pgo', 536 'macosx64/debug': 'osx-10-10/debug', 537 'macosx64/opt': 'osx-10-10/opt', 538 'win64-asan/opt': 'windows10-64/asan', 539 'win32-pgo/opt': 'windows7-32/pgo', 540 'win64-pgo/opt': 'windows10-64/pgo', 541 # The build names for Android platforms have partially evolved over the 542 # years and need to be translated. 543 'android-api-16/debug': 'android-4-3-armv7-api16/debug', 544 'android-api-16/opt': 'android-4-3-armv7-api16/opt', 545 'android-x86/opt': 'android-4-2-x86/opt', 546 'android-api-16-gradle/opt': 'android-api-16-gradle/opt', 547 } 548 for test in tests: 549 # For most desktop platforms, the above table is not used for "regular" 550 # builds, so we'll always pick the test platform here. 551 # On macOS though, the regular builds are in the table. This causes a 552 # conflict in `verify_task_graph_symbol` once you add a new test 553 # platform based on regular macOS builds, such as for Stylo. 554 # Since it's unclear if the regular macOS builds can be removed from 555 # the table, workaround the issue for Stylo. 556 test['treeherder-machine-platform'] = translation.get( 557 test['build-platform'], test['test-platform']) 558 yield test 559 560 561@transforms.add 562def set_tier(config, tests): 563 """Set the tier based on policy for all test descriptions that do not 564 specify a tier otherwise.""" 565 for test in tests: 566 if 'tier' in test: 567 resolve_keyed_by(test, 'tier', item_name=test['test-name']) 568 569 # only override if not set for the test 570 if 'tier' not in test or test['tier'] == 'default': 571 if test['test-platform'] in ['linux32/opt', 572 'linux32/debug', 573 'linux32-nightly/opt', 574 'linux32-devedition/opt', 575 'linux64/opt', 576 'linux64-nightly/opt', 577 'linux64/debug', 578 'linux64-pgo/opt', 579 'linux64-devedition/opt', 580 'linux64-asan/opt', 581 'windows7-32/debug', 582 'windows7-32/opt', 583 'windows7-32-pgo/opt', 584 'windows7-32-devedition/opt', 585 'windows7-32-nightly/opt', 586 'windows10-64/debug', 587 'windows10-64/opt', 588 'windows10-64-pgo/opt', 589 'windows10-64-devedition/opt', 590 'windows10-64-nightly/opt', 591 'macosx64/opt', 592 'macosx64/debug', 593 'macosx64-nightly/opt', 594 'macosx64-devedition/opt', 595 'android-4.3-arm7-api-16/opt', 596 'android-4.3-arm7-api-16/debug', 597 'android-4.2-x86/opt']: 598 test['tier'] = 1 599 else: 600 test['tier'] = 2 601 602 yield test 603 604 605@transforms.add 606def set_expires_after(config, tests): 607 """Try jobs expire after 2 weeks; everything else lasts 1 year. This helps 608 keep storage costs low.""" 609 for test in tests: 610 if 'expires-after' not in test: 611 if config.params.is_try(): 612 test['expires-after'] = "14 days" 613 else: 614 test['expires-after'] = "1 year" 615 yield test 616 617 618@transforms.add 619def set_download_symbols(config, tests): 620 """In general, we download symbols immediately for debug builds, but only 621 on demand for everything else. ASAN builds shouldn't download 622 symbols since they don't product symbol zips see bug 1283879""" 623 for test in tests: 624 if test['test-platform'].split('/')[-1] == 'debug': 625 test['mozharness']['download-symbols'] = True 626 elif test['build-platform'] == 'linux64-asan/opt' or \ 627 test['build-platform'] == 'windows10-64-asan/opt': 628 if 'download-symbols' in test['mozharness']: 629 del test['mozharness']['download-symbols'] 630 else: 631 test['mozharness']['download-symbols'] = 'ondemand' 632 yield test 633 634 635@transforms.add 636def handle_keyed_by(config, tests): 637 """Resolve fields that can be keyed by platform, etc.""" 638 fields = [ 639 'instance-size', 640 'docker-image', 641 'max-run-time', 642 'chunks', 643 'e10s', 644 'suite', 645 'run-on-projects', 646 'os-groups', 647 'run-as-administrator', 648 'mozharness.chunked', 649 'mozharness.config', 650 'mozharness.extra-options', 651 'mozharness.requires-signed-builds', 652 'mozharness.script', 653 'worker-type', 654 'virtualization', 655 ] 656 for test in tests: 657 for field in fields: 658 resolve_keyed_by(test, field, item_name=test['test-name'], 659 project=config.params['project']) 660 yield test 661 662 663@transforms.add 664def handle_suite_category(config, tests): 665 for test in tests: 666 if '/' in test['suite']: 667 suite, flavor = test['suite'].split('/', 1) 668 else: 669 suite = flavor = test['suite'] 670 671 test.setdefault('attributes', {}) 672 test['attributes']['unittest_suite'] = suite 673 test['attributes']['unittest_flavor'] = flavor 674 675 script = test['mozharness']['script'] 676 category_arg = None 677 if suite == 'test-verify': 678 pass 679 elif script == 'android_emulator_unittest.py': 680 category_arg = '--test-suite' 681 elif script == 'desktop_unittest.py': 682 category_arg = '--{}-suite'.format(suite) 683 684 if category_arg: 685 test['mozharness'].setdefault('extra-options', []) 686 extra = test['mozharness']['extra-options'] 687 if not any(arg.startswith(category_arg) for arg in extra): 688 extra.append('{}={}'.format(category_arg, flavor)) 689 690 yield test 691 692 693@transforms.add 694def enable_code_coverage(config, tests): 695 """Enable code coverage for the linux64-ccov/opt & linux64-jsdcov/opt & win64-ccov/debug 696 build-platforms""" 697 for test in tests: 698 if 'ccov' in test['build-platform'] and not test['test-name'].startswith('test-verify'): 699 test['mozharness'].setdefault('extra-options', []).append('--code-coverage') 700 test['instance-size'] = 'xlarge' 701 # Ensure we don't run on inbound/autoland/beta, but if the test is try only, ignore it 702 if 'mozilla-central' in test['run-on-projects'] or \ 703 test['run-on-projects'] == 'built-projects': 704 test['run-on-projects'] = ['mozilla-central', 'try'] 705 706 # Ensure we don't optimize test suites out. 707 # We always want to run all test suites for coverage purposes. 708 test.pop('schedules-component', None) 709 test.pop('when', None) 710 test['optimization'] = None 711 712 if 'talos' in test['test-name']: 713 test['max-run-time'] = 7200 714 if 'linux' in test['build-platform']: 715 test['docker-image'] = {"in-tree": "desktop1604-test"} 716 test['mozharness']['extra-options'].append('--add-option') 717 test['mozharness']['extra-options'].append('--cycles,1') 718 test['mozharness']['extra-options'].append('--add-option') 719 test['mozharness']['extra-options'].append('--tppagecycles,1') 720 test['mozharness']['extra-options'].append('--add-option') 721 test['mozharness']['extra-options'].append('--no-upload-results') 722 test['mozharness']['extra-options'].append('--add-option') 723 test['mozharness']['extra-options'].append('--tptimeout,15000') 724 elif 'jsdcov' in test['build-platform']: 725 # Ensure we don't run on inbound/autoland/beta, but if the test is try only, ignore it 726 if 'mozilla-central' in test['run-on-projects'] or \ 727 test['run-on-projects'] == 'built-projects': 728 test['run-on-projects'] = ['mozilla-central', 'try'] 729 test['mozharness'].setdefault('extra-options', []).append('--jsd-code-coverage') 730 yield test 731 732 733@transforms.add 734def handle_run_on_projects(config, tests): 735 """Handle translating `built-projects` appropriately""" 736 for test in tests: 737 if test['run-on-projects'] == 'built-projects': 738 test['run-on-projects'] = test['build-attributes'].get('run_on_projects', ['all']) 739 yield test 740 741 742@transforms.add 743def split_e10s(config, tests): 744 for test in tests: 745 e10s = test['e10s'] 746 747 test['e10s'] = False 748 test['attributes']['e10s'] = False 749 750 if e10s == 'both': 751 yield copy.deepcopy(test) 752 e10s = True 753 if e10s: 754 test['test-name'] += '-e10s' 755 test['try-name'] += '-e10s' 756 test['e10s'] = True 757 test['attributes']['e10s'] = True 758 group, symbol = split_symbol(test['treeherder-symbol']) 759 if group != '?': 760 group += '-e10s' 761 test['treeherder-symbol'] = join_symbol(group, symbol) 762 if test['suite'] == 'talos': 763 for i, option in enumerate(test['mozharness']['extra-options']): 764 if option.startswith('--suite='): 765 test['mozharness']['extra-options'][i] += '-e10s' 766 else: 767 test['mozharness']['extra-options'].append('--e10s') 768 yield test 769 770 771@transforms.add 772def split_chunks(config, tests): 773 """Based on the 'chunks' key, split tests up into chunks by duplicating 774 them and assigning 'this-chunk' appropriately and updating the treeherder 775 symbol.""" 776 for test in tests: 777 if test['chunks'] == 1: 778 test['this-chunk'] = 1 779 yield test 780 continue 781 782 for this_chunk in range(1, test['chunks'] + 1): 783 # copy the test and update with the chunk number 784 chunked = copy.deepcopy(test) 785 chunked['this-chunk'] = this_chunk 786 787 # add the chunk number to the TH symbol 788 chunked['treeherder-symbol'] = add_suffix( 789 chunked['treeherder-symbol'], this_chunk) 790 791 yield chunked 792 793 794@transforms.add 795def allow_software_gl_layers(config, tests): 796 """ 797 Handle the "allow-software-gl-layers" property for platforms where it 798 applies. 799 """ 800 for test in tests: 801 if test.get('allow-software-gl-layers'): 802 # This should be set always once bug 1296086 is resolved. 803 test['mozharness'].setdefault('extra-options', [])\ 804 .append("--allow-software-gl-layers") 805 806 yield test 807 808 809@transforms.add 810def enable_webrender(config, tests): 811 """ 812 Handle the "webrender" property by passing a flag to mozharness if it is 813 enabled. 814 """ 815 for test in tests: 816 if test.get('webrender'): 817 test['mozharness'].setdefault('extra-options', [])\ 818 .append("--enable-webrender") 819 820 yield test 821 822 823@transforms.add 824def set_retry_exit_status(config, tests): 825 """Set the retry exit status to TBPL_RETRY, the value returned by mozharness 826 scripts to indicate a transient failure that should be retried.""" 827 for test in tests: 828 test['retry-exit-status'] = [4] 829 yield test 830 831 832@transforms.add 833def set_profile(config, tests): 834 """Set profiling mode for tests.""" 835 profile = None 836 if config.params['try_mode'] == 'try_option_syntax': 837 profile = config.params['try_options']['profile'] 838 for test in tests: 839 if profile and test['suite'] == 'talos': 840 test['mozharness']['extra-options'].append('--geckoProfile') 841 yield test 842 843 844@transforms.add 845def set_tag(config, tests): 846 """Set test for a specific tag.""" 847 tag = None 848 if config.params['try_mode'] == 'try_option_syntax': 849 tag = config.params['try_options']['tag'] 850 for test in tests: 851 if tag: 852 test['mozharness']['extra-options'].extend(['--tag', tag]) 853 yield test 854 855 856@transforms.add 857def set_test_type(config, tests): 858 for test in tests: 859 for test_type in ['mochitest', 'reftest']: 860 if test_type in test['suite'] and 'web-platform' not in test['suite']: 861 test.setdefault('tags', {})['test-type'] = test_type 862 yield test 863 864 865@transforms.add 866def single_stylo_traversal_tests(config, tests): 867 """Enable single traversal for all tests on the sequential Stylo platform.""" 868 869 for test in tests: 870 if not test['test-platform'].startswith('linux64-stylo-sequential/'): 871 yield test 872 continue 873 874 # Bug 1356122 - Run Stylo tests in sequential mode 875 test['mozharness'].setdefault('extra-options', [])\ 876 .append('--single-stylo-traversal') 877 yield test 878 879 880@transforms.add 881def set_worker_type(config, tests): 882 """Set the worker type based on the test platform.""" 883 for test in tests: 884 # during the taskcluster migration, this is a bit tortured, but it 885 # will get simpler eventually! 886 test_platform = test['test-platform'] 887 if test.get('worker-type'): 888 # This test already has its worker type defined, so just use that (yields below) 889 pass 890 elif test_platform.startswith('macosx'): 891 test['worker-type'] = MACOSX_WORKER_TYPES['macosx64'] 892 elif test_platform.startswith('win'): 893 # figure out what platform the job needs to run on 894 if test['virtualization'] == 'hardware': 895 # some jobs like talos and reftest run on real h/w - those are all win10 896 win_worker_type_platform = WINDOWS_WORKER_TYPES['windows10-64'] 897 else: 898 # the other jobs run on a vm which may or may not be a win10 vm 899 win_worker_type_platform = WINDOWS_WORKER_TYPES[ 900 test_platform.split('/')[0] 901 ] 902 # now we have the right platform set the worker type accordingly 903 test['worker-type'] = win_worker_type_platform[test['virtualization']] 904 elif test_platform.startswith('linux') or test_platform.startswith('android'): 905 if test.get('suite', '') == 'talos' and test['build-platform'] != 'linux64-ccov/opt': 906 test['worker-type'] = 'releng-hardware/gecko-t-linux-talos' 907 else: 908 test['worker-type'] = LINUX_WORKER_TYPES[test['instance-size']] 909 else: 910 raise Exception("unknown test_platform {}".format(test_platform)) 911 912 yield test 913 914 915@transforms.add 916def make_job_description(config, tests): 917 """Convert *test* descriptions to *job* descriptions (input to 918 taskgraph.transforms.job)""" 919 920 for test in tests: 921 label = '{}-{}-{}'.format(config.kind, test['test-platform'], test['test-name']) 922 if test['chunks'] > 1: 923 label += '-{}'.format(test['this-chunk']) 924 925 build_label = test['build-label'] 926 927 try_name = test['try-name'] 928 if test['suite'] == 'talos': 929 attr_try_name = 'talos_try_name' 930 else: 931 attr_try_name = 'unittest_try_name' 932 933 attr_build_platform, attr_build_type = test['build-platform'].split('/', 1) 934 935 attributes = test.get('attributes', {}) 936 attributes.update({ 937 'build_platform': attr_build_platform, 938 'build_type': attr_build_type, 939 'test_platform': test['test-platform'], 940 'test_chunk': str(test['this-chunk']), 941 attr_try_name: try_name, 942 }) 943 944 jobdesc = {} 945 name = '{}-{}'.format(test['test-platform'], test['test-name']) 946 jobdesc['name'] = name 947 jobdesc['label'] = label 948 jobdesc['description'] = test['description'] 949 jobdesc['attributes'] = attributes 950 jobdesc['dependencies'] = {'build': build_label} 951 jobdesc['job-from'] = test['job-from'] 952 953 if test['mozharness']['requires-signed-builds'] is True: 954 jobdesc['dependencies']['build-signing'] = test['build-signing-label'] 955 956 jobdesc['expires-after'] = test['expires-after'] 957 jobdesc['routes'] = [] 958 jobdesc['run-on-projects'] = test['run-on-projects'] 959 jobdesc['scopes'] = [] 960 jobdesc['tags'] = test.get('tags', {}) 961 jobdesc['extra'] = { 962 'chunks': { 963 'current': test['this-chunk'], 964 'total': test['chunks'], 965 }, 966 'suite': { 967 'name': attributes['unittest_suite'], 968 'flavor': attributes['unittest_flavor'], 969 }, 970 } 971 jobdesc['treeherder'] = { 972 'symbol': test['treeherder-symbol'], 973 'kind': 'test', 974 'tier': test['tier'], 975 'platform': test.get('treeherder-machine-platform', test['build-platform']), 976 } 977 978 suite = test.get('schedules-component', attributes['unittest_suite']) 979 if suite in INCLUSIVE_COMPONENTS: 980 # if this is an "inclusive" test, then all files which might 981 # cause it to run are annotated with SCHEDULES in moz.build, 982 # so do not include the platform or any other components here 983 schedules = [suite] 984 else: 985 schedules = [suite, platform_family(test['build-platform'])] 986 987 if test.get('when'): 988 jobdesc['when'] = test['when'] 989 elif 'optimization' in test: 990 jobdesc['optimization'] = test['optimization'] 991 elif not config.params.is_try() and suite not in INCLUSIVE_COMPONENTS: 992 # for non-try branches and non-inclusive suites, include SETA 993 jobdesc['optimization'] = {'skip-unless-schedules-or-seta': schedules} 994 else: 995 # otherwise just use skip-unless-schedules 996 jobdesc['optimization'] = {'skip-unless-schedules': schedules} 997 998 run = jobdesc['run'] = {} 999 run['using'] = 'mozharness-test' 1000 run['test'] = test 1001 1002 jobdesc['worker-type'] = test.pop('worker-type') 1003 1004 yield jobdesc 1005 1006 1007def normpath(path): 1008 return path.replace('/', '\\') 1009 1010 1011def get_firefox_version(): 1012 with open('browser/config/version.txt', 'r') as f: 1013 return f.readline().strip() 1014