1# Copyright 2018 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import("//build/config/chrome_build.gni") 6import("//build/config/chromeos/args.gni") 7import("//build/config/chromeos/ui_mode.gni") 8import("//build/config/dcheck_always_on.gni") 9import("//build/config/gclient_args.gni") 10import("//build/config/python.gni") 11import("//build/util/generate_wrapper.gni") 12 13assert(is_chromeos) 14assert(is_chromeos_device) 15 16# Determine the real paths for various items in the SDK, which may be used 17# in the 'generate_runner_script' template below. We do so outside the template 18# to confine exec_script to a single invocation. 19if (cros_sdk_version != "") { 20 # Ideally these should be maps, however, gn doesn't support map, so using a 21 # list of list to simulate a map: 22 # [key1, [value1, value2, ...]], [key2, [value1, value2, ...]], where 23 # the keys are boards and values are symlinks or symlink targets, and the 24 # mapping shouldn't be used for anything else. 25 # 26 # A sample usage is: 27 # foreach(m, _symlink_targets_map) { 28 # if(m[0] == target_key) { 29 # target_value = m[1] 30 # } 31 # } 32 # 33 _symlink_map = [] 34 _symlink_targets_map = [] 35 36 if (is_chromeos_ash) { 37 _potential_test_boards = [ cros_board ] 38 } else { 39 _potential_test_boards = [] 40 if (cros_boards != "") { 41 _potential_test_boards += string_split(cros_boards, ":") 42 } 43 if (cros_boards_with_qemu_images != "") { 44 _potential_test_boards += string_split(cros_boards_with_qemu_images, ":") 45 } 46 } 47 48 foreach(b, _potential_test_boards) { 49 _cache_path_prefix = 50 "//build/cros_cache/chrome-sdk/symlinks/${b}+${cros_sdk_version}" 51 52 _cros_is_vm = false 53 foreach(b1, string_split(cros_boards_with_qemu_images, ":")) { 54 if (b == b1) { 55 _cros_is_vm = true 56 } 57 } 58 59 _symlinks = [] 60 _symlinks = [ 61 # Tast harness & test data. 62 rebase_path("${_cache_path_prefix}+autotest_server_package.tar.bz2"), 63 64 # Binutils (and other toolchain tools) used to deploy Chrome to the device. 65 rebase_path( 66 "${_cache_path_prefix}+environment_chromeos-base_chromeos-chrome.tar.xz"), 67 rebase_path("${_cache_path_prefix}+target_toolchain"), 68 ] 69 if (_cros_is_vm) { 70 # VM-related tools. 71 _symlinks += 72 [ rebase_path("${_cache_path_prefix}+chromiumos_test_image.tar.xz") ] 73 } 74 _symlink_map += [ [ 75 b, 76 _symlinks, 77 ] ] 78 } 79 80 _all_symlinks = [] 81 foreach(m, _symlink_map) { 82 _all_symlinks += m[1] 83 } 84 _all_symlink_targets = 85 exec_script("//build/get_symlink_targets.py", _all_symlinks, "list lines") 86 _index = 0 87 foreach(m, _symlink_map) { 88 _symlink_targets = [] 89 foreach(_, m[1]) { 90 _symlink_targets += [ _all_symlink_targets[_index] ] 91 _index += 1 92 } 93 94 _symlink_targets_map += [ [ 95 m[0], 96 _symlink_targets, 97 ] ] 98 } 99} 100 101template("generate_chromeos_sdk_deps") { 102 forward_variables_from(invoker, 103 [ 104 "deploy_chrome", 105 "is_tast", 106 ]) 107 if (!defined(deploy_chrome)) { 108 deploy_chrome = false 109 } 110 if (!defined(is_tast)) { 111 is_tast = false 112 } 113 114 _sdk_data = [] 115 assert(cros_sdk_version != "", "cros sdk version is not defined") 116 foreach(b, _potential_test_boards) { 117 _cros_is_vm = false 118 foreach(b1, string_split(cros_boards_with_qemu_images, ":")) { 119 if (b == b1) { 120 _cros_is_vm = true 121 } 122 } 123 124 # Determine the real paths for various items in the SDK, which may be used 125 # in the 'generate_runner_script' template below. 126 if (is_tast || _cros_is_vm || deploy_chrome) { 127 _symlink_targets = [] 128 foreach(m, _symlink_targets_map) { 129 if (b == m[0]) { 130 _symlink_targets = [] 131 _symlink_targets = m[1] 132 } 133 } 134 135 if (is_tast) { 136 # Add tast sdk items. 137 _sdk_data += [ _symlink_targets[0] ] 138 } 139 if (deploy_chrome) { 140 # To deploy chrome to the VM, it needs to be stripped down to fit into 141 # the VM. This is done by using binutils in the toolchain. So add the 142 # toolchain to the data. 143 _sdk_data += [ 144 _symlink_targets[1], 145 _symlink_targets[2], 146 ] 147 } 148 if (_cros_is_vm) { 149 # Add vm sdk items. 150 _sdk_data += [ _symlink_targets[3] ] 151 } 152 } 153 } 154 group(target_name) { 155 data = _sdk_data 156 data += [ 157 # Needed for various SDK components used below. 158 "//build/cros_cache/chrome-sdk/misc/", 159 "//build/cros_cache/chrome-sdk/symlinks/", 160 "//build/cros_cache/common/", 161 "//chrome/VERSION", 162 163 # The LKGM file controls what version of the VM image to download. Add it 164 # as data here so that changes to it will trigger analyze. 165 "//chromeos/CHROMEOS_LKGM", 166 ] 167 if (cros_boards_with_qemu_images != "") { 168 data += [ "//build/cros_cache/cipd/" ] 169 } 170 } 171} 172 173# Creates tast filter files for skylab tast tests. 174# Args: 175# tast_attr_expr: Tast expression to determine tests to run. This creates the 176# initial set of tests that can be further filtered.. 177# tast_tests: Names of tests to enable in tast. All other tests will be 178# disabled that are not listed. 179# tast_disabled_tests: Names of tests to disable in tast. All other tests that 180# match the tast expression will still run. 181# tast_control: gni file with collections of tests to be used for specific 182# filters (e.g. "//chromeos/tast_control.gni"). Any lists of strings in 183# this file will be used to generate additional tast expressions with 184# those strings expanded into tests to disable (i.e. as && !"name:test"). 185# The name of those lists are then intended to be used to specify in 186# test_suites.pyl which collection to be used on specific test suites. 187template("generate_skylab_tast_filter") { 188 forward_variables_from(invoker, 189 [ 190 "tast_attr_expr", 191 "tast_tests", 192 "tast_disabled_tests", 193 "tast_control", 194 ]) 195 196 if (defined(tast_disabled_tests)) { 197 assert(defined(tast_attr_expr), 198 "tast_attr_expr must be used when specifying tast_disabled_tests.") 199 } 200 _generated_filter = "$root_build_dir/bin/${target_name}.filter" 201 _skylab_args = [ 202 "generate-filter", 203 "--output", 204 rebase_path(_generated_filter), 205 ] 206 if (defined(tast_control)) { 207 _skylab_args += [ 208 "--tast-control", 209 rebase_path(tast_control), 210 ] 211 } 212 if (defined(tast_attr_expr)) { 213 _skylab_args += [ 214 "--tast-expr", 215 tast_attr_expr, 216 ] 217 } 218 if (defined(tast_tests)) { 219 foreach(_test, tast_tests) { 220 _skylab_args += [ 221 "--enabled-tests", 222 _test, 223 ] 224 } 225 } 226 if (defined(tast_disabled_tests)) { 227 foreach(_test_name, tast_disabled_tests) { 228 _skylab_args += [ 229 "--disabled-tests", 230 _test_name, 231 ] 232 } 233 } 234 action(target_name) { 235 testonly = true 236 script = "//build/chromeos/generate_skylab_tast_filter.py" 237 if (defined(tast_control)) { 238 sources = [ tast_control ] 239 } 240 outputs = [ _generated_filter ] 241 args = _skylab_args 242 if (defined(invoker.data_deps)) { 243 data_deps = invoker.data_deps 244 } 245 data = [ _generated_filter ] 246 if (defined(invoker.data)) { 247 data += invoker.data 248 } 249 if (defined(invoker.deps)) { 250 deps = invoker.deps 251 } 252 } 253} 254 255# Creates a script at $generated_script that can be used to launch a cros VM 256# and optionally run a test within it. 257# Args: 258# test_exe: Name of test binary located in the out dir. This will get copied 259# to the VM and executed there. 260# tast_attr_expr: Tast expression to pass to local_test_runner on the VM. 261# tast_tests: List of Tast tests to run on the VM. Note that when this is 262# specified, the target name used to invoke this template will be 263# designated as the "name" of this test and will primarly used for test 264# results tracking and displaying (eg: flakiness dashboard). 265# generated_script: Path to place the generated script. 266# deploy_chrome: If true, deploys a locally built chrome located in the root 267# build dir to the VM or DUT after launching it. 268# deploy_lacros: If true, deploys a locally built Lacros located in the root 269# build dir to the VM or DUT after launching it. 270# runtime_deps_file: Path to file listing runtime deps for the test. If set, 271# all files listed will be copied to the VM before testing. 272# skip_generating_board_args: By default, this template generates an '--board' 273# arg with corresponding '--flash' or '--use-vm' args for device and vm 274# respectively. This argument instructs the template to skip generating 275# them, and it's designed for use cases where one builds for one board 276# (e.g. amd64-generic), but tests on a different board (e.g. eve). 277# tast_vars: A list of "key=value" runtime variable pairs to pass to invoke 278# strip_chrome: If true, strips Chrome before deploying it for non-Tast tests. 279# the Tast tests. For more details, please see: 280# https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#Runtime-variables 281template("generate_runner_script") { 282 forward_variables_from(invoker, 283 [ 284 "deploy_chrome", 285 "deploy_lacros", 286 "generated_script", 287 "runtime_deps_file", 288 "skip_generating_board_args", 289 "strip_chrome", 290 "tast_attr_expr", 291 "tast_tests", 292 "tast_vars", 293 "testonly", 294 "test_exe", 295 ]) 296 297 if (!defined(skip_generating_board_args)) { 298 # --board should be assigned by the autotest wrapper on skylab builders 299 skip_generating_board_args = is_skylab 300 } 301 302 if (skip_generating_board_args) { 303 # cros_board is not needed, so setting it to empty to avoid being used 304 # accidentally below. 305 cros_board = "" 306 not_needed([ cros_board ]) 307 } 308 309 if (!defined(deploy_chrome)) { 310 deploy_chrome = false 311 } 312 if (!defined(deploy_lacros)) { 313 deploy_lacros = false 314 } 315 if (!defined(strip_chrome)) { 316 strip_chrome = false 317 } 318 is_tast = defined(tast_attr_expr) || defined(tast_tests) 319 assert(!(is_tast && defined(test_exe)), 320 "Tast tests are invoked from binaries shipped with the VM image. " + 321 "There should be no locally built binary needed.") 322 assert(is_tast || !defined(tast_vars), 323 "tast_vars is only support for Tast tests") 324 325 if (is_tast) { 326 not_needed([ "strip_chrome" ]) 327 } 328 329 # If we're in the cros chrome-sdk (and not the raw ebuild), the test will 330 # need some additional runtime data located in the SDK cache. 331 if (cros_sdk_version != "") { 332 assert(defined(generated_script), 333 "Must specify where to place generated test launcher script via " + 334 "'generated_script'") 335 336 generate_chromeos_sdk_deps(target_name + "_cros_deps__helper") { 337 is_tast = is_tast 338 deploy_chrome = deploy_chrome 339 } 340 } 341 342 generate_wrapper(target_name) { 343 executable = "//build/chromeos/test_runner.py" 344 wrapper_script = generated_script 345 executable_args = [] 346 347 if (defined(runtime_deps_file)) { 348 write_runtime_deps = runtime_deps_file 349 } 350 351 # Build executable_args for the three different test types: GTest, Tast, 352 # and host-side commands (eg telemetry). 353 if (defined(test_exe)) { 354 executable_args += [ 355 "gtest", 356 "--test-exe", 357 test_exe, 358 ] 359 360 # This target is not a gtest unit test, but an integration test suite. 361 # Similar to interactive ui tests, it would start a full browser and 362 # then do testing. 363 # See more at //docs/testing/chromeos_integration. 364 if (test_exe == "chromeos_integration_tests") { 365 # Run the test sudo helper. 366 executable_args += [ "--run-test-sudo-helper" ] 367 368 if (is_chromeos_ash) { 369 # For ash, it need to first stop the existing ash. 370 executable_args += [ "--stop-ui" ] 371 372 # Use the deployed dbus configs. 373 executable_args += [ "--use-deployed-dbus-configs" ] 374 } 375 376 # Lacros need to know the wayland socket file created by Ash. 377 # In this way, Lacros will be connected to the system Ash. 378 if (is_chromeos_lacros) { 379 executable_args += [ 380 "--env-var", 381 "XDG_RUNTIME_DIR", 382 "/run/chrome", 383 ] 384 } 385 386 # Make the tests match the browser's selinux tags so it gets the same 387 # security context as the browser would. 388 executable_args += [ "--set-selinux-label=chromeos_integration_tests=u:object_r:chrome_browser_exec:s0" ] 389 } 390 if (defined(runtime_deps_file)) { 391 executable_args += [ 392 "--runtime-deps-path", 393 rebase_path(runtime_deps_file, root_build_dir), 394 ] 395 } 396 } else if (is_tast) { 397 # When --tast-tests is specified, test_runner.py will call 398 # local_test_runner on the VM to run the set of tests. 399 executable_args += [ 400 "tast", 401 "--suite-name", 402 target_name, 403 ] 404 if (defined(tast_attr_expr)) { 405 executable_args += [ 406 "--attr-expr", 407 tast_attr_expr, 408 ] 409 } else { 410 foreach(test, tast_tests) { 411 executable_args += [ 412 "-t", 413 test, 414 ] 415 } 416 } 417 if (defined(tast_vars)) { 418 foreach(var, tast_vars) { 419 executable_args += [ 420 "--tast-var", 421 var, 422 ] 423 } 424 } 425 if (dcheck_always_on) { 426 executable_args += [ 427 "--tast-extra-use-flags", 428 "chrome_dcheck", 429 ] 430 } 431 } else { 432 executable_args += [ "host-cmd" ] 433 } 434 executable_args += [ 435 "--cros-cache", 436 "build/cros_cache/", 437 "--path-to-outdir", 438 rebase_path(root_out_dir, "//"), 439 "-v", 440 ] 441 442 if (!is_tast && strip_chrome) { 443 executable_args += [ "--strip-chrome" ] 444 } 445 446 if (!skip_generating_board_args) { 447 executable_args += [ 448 "--board", 449 cros_board, 450 ] 451 452 _cros_is_vm = false 453 foreach(b, string_split(cros_boards_with_qemu_images, ":")) { 454 if (cros_board == b) { 455 _cros_is_vm = true 456 } 457 } 458 if (_cros_is_vm) { 459 executable_args += [ "--use-vm" ] 460 } else { 461 executable_args += [ "--flash" ] 462 } 463 } 464 465 # If we have public Chromium builds, use public Chromium OS images when 466 # flashing the test device. 467 if (!is_chrome_branded) { 468 executable_args += [ "--public-image" ] 469 } 470 471 if (deploy_lacros) { 472 executable_args += [ "--deploy-lacros" ] 473 } 474 475 if (deploy_chrome && !defined(test_exe)) { 476 executable_args += [ "--deploy-chrome" ] 477 } 478 479 # executable_args should be finished, now build the data and deps lists. 480 deps = [ "//testing/buildbot/filters:chromeos_filters" ] 481 if (defined(invoker.deps)) { 482 deps += invoker.deps 483 } 484 data = [ 485 "//.vpython3", 486 487 # We use android test-runner's results libs to construct gtest output 488 # json. 489 "//build/android/pylib/__init__.py", 490 "//build/android/pylib/base/", 491 "//build/android/pylib/results/", 492 "//build/chromeos/", 493 "//build/util/", 494 "//third_party/chromite/", 495 ] 496 497 if (defined(invoker.data)) { 498 data += invoker.data 499 } 500 501 data_deps = [ "//testing:test_scripts_shared" ] 502 if (cros_sdk_version != "") { 503 data_deps += [ ":" + target_name + "_cros_deps__helper" ] 504 } 505 if (defined(invoker.data_deps)) { 506 data_deps += invoker.data_deps 507 } 508 } 509} 510 511template("tast_test") { 512 forward_variables_from(invoker, "*") 513 514 # Default the expression to match any chrome-related test. 515 if (!defined(tast_attr_expr) && !defined(tast_tests)) { 516 # The following expression filters out all non-critical tests. See the link 517 # below for more details: 518 # https://chromium.googlesource.com/chromiumos/platform/tast/+/main/docs/test_attributes.md 519 tast_attr_expr = "\"group:mainline\" && \"dep:chrome\"" 520 521 if (defined(enable_tast_informational_tests) && 522 enable_tast_informational_tests) { 523 tast_attr_expr += " && informational" 524 } else { 525 tast_attr_expr += " && !informational" 526 } 527 if (!is_chrome_branded) { 528 tast_attr_expr += " && !\"dep:chrome_internal\"" 529 } 530 } else { 531 assert(defined(tast_attr_expr) != defined(tast_tests), 532 "Specify one of tast_tests or tast_attr_expr.") 533 } 534 535 _data_deps = [ 536 "//:chromiumos_preflight", # Builds the browser. 537 "//chromeos:cros_chrome_deploy", # Adds additional browser run-time deps. 538 539 # Tools used to symbolize Chrome crash dumps. 540 # TODO(crbug.com/40160552): Remove these if/when all tests pick them up by 541 # default. 542 "//third_party/breakpad:dump_syms", 543 "//third_party/breakpad:minidump_dump", 544 "//third_party/breakpad:minidump_stackwalk", 545 ] 546 _data = [ "//components/crash/content/tools/generate_breakpad_symbols.py" ] 547 548 if (is_skylab) { 549 generate_skylab_tast_filter(target_name) { 550 # chromite.deploy_chrome is needed for sideloading Chrome. 551 data = _data + [ "//third_party/chromite/" ] 552 data_deps = _data_deps 553 554 # To disable a test on specific milestones, add it to the appropriate 555 # collection in the following file 556 tast_control = "//chromeos/tast_control.gni" 557 } 558 } else { 559 # Append any disabled tests to the expression. 560 if (defined(tast_disabled_tests)) { 561 assert(defined(tast_attr_expr), 562 "tast_attr_expr must be used when specifying tast_disabled_tests.") 563 foreach(_test_name, tast_disabled_tests) { 564 tast_attr_expr += " && !\"name:${_test_name}\"" 565 } 566 } 567 if (defined(tast_attr_expr)) { 568 tast_attr_expr = "( " + tast_attr_expr + " )" 569 } 570 generate_runner_script(target_name) { 571 testonly = true 572 generated_script = "$root_build_dir/bin/run_${target_name}" 573 runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" 574 deploy_chrome = true 575 576 data_deps = _data_deps 577 if (!defined(deploy_lacros_chrome)) { 578 deploy_lacros_chrome = false 579 } 580 deploy_lacros = deploy_lacros_chrome 581 data = _data 582 if (deploy_lacros_chrome) { 583 data += [ 584 # A script needed to launch Lacros in Lacros Tast tests. 585 "//build/lacros/mojo_connection_lacros_launcher.py", 586 ] 587 588 # By default, tast tests download a lacros-chrome from a gcs location and 589 # use it for testing. To support running lacros tast tests from Chromium CI, 590 # a Var is added to support pointing the tast tests to use a specified 591 # pre-deployed lacros-chrome. The location is decided by: 592 # https://source.chromium.org/chromium/chromium/src/+/main:third_party/chromite/scripts/deploy_chrome.py;l=80;drc=86f1234a4be8e9574442e076cdc835897f7bea61 593 tast_vars = [ "lacros.DeployedBinary=/usr/local/lacros-chrome" ] 594 } 595 } 596 } 597} 598 599template("lacros_tast_tests") { 600 forward_variables_from(invoker, 601 [ 602 "tast_attr_expr", 603 "tast_disabled_tests", 604 "tast_tests", 605 "tast_control", 606 ]) 607 assert(defined(tast_attr_expr) != defined(tast_tests), 608 "Specify one of tast_tests or tast_attr_expr.") 609 610 _lacros_data_deps = [ 611 "//chrome", # Builds the browser. 612 613 # Tools used to symbolize Chrome crash dumps. 614 # TODO(crbug.com/40160552): Remove these if/when all tests pick them up by 615 # default. 616 "//third_party/breakpad:dump_syms", 617 "//third_party/breakpad:minidump_dump", 618 "//third_party/breakpad:minidump_stackwalk", 619 ] 620 621 _lacros_data = [ 622 "//components/crash/content/tools/generate_breakpad_symbols.py", 623 624 # A script needed to launch Lacros in Lacros Tast tests. 625 "//build/lacros/mojo_connection_lacros_launcher.py", 626 ] 627 628 if (is_skylab) { 629 generate_skylab_tast_filter(target_name) { 630 data = _lacros_data + [ 631 "//.vpython3", 632 "//third_party/chromite/", 633 ] 634 data_deps = _lacros_data_deps 635 636 # To disable a test on specific milestones, add it to the appropriate 637 # collection in the following file 638 tast_control = "//chromeos/tast_control.gni" 639 } 640 } else { 641 # Append any disabled tests to the expression. 642 if (defined(tast_disabled_tests)) { 643 assert(defined(tast_attr_expr), 644 "tast_attr_expr must be used when specifying tast_disabled_tests.") 645 foreach(_test, tast_disabled_tests) { 646 _excluded_test_name_and_board = [] 647 _excluded_test_name_and_board = string_split(_test, "@") + [ "" ] 648 _excluded_test_name = _excluded_test_name_and_board[0] 649 _excluded_board = _excluded_test_name_and_board[1] 650 if (_excluded_board == "" || _excluded_board == cros_board) { 651 tast_attr_expr += " && !\"name:${_excluded_test_name}\"" 652 } 653 } 654 } 655 if (defined(tast_attr_expr)) { 656 tast_attr_expr = "( " + tast_attr_expr + " )" 657 } 658 generate_runner_script(target_name) { 659 testonly = true 660 deploy_lacros = true 661 generated_script = "$root_build_dir/bin/run_${target_name}" 662 runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" 663 664 # At build time, Lacros tests don't know whether they'll run on VM or HW, 665 # and instead, these flags are specified at runtime when invoking the 666 # generated runner script. 667 skip_generating_board_args = true 668 669 # By default, tast tests download a lacros-chrome from a gcs location and 670 # use it for testing. To support running lacros tast tests from Chromium CI, 671 # a Var is added to support pointing the tast tests to use a specified 672 # pre-deployed lacros-chrome. The location is decided by: 673 # https://source.chromium.org/chromium/chromium/src/+/main:third_party/chromite/scripts/deploy_chrome.py;l=80;drc=86f1234a4be8e9574442e076cdc835897f7bea61 674 tast_vars = [ "lacros.DeployedBinary=/usr/local/lacros-chrome" ] 675 676 data_deps = _lacros_data_deps 677 678 data = _lacros_data 679 } 680 } 681} 682