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 22import copy 23import logging 24import re 25 26from mozbuild.schedules import INCLUSIVE_COMPONENTS 27from six import string_types, text_type 28from voluptuous import ( 29 Any, 30 Optional, 31 Required, 32 Exclusive, 33) 34 35import taskgraph 36from taskgraph.transforms.base import TransformSequence 37from taskgraph.util.attributes import keymatch 38from taskgraph.util.keyed_by import evaluate_keyed_by 39from taskgraph.util.templates import merge 40from taskgraph.util.treeherder import split_symbol, join_symbol 41from taskgraph.util.platforms import platform_family 42from taskgraph.util.schema import ( 43 resolve_keyed_by, 44 optionally_keyed_by, 45 Schema, 46) 47from taskgraph.optimize.schema import OptimizationSchema 48from taskgraph.util.chunking import ( 49 chunk_manifests, 50 get_manifest_loader, 51 get_runtimes, 52 guess_mozinfo_from_task, 53 manifest_loaders, 54 DefaultLoader, 55) 56from taskgraph.util.taskcluster import ( 57 get_artifact_path, 58 get_index_url, 59) 60from taskgraph.util.perfile import perfile_number_of_chunks 61 62 63# default worker types keyed by instance-size 64LINUX_WORKER_TYPES = { 65 "large": "t-linux-large", 66 "xlarge": "t-linux-xlarge", 67 "default": "t-linux-large", 68} 69 70# windows worker types keyed by test-platform and virtualization 71WINDOWS_WORKER_TYPES = { 72 "windows10-32-mingwclang-qr": { 73 "virtual": "t-win10-64", 74 "virtual-with-gpu": "t-win10-64-gpu-s", 75 "hardware": "t-win10-64-1803-hw", 76 }, 77 "windows7-32-qr": { 78 "virtual": "t-win7-32", 79 "virtual-with-gpu": "t-win7-32-gpu", 80 "hardware": "t-win10-64-1803-hw", 81 }, 82 "windows7-32-shippable-qr": { 83 "virtual": "t-win7-32", 84 "virtual-with-gpu": "t-win7-32-gpu", 85 "hardware": "t-win10-64-1803-hw", 86 }, 87 "windows7-32-devedition-qr": { # build only, tests have no value 88 "virtual": "t-win7-32", 89 "virtual-with-gpu": "t-win7-32-gpu", 90 "hardware": "t-win10-64-1803-hw", 91 }, 92 "windows10-32-qr": { 93 "virtual": "t-win10-64", 94 "virtual-with-gpu": "t-win10-64-gpu-s", 95 "hardware": "t-win10-64-1803-hw", 96 }, 97 "windows10-32-shippable-qr": { 98 "virtual": "t-win10-64", 99 "virtual-with-gpu": "t-win10-64-gpu-s", 100 "hardware": "t-win10-64-1803-hw", 101 }, 102 "windows10-64": { 103 "virtual": "t-win10-64", 104 "virtual-with-gpu": "t-win10-64-gpu-s", 105 "hardware": "t-win10-64-1803-hw", 106 }, 107 "windows10-aarch64-qr": { 108 "virtual": "t-win64-aarch64-laptop", 109 "virtual-with-gpu": "t-win64-aarch64-laptop", 110 "hardware": "t-win64-aarch64-laptop", 111 }, 112 "windows10-64-ccov": { 113 "virtual": "t-win10-64", 114 "virtual-with-gpu": "t-win10-64-gpu-s", 115 "hardware": "t-win10-64-1803-hw", 116 }, 117 "windows10-64-ccov-qr": { 118 "virtual": "t-win10-64", 119 "virtual-with-gpu": "t-win10-64-gpu-s", 120 "hardware": "t-win10-64-1803-hw", 121 }, 122 "windows10-64-devedition": { 123 "virtual": "t-win10-64", 124 "virtual-with-gpu": "t-win10-64-gpu-s", 125 "hardware": "t-win10-64-1803-hw", 126 }, 127 "windows10-64-shippable": { 128 "virtual": "t-win10-64", 129 "virtual-with-gpu": "t-win10-64-gpu-s", 130 "hardware": "t-win10-64-1803-hw", 131 }, 132 "windows10-64-qr": { 133 "virtual": "t-win10-64", 134 "virtual-with-gpu": "t-win10-64-gpu-s", 135 "hardware": "t-win10-64-1803-hw", 136 }, 137 "windows10-64-shippable-qr": { 138 "virtual": "t-win10-64", 139 "virtual-with-gpu": "t-win10-64-gpu-s", 140 "hardware": "t-win10-64-1803-hw", 141 }, 142 "windows10-64-devedition-qr": { 143 "virtual": "t-win10-64", 144 "virtual-with-gpu": "t-win10-64-gpu-s", 145 "hardware": "t-win10-64-1803-hw", 146 }, 147 "windows10-64-asan-qr": { 148 "virtual": "t-win10-64", 149 "virtual-with-gpu": "t-win10-64-gpu-s", 150 "hardware": "t-win10-64-1803-hw", 151 }, 152 "windows10-64-mingwclang-qr": { 153 "virtual": "t-win10-64", 154 "virtual-with-gpu": "t-win10-64-gpu-s", 155 "hardware": "t-win10-64-1803-hw", 156 }, 157 "windows10-64-ref-hw-2017": { 158 "virtual": "t-win10-64", 159 "virtual-with-gpu": "t-win10-64-gpu-s", 160 "hardware": "t-win10-64-ref-hw", 161 }, 162 "windows10-32-2004-mingwclang-qr": { 163 "virtual": "win10-64-2004", 164 "virtual-with-gpu": "win10-64-2004-gpu", 165 }, 166 "windows10-32-2004-qr": { 167 "virtual": "win10-64-2004", 168 "virtual-with-gpu": "win10-64-2004-gpu", 169 }, 170 "windows10-32-2004-shippable-qr": { 171 "virtual": "win10-64-2004", 172 "virtual-with-gpu": "win10-64-2004-gpu", 173 }, 174 "windows10-64-2004": { 175 "virtual": "win10-64-2004", 176 "virtual-with-gpu": "win10-64-2004-gpu", 177 }, 178 "windows10-64-2004-ccov": { 179 "virtual": "win10-64-2004", 180 "virtual-with-gpu": "win10-64-2004-gpu", 181 }, 182 "windows10-64-2004-ccov-qr": { 183 "virtual": "win10-64-2004", 184 "virtual-with-gpu": "win10-64-2004-gpu", 185 }, 186 "windows10-64-2004-devedition": { 187 "virtual": "win10-64-2004", 188 "virtual-with-gpu": "win10-64-2004-gpu", 189 }, 190 "windows10-64-2004-shippable": { 191 "virtual": "win10-64-2004", 192 "virtual-with-gpu": "win10-64-2004-gpu", 193 }, 194 "windows10-64-2004-qr": { 195 "virtual": "win10-64-2004", 196 "virtual-with-gpu": "win10-64-2004-gpu", 197 }, 198 "windows10-64-2004-shippable-qr": { 199 "virtual": "win10-64-2004", 200 "virtual-with-gpu": "win10-64-2004-gpu", 201 }, 202 "windows10-64-2004-devedition-qr": { 203 "virtual": "win10-64-2004", 204 "virtual-with-gpu": "win10-64-2004-gpu", 205 }, 206 "windows10-64-2004-asan-qr": { 207 "virtual": "win10-64-2004", 208 "virtual-with-gpu": "win10-64-2004-gpu", 209 }, 210 "windows10-64-2004-mingwclang-qr": { 211 "virtual": "win10-64-2004", 212 "virtual-with-gpu": "win10-64-2004-gpu", 213 }, 214} 215 216# os x worker types keyed by test-platform 217MACOSX_WORKER_TYPES = { 218 "macosx1014-64": "t-osx-1014", 219 "macosx1014-64-power": "t-osx-1014-power", 220 "macosx1015-64": "t-osx-1015-r8", 221 "macosx1100-64": "t-osx-1100-m1", 222} 223 224 225def gv_e10s_filter(task): 226 return get_mobile_project(task) == "geckoview" and task["e10s"] 227 228 229def fission_filter(task): 230 return task.get("e10s") in (True, "both") 231 232 233TEST_VARIANTS = { 234 "noqr": { 235 "description": "{description} with no webrender or software webrender", 236 "suffix": "noqr", 237 "merge": { 238 "webrender": False, 239 "mozharness": { 240 "extra-options": [ 241 "--setpref=gfx.webrender.software=false", 242 "--setpref=layers.acceleration.disabled=true", 243 ], 244 }, 245 }, 246 }, 247 "a11y-checks": { 248 "description": "{description} with accessibility checks enabled", 249 "suffix": "a11y-checks", 250 "replace": { 251 "run-on-projects": { 252 "by-test-platform": { 253 "linux.*64(-shippable)?-qr/opt": ["trunk"], 254 "default": [], 255 }, 256 }, 257 "tier": 2, 258 }, 259 "merge": { 260 "mozharness": { 261 "extra-options": [ 262 "--enable-a11y-checks", 263 ], 264 }, 265 }, 266 }, 267 "geckoview-e10s-single": { 268 "description": "{description} with single-process e10s", 269 "filterfn": gv_e10s_filter, 270 "replace": { 271 "run-on-projects": ["trunk"], 272 }, 273 "suffix": "e10s-single", 274 "merge": { 275 "mozharness": { 276 "extra-options": [ 277 "--setpref=dom.ipc.processCount=1", 278 ], 279 }, 280 }, 281 }, 282 "geckoview-fission": { 283 "description": "{description} with fission enabled", 284 "filterfn": gv_e10s_filter, 285 "suffix": "fis", 286 "merge": { 287 "mozharness": { 288 "extra-options": [ 289 "--enable-fission", 290 ], 291 }, 292 }, 293 }, 294 "fission": { 295 "description": "{description} with fission enabled", 296 "filterfn": fission_filter, 297 "suffix": "fis", 298 "replace": { 299 "e10s": True, 300 }, 301 "merge": { 302 "mozharness": { 303 "extra-options": [ 304 "--setpref=fission.autostart=true", 305 ], 306 }, 307 }, 308 }, 309 "fission-xorigin": { 310 "description": "{description} with cross-origin and fission enabled", 311 "filterfn": fission_filter, 312 "suffix": "fis-xorig", 313 "replace": { 314 "e10s": True, 315 }, 316 "merge": { 317 "mozharness": { 318 "extra-options": [ 319 "--setpref=fission.autostart=true", 320 "--enable-xorigin-tests", 321 ], 322 }, 323 }, 324 }, 325 "fission-webgl-ipc": { 326 # TODO: After 2021-05-01, verify this variant is still needed. 327 "description": "{description} with fission and WebGL IPC process enabled", 328 "suffix": "fis-gli", 329 "replace": { 330 "e10s": True, 331 }, 332 "merge": { 333 "mozharness": { 334 "extra-options": [ 335 "--setpref=fission.autostart=true", 336 "--setpref=dom.serviceWorkers.parent_intercept=true", 337 "--setpref=webgl.out-of-process=true", 338 ], 339 }, 340 }, 341 }, 342 "socketprocess": { 343 "description": "{description} with socket process enabled", 344 "suffix": "spi", 345 "merge": { 346 "mozharness": { 347 "extra-options": [ 348 "--setpref=media.peerconnection.mtransport_process=true", 349 "--setpref=network.process.enabled=true", 350 ], 351 } 352 }, 353 }, 354 "socketprocess_networking": { 355 "description": "{description} with networking on socket process enabled", 356 "suffix": "spi-nw", 357 "merge": { 358 "mozharness": { 359 "extra-options": [ 360 "--setpref=network.process.enabled=true", 361 "--setpref=network.http.network_access_on_socket_process.enabled=true", 362 "--setpref=network.ssl_tokens_cache_enabled=true", 363 ], 364 } 365 }, 366 }, 367 "wayland": { 368 "description": "{description} with Wayland backend enabled", 369 "suffix": "wayland", 370 "replace": { 371 "run-on-projects": [], 372 }, 373 "merge": { 374 "mozharness": { 375 "extra-options": [ 376 "--setpref=widget.wayland.test-workarounds.enabled=true", 377 ], 378 } 379 }, 380 }, 381 "webrender": { 382 "description": "{description} with webrender enabled", 383 "suffix": "wr", 384 "merge": { 385 "webrender": True, 386 }, 387 }, 388 "webrender-sw": { 389 "description": "{description} with software webrender enabled", 390 "suffix": "swr", 391 "merge": { 392 "webrender": True, 393 "mozharness": { 394 "extra-options": [ 395 "--setpref=gfx.webrender.software=true", 396 ], 397 }, 398 }, 399 }, 400 "webrender-sw-a11y-checks": { 401 "description": "{description} with software webrender and accessibility checks enabled", 402 "suffix": "swr-a11y-checks", 403 "replace": { 404 "run-on-projects": { 405 "by-test-platform": { 406 "linux.*64(-shippable)?-qr/opt": ["trunk"], 407 "default": [], 408 }, 409 }, 410 "tier": 2, 411 }, 412 "merge": { 413 "webrender": True, 414 "mozharness": { 415 "extra-options": [ 416 "--setpref=gfx.webrender.software=true", 417 "--enable-a11y-checks", 418 ], 419 }, 420 }, 421 }, 422 "webrender-sw-fission": { 423 "description": "{description} with software webrender and fission enabled", 424 "filterfn": fission_filter, 425 "suffix": "swr-fis", 426 "replace": { 427 "e10s": True, 428 }, 429 "merge": { 430 "webrender": True, 431 "mozharness": { 432 "extra-options": [ 433 "--setpref=gfx.webrender.software=true", 434 "--setpref=fission.autostart=true", 435 ], 436 }, 437 }, 438 }, 439 "webrender-sw-wayland": { 440 "description": "{description} with software webrender and Wayland backend enabled", 441 "suffix": "swr-wayland", 442 "replace": { 443 "run-on-projects": [], 444 }, 445 "merge": { 446 "mozharness": { 447 "extra-options": [ 448 "--setpref=gfx.webrender.software=true", 449 "--setpref=widget.wayland.test-workarounds.enabled=true", 450 ], 451 } 452 }, 453 }, 454 "webgl-ipc": { 455 # TODO: After 2021-05-01, verify this variant is still needed. 456 "description": "{description} with WebGL IPC process enabled", 457 "suffix": "gli", 458 "replace": { 459 "run-on-projects": { 460 "by-test-platform": { 461 "linux.*-64.*": ["trunk"], 462 "mac.*": ["trunk"], 463 "win.*": ["trunk"], 464 "default": [], 465 }, 466 }, 467 }, 468 "merge": { 469 "mozharness": { 470 "extra-options": [ 471 "--setpref=webgl.out-of-process=true", 472 ], 473 }, 474 }, 475 }, 476 "webgl-ipc-profiling": { 477 # TODO: After 2021-05-01, verify this variant is still needed. 478 "description": "{description} with WebGL IPC process enabled", 479 "suffix": "gli", 480 "merge": { 481 "mozharness": { 482 "extra-options": [ 483 "--setpref=webgl.out-of-process=true", 484 ], 485 }, 486 }, 487 }, 488} 489 490 491DYNAMIC_CHUNK_DURATION = 20 * 60 # seconds 492"""The approximate time each test chunk should take to run.""" 493 494 495DYNAMIC_CHUNK_MULTIPLIER = { 496 # Desktop xpcshell tests run in parallel. Reduce the total runtime to 497 # compensate. 498 "^(?!android).*-xpcshell.*": 0.2, 499} 500"""A multiplication factor to tweak the total duration per platform / suite.""" 501 502 503logger = logging.getLogger(__name__) 504 505transforms = TransformSequence() 506 507# Schema for a test description 508# 509# *****WARNING***** 510# 511# This is a great place for baffling cruft to accumulate, and that makes 512# everyone move more slowly. Be considerate of your fellow hackers! 513# See the warnings in taskcluster/docs/how-tos.rst 514# 515# *****WARNING***** 516test_description_schema = Schema( 517 { 518 # description of the suite, for the task metadata 519 Required("description"): text_type, 520 # test suite category and name 521 Optional("suite"): Any( 522 text_type, 523 {Optional("category"): text_type, Optional("name"): text_type}, 524 ), 525 # base work directory used to set up the task. 526 Optional("workdir"): optionally_keyed_by( 527 "test-platform", Any(text_type, "default") 528 ), 529 # the name by which this test suite is addressed in try syntax; defaults to 530 # the test-name. This will translate to the `unittest_try_name` or 531 # `talos_try_name` attribute. 532 Optional("try-name"): text_type, 533 # additional tags to mark up this type of test 534 Optional("tags"): {text_type: object}, 535 # the symbol, or group(symbol), under which this task should appear in 536 # treeherder. 537 Required("treeherder-symbol"): text_type, 538 # the value to place in task.extra.treeherder.machine.platform; ideally 539 # this is the same as build-platform, and that is the default, but in 540 # practice it's not always a match. 541 Optional("treeherder-machine-platform"): text_type, 542 # attributes to appear in the resulting task (later transforms will add the 543 # common attributes) 544 Optional("attributes"): {text_type: object}, 545 # relative path (from config.path) to the file task was defined in 546 Optional("job-from"): text_type, 547 # The `run_on_projects` attribute, defaulting to "all". This dictates the 548 # projects on which this task should be included in the target task set. 549 # See the attributes documentation for details. 550 # 551 # Note that the special case 'built-projects', the default, uses the parent 552 # build task's run-on-projects, meaning that tests run only on platforms 553 # that are built. 554 Optional("run-on-projects"): optionally_keyed_by( 555 "app", 556 "subtest", 557 "test-platform", 558 "test-name", 559 "variant", 560 Any([text_type], "built-projects"), 561 ), 562 # When set only run on projects where the build would already be running. 563 # This ensures tasks where this is True won't be the cause of the build 564 # running on a project it otherwise wouldn't have. 565 Optional("built-projects-only"): bool, 566 # the sheriffing tier for this task (default: set based on test platform) 567 Optional("tier"): optionally_keyed_by( 568 "test-platform", "variant", "app", "subtest", Any(int, "default") 569 ), 570 # number of chunks to create for this task. This can be keyed by test 571 # platform by passing a dictionary in the `by-test-platform` key. If the 572 # test platform is not found, the key 'default' will be tried. 573 Required("chunks"): optionally_keyed_by("test-platform", Any(int, "dynamic")), 574 # Custom 'test_manifest_loader' to use, overriding the one configured in the 575 # parameters. When 'null', no test chunking will be performed. Can also 576 # be used to disable "manifest scheduling". 577 Optional("test-manifest-loader"): Any(None, *list(manifest_loaders)), 578 # the time (with unit) after which this task is deleted; default depends on 579 # the branch (see below) 580 Optional("expires-after"): text_type, 581 # The different configurations that should be run against this task, defined 582 # in the TEST_VARIANTS object. 583 Optional("variants"): optionally_keyed_by( 584 "test-platform", "project", Any(list(TEST_VARIANTS)) 585 ), 586 # Whether to run this task with e10s. If false, run 587 # without e10s; if true, run with e10s; if 'both', run one task with and 588 # one task without e10s. E10s tasks have "-e10s" appended to the test name 589 # and treeherder group. 590 Required("e10s"): optionally_keyed_by( 591 "test-platform", "project", Any(bool, "both") 592 ), 593 # Whether the task should run with WebRender enabled or not. 594 Optional("webrender"): bool, 595 Optional("webrender-run-on-projects"): optionally_keyed_by( 596 "app", Any([text_type], "default") 597 ), 598 # The EC2 instance size to run these tests on. 599 Required("instance-size"): optionally_keyed_by( 600 "test-platform", Any("default", "large", "xlarge") 601 ), 602 # type of virtualization or hardware required by test. 603 Required("virtualization"): optionally_keyed_by( 604 "test-platform", Any("virtual", "virtual-with-gpu", "hardware") 605 ), 606 # Whether the task requires loopback audio or video (whatever that may mean 607 # on the platform) 608 Required("loopback-audio"): bool, 609 Required("loopback-video"): bool, 610 # Whether the test can run using a software GL implementation on Linux 611 # using the GL compositor. May not be used with "legacy" sized instances 612 # due to poor LLVMPipe performance (bug 1296086). Defaults to true for 613 # unit tests on linux platforms and false otherwise 614 Optional("allow-software-gl-layers"): bool, 615 # For tasks that will run in docker-worker, this is the 616 # name of the docker image or in-tree docker image to run the task in. If 617 # in-tree, then a dependency will be created automatically. This is 618 # generally `desktop-test`, or an image that acts an awful lot like it. 619 Required("docker-image"): optionally_keyed_by( 620 "test-platform", 621 Any( 622 # a raw Docker image path (repo/image:tag) 623 text_type, 624 # an in-tree generated docker image (from `taskcluster/docker/<name>`) 625 {"in-tree": text_type}, 626 # an indexed docker image 627 {"indexed": text_type}, 628 ), 629 ), 630 # seconds of runtime after which the task will be killed. Like 'chunks', 631 # this can be keyed by test pltaform. 632 Required("max-run-time"): optionally_keyed_by("test-platform", int), 633 # the exit status code that indicates the task should be retried 634 Optional("retry-exit-status"): [int], 635 # Whether to perform a gecko checkout. 636 Required("checkout"): bool, 637 # Wheter to perform a machine reboot after test is done 638 Optional("reboot"): Any(False, "always", "on-exception", "on-failure"), 639 # What to run 640 Required("mozharness"): { 641 # the mozharness script used to run this task 642 Required("script"): optionally_keyed_by("test-platform", text_type), 643 # the config files required for the task 644 Required("config"): optionally_keyed_by("test-platform", [text_type]), 645 # mochitest flavor for mochitest runs 646 Optional("mochitest-flavor"): text_type, 647 # any additional actions to pass to the mozharness command 648 Optional("actions"): [text_type], 649 # additional command-line options for mozharness, beyond those 650 # automatically added 651 Required("extra-options"): optionally_keyed_by( 652 "test-platform", [text_type] 653 ), 654 # the artifact name (including path) to test on the build task; this is 655 # generally set in a per-kind transformation 656 Optional("build-artifact-name"): text_type, 657 Optional("installer-url"): text_type, 658 # If not false, tooltool downloads will be enabled via relengAPIProxy 659 # for either just public files, or all files. Not supported on Windows 660 Required("tooltool-downloads"): Any( 661 False, 662 "public", 663 "internal", 664 ), 665 # Add --blob-upload-branch=<project> mozharness parameter 666 Optional("include-blob-upload-branch"): bool, 667 # The setting for --download-symbols (if omitted, the option will not 668 # be passed to mozharness) 669 Optional("download-symbols"): Any(True, "ondemand"), 670 # If set, then MOZ_NODE_PATH=/usr/local/bin/node is included in the 671 # environment. This is more than just a helpful path setting -- it 672 # causes xpcshell tests to start additional servers, and runs 673 # additional tests. 674 Required("set-moz-node-path"): bool, 675 # If true, include chunking information in the command even if the number 676 # of chunks is 1 677 Required("chunked"): optionally_keyed_by("test-platform", bool), 678 Required("requires-signed-builds"): optionally_keyed_by( 679 "test-platform", bool 680 ), 681 }, 682 # The set of test manifests to run. 683 Optional("test-manifests"): Any( 684 [text_type], 685 {"active": [text_type], "skipped": [text_type]}, 686 ), 687 # The current chunk (if chunking is enabled). 688 Optional("this-chunk"): int, 689 # os user groups for test task workers; required scopes, will be 690 # added automatically 691 Optional("os-groups"): optionally_keyed_by("test-platform", [text_type]), 692 Optional("run-as-administrator"): optionally_keyed_by("test-platform", bool), 693 # -- values supplied by the task-generation infrastructure 694 # the platform of the build this task is testing 695 Required("build-platform"): text_type, 696 # the label of the build task generating the materials to test 697 Required("build-label"): text_type, 698 # the label of the signing task generating the materials to test. 699 # Signed builds are used in xpcshell tests on Windows, for instance. 700 Optional("build-signing-label"): text_type, 701 # the build's attributes 702 Required("build-attributes"): {text_type: object}, 703 # the platform on which the tests will run 704 Required("test-platform"): text_type, 705 # limit the test-platforms (as defined in test-platforms.yml) 706 # that the test will run on 707 Optional("limit-platforms"): optionally_keyed_by("app", [text_type]), 708 # the name of the test (the key in tests.yml) 709 Required("test-name"): text_type, 710 # the product name, defaults to firefox 711 Optional("product"): text_type, 712 # conditional files to determine when these tests should be run 713 Exclusive("when", "optimization"): { 714 Optional("files-changed"): [text_type], 715 }, 716 # Optimization to perform on this task during the optimization phase. 717 # Optimizations are defined in taskcluster/taskgraph/optimize.py. 718 Exclusive("optimization", "optimization"): OptimizationSchema, 719 # The SCHEDULES component for this task; this defaults to the suite 720 # (not including the flavor) but can be overridden here. 721 Exclusive("schedules-component", "optimization"): Any( 722 text_type, 723 [text_type], 724 ), 725 Optional("worker-type"): optionally_keyed_by( 726 "test-platform", 727 Any(text_type, None), 728 ), 729 Optional( 730 "require-signed-extensions", 731 description="Whether the build being tested requires extensions be signed.", 732 ): optionally_keyed_by("release-type", "test-platform", bool), 733 # The target name, specifying the build artifact to be tested. 734 # If None or not specified, a transform sets the target based on OS: 735 # target.dmg (Mac), target.apk (Android), target.tar.bz2 (Linux), 736 # or target.zip (Windows). 737 Optional("target"): optionally_keyed_by( 738 "test-platform", 739 Any( 740 text_type, 741 None, 742 {Required("index"): text_type, Required("name"): text_type}, 743 ), 744 ), 745 # A list of artifacts to install from 'fetch' tasks. 746 Optional("fetches"): { 747 text_type: optionally_keyed_by("test-platform", [text_type]) 748 }, 749 # Opt-in to Python 3 support 750 Optional("python-3"): bool, 751 # Raptor / browsertime specific keys that need to be here to support 752 # using `by-key` after `by-variant`. Ideally these keys should not exist 753 # in the tests.py schema and instead we'd split variants before the raptor 754 # transforms need them. See bug 1700774. 755 Optional("app"): text_type, 756 Optional("subtest"): text_type, 757 # Define if a given task supports artifact builds or not, see bug 1695325. 758 Optional("supports-artifact-builds"): bool, 759 } 760) 761 762 763@transforms.add 764def handle_keyed_by_mozharness(config, tasks): 765 """Resolve a mozharness field if it is keyed by something""" 766 fields = [ 767 "mozharness", 768 "mozharness.chunked", 769 "mozharness.config", 770 "mozharness.extra-options", 771 "mozharness.requires-signed-builds", 772 "mozharness.script", 773 ] 774 for task in tasks: 775 for field in fields: 776 resolve_keyed_by( 777 task, field, item_name=task["test-name"], enforce_single_match=False 778 ) 779 yield task 780 781 782@transforms.add 783def set_defaults(config, tasks): 784 for task in tasks: 785 build_platform = task["build-platform"] 786 if build_platform.startswith("android"): 787 # all Android test tasks download internal objects from tooltool 788 task["mozharness"]["tooltool-downloads"] = "internal" 789 task["mozharness"]["actions"] = ["get-secrets"] 790 791 # loopback-video is always true for Android, but false for other 792 # platform phyla 793 task["loopback-video"] = True 794 task["mozharness"]["set-moz-node-path"] = True 795 796 # software-gl-layers is only meaningful on linux unittests, where it defaults to True 797 if task["test-platform"].startswith("linux") and task["suite"] not in [ 798 "talos", 799 "raptor", 800 ]: 801 task.setdefault("allow-software-gl-layers", True) 802 else: 803 task["allow-software-gl-layers"] = False 804 805 # Enable WebRender by default on the QuantumRender test platforms, since 806 # the whole point of QuantumRender is to run with WebRender enabled. 807 # This currently matches linux64-qr and windows10-64-qr; both of these 808 # have /opt and /debug variants. 809 if "-qr/" in task["test-platform"]: 810 task["webrender"] = True 811 else: 812 task.setdefault("webrender", False) 813 814 task.setdefault("e10s", True) 815 task.setdefault("try-name", task["test-name"]) 816 task.setdefault("os-groups", []) 817 task.setdefault("run-as-administrator", False) 818 task.setdefault("chunks", 1) 819 task.setdefault("run-on-projects", "built-projects") 820 task.setdefault("built-projects-only", False) 821 task.setdefault("instance-size", "default") 822 task.setdefault("max-run-time", 3600) 823 task.setdefault("reboot", False) 824 task.setdefault("virtualization", "virtual") 825 task.setdefault("loopback-audio", False) 826 task.setdefault("loopback-video", False) 827 task.setdefault("limit-platforms", []) 828 task.setdefault("docker-image", {"in-tree": "ubuntu1804-test"}) 829 task.setdefault("checkout", False) 830 task.setdefault("require-signed-extensions", False) 831 task.setdefault("variants", []) 832 task.setdefault("supports-artifact-builds", True) 833 834 task["mozharness"].setdefault("extra-options", []) 835 task["mozharness"].setdefault("requires-signed-builds", False) 836 task["mozharness"].setdefault("tooltool-downloads", "public") 837 task["mozharness"].setdefault("set-moz-node-path", False) 838 task["mozharness"].setdefault("chunked", False) 839 yield task 840 841 842@transforms.add 843def resolve_keys(config, tasks): 844 for task in tasks: 845 resolve_keyed_by( 846 task, 847 "require-signed-extensions", 848 item_name=task["test-name"], 849 enforce_single_match=False, 850 **{ 851 "release-type": config.params["release_type"], 852 } 853 ) 854 yield task 855 856 857@transforms.add 858def setup_raptor(config, tasks): 859 """Add options that are specific to raptor jobs (identified by suite=raptor)""" 860 from taskgraph.transforms.raptor import transforms as raptor_transforms 861 862 for task in tasks: 863 if task["suite"] != "raptor": 864 yield task 865 continue 866 867 for t in raptor_transforms(config, [task]): 868 yield t 869 870 871@transforms.add 872def limit_platforms(config, tasks): 873 for task in tasks: 874 if not task["limit-platforms"]: 875 yield task 876 continue 877 878 limited_platforms = {key: key for key in task["limit-platforms"]} 879 if keymatch(limited_platforms, task["test-platform"]): 880 yield task 881 882 883transforms.add_validate(test_description_schema) 884 885 886@transforms.add 887def handle_suite_category(config, tasks): 888 for task in tasks: 889 task.setdefault("suite", {}) 890 891 if isinstance(task["suite"], text_type): 892 task["suite"] = {"name": task["suite"]} 893 894 suite = task["suite"].setdefault("name", task["test-name"]) 895 category = task["suite"].setdefault("category", suite) 896 897 task.setdefault("attributes", {}) 898 task["attributes"]["unittest_suite"] = suite 899 task["attributes"]["unittest_category"] = category 900 901 script = task["mozharness"]["script"] 902 category_arg = None 903 if suite.startswith("test-verify") or suite.startswith("test-coverage"): 904 pass 905 elif script in ("android_emulator_unittest.py", "android_hardware_unittest.py"): 906 category_arg = "--test-suite" 907 elif script == "desktop_unittest.py": 908 category_arg = "--{}-suite".format(category) 909 910 if category_arg: 911 task["mozharness"].setdefault("extra-options", []) 912 extra = task["mozharness"]["extra-options"] 913 if not any(arg.startswith(category_arg) for arg in extra): 914 extra.append("{}={}".format(category_arg, suite)) 915 916 # From here on out we only use the suite name. 917 task["suite"] = suite 918 yield task 919 920 921@transforms.add 922def setup_talos(config, tasks): 923 """Add options that are specific to talos jobs (identified by suite=talos)""" 924 for task in tasks: 925 if task["suite"] != "talos": 926 yield task 927 continue 928 929 extra_options = task.setdefault("mozharness", {}).setdefault( 930 "extra-options", [] 931 ) 932 extra_options.append("--use-talos-json") 933 934 # win7 needs to test skip 935 if task["build-platform"].startswith("win32"): 936 extra_options.append("--add-option") 937 extra_options.append("--setpref,gfx.direct2d.disabled=true") 938 939 yield task 940 941 942@transforms.add 943def setup_browsertime_flag(config, tasks): 944 """Optionally add `--browsertime` flag to Raptor pageload tests.""" 945 946 browsertime_flag = config.params["try_task_config"].get("browsertime", False) 947 948 for task in tasks: 949 if not browsertime_flag or task["suite"] != "raptor": 950 yield task 951 continue 952 953 if task["treeherder-symbol"].startswith("Rap"): 954 # The Rap group is subdivided as Rap{-fenix,-refbrow(...), 955 # so `taskgraph.util.treeherder.replace_group` isn't appropriate. 956 task["treeherder-symbol"] = task["treeherder-symbol"].replace( 957 "Rap", "Btime", 1 958 ) 959 960 extra_options = task.setdefault("mozharness", {}).setdefault( 961 "extra-options", [] 962 ) 963 extra_options.append("--browsertime") 964 965 yield task 966 967 968@transforms.add 969def handle_artifact_prefix(config, tasks): 970 """Handle translating `artifact_prefix` appropriately""" 971 for task in tasks: 972 if task["build-attributes"].get("artifact_prefix"): 973 task.setdefault("attributes", {}).setdefault( 974 "artifact_prefix", task["build-attributes"]["artifact_prefix"] 975 ) 976 yield task 977 978 979@transforms.add 980def set_target(config, tasks): 981 for task in tasks: 982 build_platform = task["build-platform"] 983 target = None 984 if "target" in task: 985 resolve_keyed_by( 986 task, "target", item_name=task["test-name"], enforce_single_match=False 987 ) 988 target = task["target"] 989 if not target: 990 if build_platform.startswith("macosx"): 991 target = "target.dmg" 992 elif build_platform.startswith("android"): 993 target = "target.apk" 994 elif build_platform.startswith("win"): 995 target = "target.zip" 996 else: 997 target = "target.tar.bz2" 998 999 if isinstance(target, dict): 1000 # TODO Remove hardcoded mobile artifact prefix 1001 index_url = get_index_url(target["index"]) 1002 installer_url = "{}/artifacts/public/{}".format(index_url, target["name"]) 1003 task["mozharness"]["installer-url"] = installer_url 1004 else: 1005 task["mozharness"]["build-artifact-name"] = get_artifact_path(task, target) 1006 1007 yield task 1008 1009 1010@transforms.add 1011def set_treeherder_machine_platform(config, tasks): 1012 """Set the appropriate task.extra.treeherder.machine.platform""" 1013 translation = { 1014 # Linux64 build platform for asan is specified differently to 1015 # treeherder. 1016 "macosx1014-64/debug": "osx-10-14/debug", 1017 "macosx1014-64/opt": "osx-10-14/opt", 1018 "macosx1014-64-shippable/opt": "osx-10-14-shippable/opt", 1019 "macosx1100-64/opt": "osx-1100/opt", 1020 "macosx1100-64-shippable/opt": "osx-1100-shippable/opt", 1021 "win64-asan/opt": "windows10-64/asan", 1022 "win64-aarch64/opt": "windows10-aarch64/opt", 1023 } 1024 for task in tasks: 1025 # For most desktop platforms, the above table is not used for "regular" 1026 # builds, so we'll always pick the test platform here. 1027 # On macOS though, the regular builds are in the table. This causes a 1028 # conflict in `verify_task_graph_symbol` once you add a new test 1029 # platform based on regular macOS builds, such as for QR. 1030 # Since it's unclear if the regular macOS builds can be removed from 1031 # the table, workaround the issue for QR. 1032 if "android" in task["test-platform"] and "pgo/opt" in task["test-platform"]: 1033 platform_new = task["test-platform"].replace("-pgo/opt", "/pgo") 1034 task["treeherder-machine-platform"] = platform_new 1035 elif "android-em-7.0-x86_64-qr" in task["test-platform"]: 1036 task["treeherder-machine-platform"] = task["test-platform"].replace( 1037 ".", "-" 1038 ) 1039 elif "android-em-7.0-x86_64-shippable-qr" in task["test-platform"]: 1040 task["treeherder-machine-platform"] = task["test-platform"].replace( 1041 ".", "-" 1042 ) 1043 elif "-qr" in task["test-platform"]: 1044 task["treeherder-machine-platform"] = task["test-platform"] 1045 elif "android-hw" in task["test-platform"]: 1046 task["treeherder-machine-platform"] = task["test-platform"] 1047 elif "android-em-7.0-x86_64" in task["test-platform"]: 1048 task["treeherder-machine-platform"] = task["test-platform"].replace( 1049 ".", "-" 1050 ) 1051 elif "android-em-7.0-x86" in task["test-platform"]: 1052 task["treeherder-machine-platform"] = task["test-platform"].replace( 1053 ".", "-" 1054 ) 1055 # Bug 1602863 - must separately define linux64/asan and linux1804-64/asan 1056 # otherwise causes an exception during taskgraph generation about 1057 # duplicate treeherder platform/symbol. 1058 elif "linux64-asan/opt" in task["test-platform"]: 1059 task["treeherder-machine-platform"] = "linux64/asan" 1060 elif "linux1804-asan/opt" in task["test-platform"]: 1061 task["treeherder-machine-platform"] = "linux1804-64/asan" 1062 else: 1063 task["treeherder-machine-platform"] = translation.get( 1064 task["build-platform"], task["test-platform"] 1065 ) 1066 yield task 1067 1068 1069@transforms.add 1070def set_download_symbols(config, tasks): 1071 """In general, we download symbols immediately for debug builds, but only 1072 on demand for everything else. ASAN builds shouldn't download 1073 symbols since they don't product symbol zips see bug 1283879""" 1074 for task in tasks: 1075 if task["test-platform"].split("/")[-1] == "debug": 1076 task["mozharness"]["download-symbols"] = True 1077 elif ( 1078 task["build-platform"] == "linux64-asan/opt" 1079 or task["build-platform"] == "linux64-asan-qr/opt" 1080 or task["build-platform"] == "windows10-64-asan-qr/opt" 1081 ): 1082 if "download-symbols" in task["mozharness"]: 1083 del task["mozharness"]["download-symbols"] 1084 else: 1085 task["mozharness"]["download-symbols"] = "ondemand" 1086 yield task 1087 1088 1089@transforms.add 1090def handle_keyed_by(config, tasks): 1091 """Resolve fields that can be keyed by platform, etc.""" 1092 fields = [ 1093 "instance-size", 1094 "docker-image", 1095 "max-run-time", 1096 "chunks", 1097 "variants", 1098 "e10s", 1099 "suite", 1100 "run-on-projects", 1101 "os-groups", 1102 "run-as-administrator", 1103 "workdir", 1104 "worker-type", 1105 "virtualization", 1106 "fetches.fetch", 1107 "fetches.toolchain", 1108 "target", 1109 "webrender-run-on-projects", 1110 ] 1111 for task in tasks: 1112 for field in fields: 1113 resolve_keyed_by( 1114 task, 1115 field, 1116 item_name=task["test-name"], 1117 defer=["variant"], 1118 enforce_single_match=False, 1119 project=config.params["project"], 1120 ) 1121 yield task 1122 1123 1124@transforms.add 1125def setup_browsertime(config, tasks): 1126 """Configure browsertime dependencies for Raptor pageload tests that have 1127 `--browsertime` extra option.""" 1128 1129 for task in tasks: 1130 # We need to make non-trivial changes to various fetches, and our 1131 # `by-test-platform` may not be "compatible" with existing 1132 # `by-test-platform` filters. Therefore we do everything after 1133 # `handle_keyed_by` so that existing fields have been resolved down to 1134 # simple lists. But we use the `by-test-platform` machinery to express 1135 # filters so that when the time comes to move browsertime into YAML 1136 # files, the transition is straight-forward. 1137 extra_options = task.get("mozharness", {}).get("extra-options", []) 1138 1139 if task["suite"] != "raptor" or "--browsertime" not in extra_options: 1140 yield task 1141 continue 1142 1143 ts = { 1144 "by-test-platform": { 1145 "android.*": ["browsertime", "linux64-geckodriver", "linux64-node"], 1146 "linux.*": ["browsertime", "linux64-geckodriver", "linux64-node"], 1147 "macosx.*": ["browsertime", "macosx64-geckodriver", "macosx64-node"], 1148 "windows.*aarch64.*": [ 1149 "browsertime", 1150 "win32-geckodriver", 1151 "win32-node", 1152 ], 1153 "windows.*-32.*": ["browsertime", "win32-geckodriver", "win32-node"], 1154 "windows.*-64.*": ["browsertime", "win64-geckodriver", "win64-node"], 1155 }, 1156 } 1157 1158 task.setdefault("fetches", {}).setdefault("toolchain", []).extend( 1159 evaluate_keyed_by(ts, "fetches.toolchain", task) 1160 ) 1161 1162 fs = { 1163 "by-test-platform": { 1164 "android.*": ["linux64-ffmpeg-4.1.4"], 1165 "linux.*": ["linux64-ffmpeg-4.1.4"], 1166 "macosx.*": ["mac64-ffmpeg-4.1.1"], 1167 "windows.*aarch64.*": ["win64-ffmpeg-4.1.1"], 1168 "windows.*-32.*": ["win64-ffmpeg-4.1.1"], 1169 "windows.*-64.*": ["win64-ffmpeg-4.1.1"], 1170 }, 1171 } 1172 1173 cd_fetches = { 1174 "android.*": [ 1175 "linux64-chromedriver-87", 1176 "linux64-chromedriver-89", 1177 "linux64-chromedriver-90", 1178 "linux64-chromedriver-91", 1179 ], 1180 "linux.*": [ 1181 "linux64-chromedriver-87", 1182 "linux64-chromedriver-89", 1183 "linux64-chromedriver-90", 1184 "linux64-chromedriver-91", 1185 ], 1186 "macosx.*": [ 1187 "mac64-chromedriver-87", 1188 "mac64-chromedriver-89", 1189 "mac64-chromedriver-90", 1190 "mac64-chromedriver-91", 1191 ], 1192 "windows.*aarch64.*": [ 1193 "win32-chromedriver-87", 1194 "win32-chromedriver-89", 1195 "win32-chromedriver-90", 1196 "win32-chromedriver-91", 1197 ], 1198 "windows.*-32.*": [ 1199 "win32-chromedriver-87", 1200 "win32-chromedriver-89", 1201 "win32-chromedriver-90", 1202 "win32-chromedriver-91", 1203 ], 1204 "windows.*-64.*": [ 1205 "win32-chromedriver-87", 1206 "win32-chromedriver-89", 1207 "win32-chromedriver-90", 1208 "win32-chromedriver-91", 1209 ], 1210 } 1211 1212 chromium_fetches = { 1213 "linux.*": ["linux64-chromium"], 1214 "macosx.*": ["mac-chromium"], 1215 "windows.*aarch64.*": ["win32-chromium"], 1216 "windows.*-32.*": ["win32-chromium"], 1217 "windows.*-64.*": ["win64-chromium"], 1218 } 1219 1220 cd_extracted_name = { 1221 "windows": "{}chromedriver.exe", 1222 "mac": "{}chromedriver", 1223 "default": "{}chromedriver", 1224 } 1225 1226 if "--app=chrome" in extra_options or "--app=chrome-m" in extra_options: 1227 # Only add the chromedriver fetches when chrome is running 1228 for platform in cd_fetches: 1229 fs["by-test-platform"][platform].extend(cd_fetches[platform]) 1230 if "--app=chromium" in extra_options: 1231 for platform in chromium_fetches: 1232 fs["by-test-platform"][platform].extend(chromium_fetches[platform]) 1233 1234 # The chromedrivers for chromium are repackaged into the archives 1235 # that we get the chromium binary from so we always have a compatible 1236 # version. 1237 cd_extracted_name = { 1238 "windows": "chrome-win/chromedriver.exe", 1239 "mac": "chrome-mac/chromedriver", 1240 "default": "chrome-linux/chromedriver", 1241 } 1242 1243 # Disable the Raptor install step 1244 if "--app=chrome-m" in extra_options: 1245 extra_options.append("--noinstall") 1246 1247 task.setdefault("fetches", {}).setdefault("fetch", []).extend( 1248 evaluate_keyed_by(fs, "fetches.fetch", task) 1249 ) 1250 1251 extra_options.extend( 1252 ( 1253 "--browsertime-browsertimejs", 1254 "$MOZ_FETCHES_DIR/browsertime/node_modules/browsertime/bin/browsertime.js", 1255 ) 1256 ) # noqa: E501 1257 1258 eos = { 1259 "by-test-platform": { 1260 "windows.*": [ 1261 "--browsertime-node", 1262 "$MOZ_FETCHES_DIR/node/node.exe", 1263 "--browsertime-geckodriver", 1264 "$MOZ_FETCHES_DIR/geckodriver.exe", 1265 "--browsertime-chromedriver", 1266 "$MOZ_FETCHES_DIR/" + cd_extracted_name["windows"], 1267 "--browsertime-ffmpeg", 1268 "$MOZ_FETCHES_DIR/ffmpeg-4.1.1-win64-static/bin/ffmpeg.exe", 1269 ], 1270 "macosx.*": [ 1271 "--browsertime-node", 1272 "$MOZ_FETCHES_DIR/node/bin/node", 1273 "--browsertime-geckodriver", 1274 "$MOZ_FETCHES_DIR/geckodriver", 1275 "--browsertime-chromedriver", 1276 "$MOZ_FETCHES_DIR/" + cd_extracted_name["mac"], 1277 "--browsertime-ffmpeg", 1278 "$MOZ_FETCHES_DIR/ffmpeg-4.1.1-macos64-static/bin/ffmpeg", 1279 ], 1280 "default": [ 1281 "--browsertime-node", 1282 "$MOZ_FETCHES_DIR/node/bin/node", 1283 "--browsertime-geckodriver", 1284 "$MOZ_FETCHES_DIR/geckodriver", 1285 "--browsertime-chromedriver", 1286 "$MOZ_FETCHES_DIR/" + cd_extracted_name["default"], 1287 "--browsertime-ffmpeg", 1288 "$MOZ_FETCHES_DIR/ffmpeg-4.1.4-i686-static/ffmpeg", 1289 ], 1290 } 1291 } 1292 1293 extra_options.extend(evaluate_keyed_by(eos, "mozharness.extra-options", task)) 1294 1295 yield task 1296 1297 1298def get_mobile_project(task): 1299 """Returns the mobile project of the specified task or None.""" 1300 1301 if not task["build-platform"].startswith("android"): 1302 return 1303 1304 mobile_projects = ("fenix", "geckoview", "refbrow", "chrome-m") 1305 1306 for name in mobile_projects: 1307 if name in task["test-name"]: 1308 return name 1309 1310 target = task.get("target") 1311 if target: 1312 if isinstance(target, dict): 1313 target = target["name"] 1314 1315 for name in mobile_projects: 1316 if name in target: 1317 return name 1318 1319 return None 1320 1321 1322@transforms.add 1323def adjust_mobile_e10s(config, tasks): 1324 for task in tasks: 1325 project = get_mobile_project(task) 1326 if project == "geckoview": 1327 # Geckoview is always-e10s 1328 task["e10s"] = True 1329 yield task 1330 1331 1332@transforms.add 1333def disable_wpt_timeouts_on_autoland(config, tasks): 1334 """do not run web-platform-tests that are expected TIMEOUT on autoland""" 1335 for task in tasks: 1336 if ( 1337 "web-platform-tests" in task["test-name"] 1338 and config.params["project"] == "autoland" 1339 ): 1340 task["mozharness"].setdefault("extra-options", []).append("--skip-timeout") 1341 yield task 1342 1343 1344@transforms.add 1345def split_variants(config, tasks): 1346 for task in tasks: 1347 variants = task.pop("variants", []) 1348 1349 yield copy.deepcopy(task) 1350 1351 for name in variants: 1352 variant = TEST_VARIANTS[name] 1353 1354 if "filterfn" in variant and not variant["filterfn"](task): 1355 continue 1356 1357 taskv = copy.deepcopy(task) 1358 taskv["attributes"]["unittest_variant"] = name 1359 taskv["description"] = variant["description"].format(**taskv) 1360 1361 suffix = "-" + variant["suffix"] 1362 taskv["test-name"] += suffix 1363 taskv["try-name"] += suffix 1364 1365 group, symbol = split_symbol(taskv["treeherder-symbol"]) 1366 if group != "?": 1367 group += suffix 1368 else: 1369 symbol += suffix 1370 taskv["treeherder-symbol"] = join_symbol(group, symbol) 1371 1372 taskv.update(variant.get("replace", {})) 1373 yield merge(taskv, variant.get("merge", {})) 1374 1375 1376@transforms.add 1377def handle_keyed_by_variant(config, tasks): 1378 """Resolve fields that can be keyed by platform, etc.""" 1379 fields = [ 1380 "run-on-projects", 1381 "tier", 1382 ] 1383 for task in tasks: 1384 for field in fields: 1385 resolve_keyed_by( 1386 task, 1387 field, 1388 item_name=task["test-name"], 1389 enforce_single_match=False, 1390 variant=task["attributes"].get("unittest_variant"), 1391 ) 1392 yield task 1393 1394 1395@transforms.add 1396def enable_code_coverage(config, tasks): 1397 """Enable code coverage for the ccov build-platforms""" 1398 for task in tasks: 1399 if "ccov" in task["build-platform"]: 1400 # Do not run tests on fuzzing builds 1401 if "fuzzing" in task["build-platform"]: 1402 task["run-on-projects"] = [] 1403 continue 1404 1405 # Skip this transform for android code coverage builds. 1406 if "android" in task["build-platform"]: 1407 task.setdefault("fetches", {}).setdefault("toolchain", []).append( 1408 "linux64-grcov" 1409 ) 1410 task["mozharness"].setdefault("extra-options", []).append( 1411 "--java-code-coverage" 1412 ) 1413 yield task 1414 continue 1415 task["mozharness"].setdefault("extra-options", []).append("--code-coverage") 1416 task["instance-size"] = "xlarge" 1417 1418 # Temporarily disable Mac tests on mozilla-central 1419 if "mac" in task["build-platform"]: 1420 task["run-on-projects"] = [] 1421 1422 # Ensure we always run on the projects defined by the build, unless the test 1423 # is try only or shouldn't run at all. 1424 if task["run-on-projects"] not in [[]]: 1425 task["run-on-projects"] = "built-projects" 1426 1427 # Ensure we don't optimize test suites out. 1428 # We always want to run all test suites for coverage purposes. 1429 task.pop("schedules-component", None) 1430 task.pop("when", None) 1431 task["optimization"] = None 1432 1433 # Add a toolchain and a fetch task for the grcov binary. 1434 if any(p in task["build-platform"] for p in ("linux", "osx", "win")): 1435 task.setdefault("fetches", {}) 1436 task["fetches"].setdefault("fetch", []) 1437 task["fetches"].setdefault("toolchain", []) 1438 1439 if "linux" in task["build-platform"]: 1440 task["fetches"]["toolchain"].append("linux64-grcov") 1441 elif "osx" in task["build-platform"]: 1442 task["fetches"]["fetch"].append("grcov-osx-x86_64") 1443 elif "win" in task["build-platform"]: 1444 task["fetches"]["toolchain"].append("win64-grcov") 1445 1446 if "talos" in task["test-name"]: 1447 task["max-run-time"] = 7200 1448 if "linux" in task["build-platform"]: 1449 task["docker-image"] = {"in-tree": "ubuntu1804-test"} 1450 task["mozharness"]["extra-options"].append("--add-option") 1451 task["mozharness"]["extra-options"].append("--cycles,1") 1452 task["mozharness"]["extra-options"].append("--add-option") 1453 task["mozharness"]["extra-options"].append("--tppagecycles,1") 1454 task["mozharness"]["extra-options"].append("--add-option") 1455 task["mozharness"]["extra-options"].append("--no-upload-results") 1456 task["mozharness"]["extra-options"].append("--add-option") 1457 task["mozharness"]["extra-options"].append("--tptimeout,15000") 1458 if "raptor" in task["test-name"]: 1459 task["max-run-time"] = 1800 1460 yield task 1461 1462 1463@transforms.add 1464def handle_run_on_projects(config, tasks): 1465 """Handle translating `built-projects` appropriately""" 1466 for task in tasks: 1467 if task["run-on-projects"] == "built-projects": 1468 task["run-on-projects"] = task["build-attributes"].get( 1469 "run_on_projects", ["all"] 1470 ) 1471 1472 if task.pop("built-projects-only", False): 1473 built_projects = set( 1474 task["build-attributes"].get("run_on_projects", {"all"}) 1475 ) 1476 run_on_projects = set(task.get("run-on-projects", set())) 1477 1478 # If 'all' exists in run-on-projects, then the intersection of both 1479 # is built-projects. Similarly if 'all' exists in built-projects, 1480 # the intersection is run-on-projects (so do nothing). When neither 1481 # contains 'all', take the actual set intersection. 1482 if "all" in run_on_projects: 1483 task["run-on-projects"] = sorted(built_projects) 1484 elif "all" not in built_projects: 1485 task["run-on-projects"] = sorted(run_on_projects & built_projects) 1486 yield task 1487 1488 1489@transforms.add 1490def handle_tier(config, tasks): 1491 """Set the tier based on policy for all test descriptions that do not 1492 specify a tier otherwise.""" 1493 for task in tasks: 1494 if "tier" in task: 1495 resolve_keyed_by( 1496 task, "tier", item_name=task["test-name"], enforce_single_match=False 1497 ) 1498 1499 # only override if not set for the test 1500 if "tier" not in task or task["tier"] == "default": 1501 if task["test-platform"] in [ 1502 "linux64/opt", 1503 "linux64/debug", 1504 "linux64-shippable/opt", 1505 "linux64-devedition/opt", 1506 "linux64-asan/opt", 1507 "linux64-qr/opt", 1508 "linux64-qr/debug", 1509 "linux64-shippable-qr/opt", 1510 "linux1804-64/opt", 1511 "linux1804-64/debug", 1512 "linux1804-64-shippable/opt", 1513 "linux1804-64-devedition/opt", 1514 "linux1804-64-qr/opt", 1515 "linux1804-64-qr/debug", 1516 "linux1804-64-shippable-qr/opt", 1517 "linux1804-64-asan-qr/opt", 1518 "linux1804-64-tsan-qr/opt", 1519 "windows7-32-qr/debug", 1520 "windows7-32-qr/opt", 1521 "windows7-32-devedition-qr/opt", 1522 "windows7-32-shippable-qr/opt", 1523 "windows10-32-qr/debug", 1524 "windows10-32-qr/opt", 1525 "windows10-32-shippable-qr/opt", 1526 "windows10-32-2004-qr/debug", 1527 "windows10-32-2004-qr/opt", 1528 "windows10-32-2004-shippable-qr/opt", 1529 "windows10-aarch64-qr/opt", 1530 "windows10-64/debug", 1531 "windows10-64/opt", 1532 "windows10-64-shippable/opt", 1533 "windows10-64-devedition/opt", 1534 "windows10-64-qr/opt", 1535 "windows10-64-qr/debug", 1536 "windows10-64-shippable-qr/opt", 1537 "windows10-64-devedition-qr/opt", 1538 "windows10-64-asan-qr/opt", 1539 "windows10-64-2004-qr/opt", 1540 "windows10-64-2004-qr/debug", 1541 "windows10-64-2004-shippable-qr/opt", 1542 "windows10-64-2004-devedition-qr/opt", 1543 "windows10-64-2004-asan-qr/opt", 1544 "macosx1014-64/opt", 1545 "macosx1014-64/debug", 1546 "macosx1014-64-shippable/opt", 1547 "macosx1014-64-devedition/opt", 1548 "macosx1014-64-devedition-qr/opt", 1549 "macosx1014-64-qr/opt", 1550 "macosx1014-64-shippable-qr/opt", 1551 "macosx1014-64-qr/debug", 1552 "macosx1015-64/opt", 1553 "macosx1015-64/debug", 1554 "macosx1015-64-shippable/opt", 1555 "macosx1015-64-devedition/opt", 1556 "macosx1015-64-devedition-qr/opt", 1557 "macosx1015-64-qr/opt", 1558 "macosx1015-64-shippable-qr/opt", 1559 "macosx1015-64-qr/debug", 1560 "android-em-7.0-x86_64-shippable/opt", 1561 "android-em-7.0-x86_64/debug", 1562 "android-em-7.0-x86_64/debug-isolated-process", 1563 "android-em-7.0-x86_64/opt", 1564 "android-em-7.0-x86-shippable/opt", 1565 "android-em-7.0-x86_64-shippable-qr/opt", 1566 "android-em-7.0-x86_64-qr/debug", 1567 "android-em-7.0-x86_64-qr/opt", 1568 ]: 1569 task["tier"] = 1 1570 else: 1571 task["tier"] = 2 1572 1573 yield task 1574 1575 1576@transforms.add 1577def apply_raptor_tier_optimization(config, tasks): 1578 for task in tasks: 1579 if task["suite"] != "raptor": 1580 yield task 1581 continue 1582 1583 if not task["test-platform"].startswith("android-hw"): 1584 task["optimization"] = {"skip-unless-expanded": None} 1585 if task["tier"] > 1: 1586 task["optimization"] = {"skip-unless-backstop": None} 1587 1588 if task["attributes"].get("unittest_variant"): 1589 task["tier"] = max(task["tier"], 2) 1590 yield task 1591 1592 1593@transforms.add 1594def disable_try_only_platforms(config, tasks): 1595 """Turns off platforms that should only run on try.""" 1596 try_only_platforms = () 1597 for task in tasks: 1598 if any(re.match(k + "$", task["test-platform"]) for k in try_only_platforms): 1599 task["run-on-projects"] = [] 1600 yield task 1601 1602 1603@transforms.add 1604def ensure_spi_disabled_on_all_but_spi(config, tasks): 1605 for task in tasks: 1606 variant = task["attributes"].get("unittest_variant", "") 1607 has_setpref = ( 1608 "gtest" not in task["suite"] 1609 and "cppunit" not in task["suite"] 1610 and "jittest" not in task["suite"] 1611 and "junit" not in task["suite"] 1612 and "raptor" not in task["suite"] 1613 ) 1614 1615 if ( 1616 has_setpref 1617 and variant != "socketprocess" 1618 and variant != "socketprocess_networking" 1619 ): 1620 task["mozharness"]["extra-options"].append( 1621 "--setpref=media.peerconnection.mtransport_process=false" 1622 ) 1623 task["mozharness"]["extra-options"].append( 1624 "--setpref=network.process.enabled=false" 1625 ) 1626 1627 yield task 1628 1629 1630@transforms.add 1631def split_e10s(config, tasks): 1632 for task in tasks: 1633 e10s = task["e10s"] 1634 1635 if e10s: 1636 task_copy = copy.deepcopy(task) 1637 task_copy["test-name"] += "-e10s" 1638 task_copy["e10s"] = True 1639 task_copy["attributes"]["e10s"] = True 1640 yield task_copy 1641 1642 if not e10s or e10s == "both": 1643 task["test-name"] += "-1proc" 1644 task["try-name"] += "-1proc" 1645 task["e10s"] = False 1646 task["attributes"]["e10s"] = False 1647 group, symbol = split_symbol(task["treeherder-symbol"]) 1648 if group != "?": 1649 group += "-1proc" 1650 task["treeherder-symbol"] = join_symbol(group, symbol) 1651 task["mozharness"]["extra-options"].append("--disable-e10s") 1652 yield task 1653 1654 1655@transforms.add 1656def set_test_verify_chunks(config, tasks): 1657 """Set the number of chunks we use for test-verify.""" 1658 for task in tasks: 1659 if any(task["suite"].startswith(s) for s in ("test-verify", "test-coverage")): 1660 env = config.params.get("try_task_config", {}) or {} 1661 env = env.get("templates", {}).get("env", {}) 1662 task["chunks"] = perfile_number_of_chunks( 1663 config.params.is_try(), 1664 env.get("MOZHARNESS_TEST_PATHS", ""), 1665 config.params.get("head_repository", ""), 1666 config.params.get("head_rev", ""), 1667 task["test-name"], 1668 ) 1669 1670 # limit the number of chunks we run for test-verify mode because 1671 # test-verify is comprehensive and takes a lot of time, if we have 1672 # >30 tests changed, this is probably an import of external tests, 1673 # or a patch renaming/moving files in bulk 1674 maximum_number_verify_chunks = 3 1675 if task["chunks"] > maximum_number_verify_chunks: 1676 task["chunks"] = maximum_number_verify_chunks 1677 1678 yield task 1679 1680 1681@transforms.add 1682def set_test_manifests(config, tasks): 1683 """Determine the set of test manifests that should run in this task.""" 1684 1685 for task in tasks: 1686 # When a task explicitly requests no 'test_manifest_loader', test 1687 # resolving will happen at test runtime rather than in the taskgraph. 1688 if "test-manifest-loader" in task and task["test-manifest-loader"] is None: 1689 yield task 1690 continue 1691 1692 # Set 'tests_grouped' to "1", so we can differentiate between suites that are 1693 # chunked at the test runtime and those that are chunked in the taskgraph. 1694 task.setdefault("tags", {})["tests_grouped"] = "1" 1695 1696 if taskgraph.fast: 1697 # We want to avoid evaluating manifests when taskgraph.fast is set. But 1698 # manifests are required for dynamic chunking. Just set the number of 1699 # chunks to one in this case. 1700 if task["chunks"] == "dynamic": 1701 task["chunks"] = 1 1702 yield task 1703 continue 1704 1705 manifests = task.get("test-manifests") 1706 if manifests: 1707 if isinstance(manifests, list): 1708 task["test-manifests"] = {"active": manifests, "skipped": []} 1709 yield task 1710 continue 1711 1712 mozinfo = guess_mozinfo_from_task(task) 1713 1714 loader_name = task.pop( 1715 "test-manifest-loader", config.params["test_manifest_loader"] 1716 ) 1717 loader = get_manifest_loader(loader_name, config.params) 1718 1719 task["test-manifests"] = loader.get_manifests( 1720 task["suite"], 1721 frozenset(mozinfo.items()), 1722 ) 1723 1724 # The default loader loads all manifests. If we use a non-default 1725 # loader, we'll only run some subset of manifests and the hardcoded 1726 # chunk numbers will no longer be valid. Dynamic chunking should yield 1727 # better results. 1728 if not isinstance(loader, DefaultLoader): 1729 task["chunks"] = "dynamic" 1730 1731 yield task 1732 1733 1734@transforms.add 1735def resolve_dynamic_chunks(config, tasks): 1736 """Determine how many chunks are needed to handle the given set of manifests.""" 1737 1738 for task in tasks: 1739 if task["chunks"] != "dynamic": 1740 yield task 1741 continue 1742 1743 if not task.get("test-manifests"): 1744 raise Exception( 1745 "{} must define 'test-manifests' to use dynamic chunking!".format( 1746 task["test-name"] 1747 ) 1748 ) 1749 1750 runtimes = { 1751 m: r 1752 for m, r in get_runtimes(task["test-platform"], task["suite"]).items() 1753 if m in task["test-manifests"]["active"] 1754 } 1755 1756 # Truncate runtimes that are above the desired chunk duration. They 1757 # will be assigned to a chunk on their own and the excess duration 1758 # shouldn't cause additional chunks to be needed. 1759 times = [min(DYNAMIC_CHUNK_DURATION, r) for r in runtimes.values()] 1760 avg = round(sum(times) / len(times), 2) if times else 0 1761 total = sum(times) 1762 1763 # If there are manifests missing from the runtimes data, fill them in 1764 # with the average of all present manifests. 1765 missing = [m for m in task["test-manifests"]["active"] if m not in runtimes] 1766 total += avg * len(missing) 1767 1768 # Apply any chunk multipliers if found. 1769 key = "{}-{}".format(task["test-platform"], task["test-name"]) 1770 matches = keymatch(DYNAMIC_CHUNK_MULTIPLIER, key) 1771 if len(matches) > 1: 1772 raise Exception( 1773 "Multiple matching values for {} found while " 1774 "determining dynamic chunk multiplier!".format(key) 1775 ) 1776 elif matches: 1777 total = total * matches[0] 1778 1779 chunks = int(round(total / DYNAMIC_CHUNK_DURATION)) 1780 1781 # Make sure we never exceed the number of manifests, nor have a chunk 1782 # length of 0. 1783 task["chunks"] = min(chunks, len(task["test-manifests"]["active"])) or 1 1784 yield task 1785 1786 1787@transforms.add 1788def split_chunks(config, tasks): 1789 """Based on the 'chunks' key, split tests up into chunks by duplicating 1790 them and assigning 'this-chunk' appropriately and updating the treeherder 1791 symbol. 1792 """ 1793 1794 for task in tasks: 1795 # If test-manifests are set, chunk them ahead of time to avoid running 1796 # the algorithm more than once. 1797 chunked_manifests = None 1798 if "test-manifests" in task: 1799 manifests = task["test-manifests"] 1800 chunked_manifests = chunk_manifests( 1801 task["suite"], 1802 task["test-platform"], 1803 task["chunks"], 1804 manifests["active"], 1805 ) 1806 1807 # Add all skipped manifests to the first chunk of backstop pushes 1808 # so they still show up in the logs. They won't impact runtime much 1809 # and this way tools like ActiveData are still aware that they 1810 # exist. 1811 if config.params["backstop"] and manifests["active"]: 1812 chunked_manifests[0].extend(manifests["skipped"]) 1813 1814 for i in range(task["chunks"]): 1815 this_chunk = i + 1 1816 1817 # copy the test and update with the chunk number 1818 chunked = copy.deepcopy(task) 1819 chunked["this-chunk"] = this_chunk 1820 1821 if chunked_manifests is not None: 1822 chunked["test-manifests"] = sorted(chunked_manifests[i]) 1823 1824 group, symbol = split_symbol(chunked["treeherder-symbol"]) 1825 if task["chunks"] > 1 or not symbol: 1826 # add the chunk number to the TH symbol 1827 symbol += str(this_chunk) 1828 chunked["treeherder-symbol"] = join_symbol(group, symbol) 1829 1830 yield chunked 1831 1832 1833@transforms.add 1834def allow_software_gl_layers(config, tasks): 1835 """ 1836 Handle the "allow-software-gl-layers" property for platforms where it 1837 applies. 1838 """ 1839 for task in tasks: 1840 if task.get("allow-software-gl-layers"): 1841 # This should be set always once bug 1296086 is resolved. 1842 task["mozharness"].setdefault("extra-options", []).append( 1843 "--allow-software-gl-layers" 1844 ) 1845 1846 yield task 1847 1848 1849@transforms.add 1850def enable_webrender(config, tasks): 1851 """ 1852 Handle the "webrender" property by passing a flag to mozharness if it is 1853 enabled. 1854 """ 1855 for task in tasks: 1856 if task.get("webrender"): 1857 extra_options = task["mozharness"].setdefault("extra-options", []) 1858 extra_options.append("--enable-webrender") 1859 # We only want to 'setpref' on tests that have a profile 1860 if not task["attributes"]["unittest_category"] in [ 1861 "cppunittest", 1862 "geckoview-junit", 1863 "gtest", 1864 "jittest", 1865 "raptor", 1866 ]: 1867 extra_options.append("--setpref=layers.d3d11.enable-blacklist=false") 1868 1869 # run webrender variants on the projects specified on webrender-run-on-projects 1870 if task.get("webrender-run-on-projects") is not None: 1871 task["run-on-projects"] = task["webrender-run-on-projects"] 1872 1873 yield task 1874 1875 1876@transforms.add 1877def set_schedules_for_webrender_android(config, tasks): 1878 """android-hw has limited resources, we need webrender on phones""" 1879 for task in tasks: 1880 if task["suite"] in ["crashtest", "reftest"] and task[ 1881 "test-platform" 1882 ].startswith("android-hw"): 1883 task["schedules-component"] = "android-hw-gfx" 1884 yield task 1885 1886 1887@transforms.add 1888def set_retry_exit_status(config, tasks): 1889 """Set the retry exit status to TBPL_RETRY, the value returned by mozharness 1890 scripts to indicate a transient failure that should be retried.""" 1891 for task in tasks: 1892 task["retry-exit-status"] = [4] 1893 yield task 1894 1895 1896@transforms.add 1897def set_profile(config, tasks): 1898 """Set profiling mode for tests.""" 1899 ttconfig = config.params["try_task_config"] 1900 profile = ttconfig.get("gecko-profile", False) 1901 settings = ( 1902 "gecko-profile-interval", 1903 "gecko-profile-entries", 1904 "gecko-profile-threads", 1905 "gecko-profile-features", 1906 ) 1907 1908 for task in tasks: 1909 if profile and task["suite"] in ["talos", "raptor"]: 1910 extras = task["mozharness"]["extra-options"] 1911 extras.append("--gecko-profile") 1912 for setting in settings: 1913 value = ttconfig.get(setting) 1914 if value is not None: 1915 # These values can contain spaces (eg the "DOM Worker" 1916 # thread) and the command is constructed in different, 1917 # incompatible ways on different platforms. 1918 1919 if task["test-platform"].startswith("win"): 1920 # Double quotes for Windows (single won't work). 1921 extras.append("--" + setting + '="' + str(value) + '"') 1922 else: 1923 # Other platforms keep things as separate values, 1924 # rather than joining with spaces. 1925 extras.append("--" + setting + "=" + str(value)) 1926 1927 yield task 1928 1929 1930@transforms.add 1931def set_tag(config, tasks): 1932 """Set test for a specific tag.""" 1933 tag = None 1934 if config.params["try_mode"] == "try_option_syntax": 1935 tag = config.params["try_options"]["tag"] 1936 for task in tasks: 1937 if tag: 1938 task["mozharness"]["extra-options"].extend(["--tag", tag]) 1939 yield task 1940 1941 1942@transforms.add 1943def set_test_type(config, tasks): 1944 types = ["mochitest", "reftest", "talos", "raptor", "geckoview-junit", "gtest"] 1945 for task in tasks: 1946 for test_type in types: 1947 if test_type in task["suite"] and "web-platform" not in task["suite"]: 1948 task.setdefault("tags", {})["test-type"] = test_type 1949 yield task 1950 1951 1952@transforms.add 1953def set_worker_type(config, tasks): 1954 """Set the worker type based on the test platform.""" 1955 for task in tasks: 1956 # during the taskcluster migration, this is a bit tortured, but it 1957 # will get simpler eventually! 1958 test_platform = task["test-platform"] 1959 if task.get("worker-type"): 1960 # This test already has its worker type defined, so just use that (yields below) 1961 pass 1962 elif test_platform.startswith("macosx1014-64"): 1963 task["worker-type"] = MACOSX_WORKER_TYPES["macosx1014-64"] 1964 elif test_platform.startswith("macosx1015-64"): 1965 if "--power-test" in task["mozharness"]["extra-options"]: 1966 task["worker-type"] = MACOSX_WORKER_TYPES["macosx1014-64-power"] 1967 else: 1968 task["worker-type"] = MACOSX_WORKER_TYPES["macosx1015-64"] 1969 elif test_platform.startswith("macosx1100-64"): 1970 task["worker-type"] = MACOSX_WORKER_TYPES["macosx1100-64"] 1971 elif test_platform.startswith("win"): 1972 # figure out what platform the job needs to run on 1973 if task["virtualization"] == "hardware": 1974 # some jobs like talos and reftest run on real h/w - those are all win10 1975 if test_platform.startswith("windows10-64-ref-hw-2017"): 1976 win_worker_type_platform = WINDOWS_WORKER_TYPES[ 1977 "windows10-64-ref-hw-2017" 1978 ] 1979 elif test_platform.startswith("windows10-aarch64-qr"): 1980 win_worker_type_platform = WINDOWS_WORKER_TYPES[ 1981 "windows10-aarch64-qr" 1982 ] 1983 else: 1984 win_worker_type_platform = WINDOWS_WORKER_TYPES["windows10-64"] 1985 else: 1986 # the other jobs run on a vm which may or may not be a win10 vm 1987 win_worker_type_platform = WINDOWS_WORKER_TYPES[ 1988 test_platform.split("/")[0] 1989 ] 1990 # now we have the right platform set the worker type accordingly 1991 task["worker-type"] = win_worker_type_platform[task["virtualization"]] 1992 elif test_platform.startswith("android-hw-g5"): 1993 if task["suite"] != "raptor": 1994 task["worker-type"] = "t-bitbar-gw-unit-g5" 1995 else: 1996 task["worker-type"] = "t-bitbar-gw-perf-g5" 1997 elif test_platform.startswith("android-hw-p2"): 1998 if task["suite"] != "raptor": 1999 task["worker-type"] = "t-bitbar-gw-unit-p2" 2000 else: 2001 task["worker-type"] = "t-bitbar-gw-perf-p2" 2002 elif test_platform.startswith("android-hw-s7"): 2003 if task["suite"] != "raptor": 2004 task["worker-type"] = "t-bitbar-gw-unit-s7" 2005 else: 2006 task["worker-type"] = "t-bitbar-gw-perf-s7" 2007 elif test_platform.startswith("android-em-7.0-x86"): 2008 task["worker-type"] = "t-linux-metal" 2009 elif test_platform.startswith("linux") or test_platform.startswith("android"): 2010 if task.get("suite", "") in ["talos", "raptor"] and not task[ 2011 "build-platform" 2012 ].startswith("linux64-ccov"): 2013 task["worker-type"] = "t-linux-talos-1804" 2014 else: 2015 task["worker-type"] = LINUX_WORKER_TYPES[task["instance-size"]] 2016 else: 2017 raise Exception("unknown test_platform {}".format(test_platform)) 2018 2019 yield task 2020 2021 2022@transforms.add 2023def set_schedules_components(config, tasks): 2024 for task in tasks: 2025 if "optimization" in task or "when" in task: 2026 yield task 2027 continue 2028 2029 category = task["attributes"]["unittest_category"] 2030 schedules = task.get("schedules-component", category) 2031 if isinstance(schedules, string_types): 2032 schedules = [schedules] 2033 2034 schedules = set(schedules) 2035 if schedules & set(INCLUSIVE_COMPONENTS): 2036 # if this is an "inclusive" test, then all files which might 2037 # cause it to run are annotated with SCHEDULES in moz.build, 2038 # so do not include the platform or any other components here 2039 task["schedules-component"] = sorted(schedules) 2040 yield task 2041 continue 2042 2043 schedules.add(category) 2044 schedules.add(platform_family(task["build-platform"])) 2045 2046 if task["webrender"]: 2047 schedules.add("webrender") 2048 2049 task["schedules-component"] = sorted(schedules) 2050 yield task 2051 2052 2053@transforms.add 2054def make_job_description(config, tasks): 2055 """Convert *test* descriptions to *job* descriptions (input to 2056 taskgraph.transforms.job)""" 2057 2058 for task in tasks: 2059 mobile = get_mobile_project(task) 2060 if mobile and (mobile not in task["test-name"]): 2061 label = "{}-{}-{}-{}".format( 2062 config.kind, task["test-platform"], mobile, task["test-name"] 2063 ) 2064 else: 2065 label = "{}-{}-{}".format( 2066 config.kind, task["test-platform"], task["test-name"] 2067 ) 2068 if task["chunks"] > 1: 2069 label += "-{}".format(task["this-chunk"]) 2070 2071 build_label = task["build-label"] 2072 2073 try_name = task["try-name"] 2074 if task["suite"] == "talos": 2075 attr_try_name = "talos_try_name" 2076 elif task["suite"] == "raptor": 2077 attr_try_name = "raptor_try_name" 2078 else: 2079 attr_try_name = "unittest_try_name" 2080 2081 attr_build_platform, attr_build_type = task["build-platform"].split("/", 1) 2082 2083 attributes = task.get("attributes", {}) 2084 attributes.update( 2085 { 2086 "build_platform": attr_build_platform, 2087 "build_type": attr_build_type, 2088 "test_platform": task["test-platform"], 2089 "test_chunk": str(task["this-chunk"]), 2090 "supports-artifact-builds": task["supports-artifact-builds"], 2091 attr_try_name: try_name, 2092 } 2093 ) 2094 2095 if "test-manifests" in task: 2096 attributes["test_manifests"] = task["test-manifests"] 2097 2098 jobdesc = {} 2099 name = "{}-{}".format(task["test-platform"], task["test-name"]) 2100 jobdesc["name"] = name 2101 jobdesc["label"] = label 2102 jobdesc["description"] = task["description"] 2103 jobdesc["attributes"] = attributes 2104 jobdesc["dependencies"] = {"build": build_label} 2105 jobdesc["job-from"] = task["job-from"] 2106 2107 if task.get("fetches"): 2108 jobdesc["fetches"] = task["fetches"] 2109 2110 if task["mozharness"]["requires-signed-builds"] is True: 2111 jobdesc["dependencies"]["build-signing"] = task["build-signing-label"] 2112 2113 if "expires-after" in task: 2114 jobdesc["expires-after"] = task["expires-after"] 2115 2116 jobdesc["routes"] = [] 2117 jobdesc["run-on-projects"] = sorted(task["run-on-projects"]) 2118 jobdesc["scopes"] = [] 2119 jobdesc["tags"] = task.get("tags", {}) 2120 jobdesc["extra"] = { 2121 "chunks": { 2122 "current": task["this-chunk"], 2123 "total": task["chunks"], 2124 }, 2125 "suite": attributes["unittest_suite"], 2126 } 2127 jobdesc["treeherder"] = { 2128 "symbol": task["treeherder-symbol"], 2129 "kind": "test", 2130 "tier": task["tier"], 2131 "platform": task.get("treeherder-machine-platform", task["build-platform"]), 2132 } 2133 2134 schedules = task.get("schedules-component", []) 2135 if task.get("when"): 2136 # This may still be used by comm-central. 2137 jobdesc["when"] = task["when"] 2138 elif "optimization" in task: 2139 jobdesc["optimization"] = task["optimization"] 2140 elif set(schedules) & set(INCLUSIVE_COMPONENTS): 2141 jobdesc["optimization"] = {"test-inclusive": schedules} 2142 else: 2143 jobdesc["optimization"] = {"test": schedules} 2144 2145 run = jobdesc["run"] = {} 2146 run["using"] = "mozharness-test" 2147 run["test"] = task 2148 2149 if "workdir" in task: 2150 run["workdir"] = task.pop("workdir") 2151 2152 jobdesc["worker-type"] = task.pop("worker-type") 2153 if task.get("fetches"): 2154 jobdesc["fetches"] = task.pop("fetches") 2155 2156 yield jobdesc 2157 2158 2159def normpath(path): 2160 return path.replace("/", "\\") 2161 2162 2163def get_firefox_version(): 2164 with open("browser/config/version.txt", "r") as f: 2165 return f.readline().strip() 2166