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# runtime_deps_file: Path to file listing runtime deps for the test. If set, 269# all files listed will be copied to the VM before testing. 270# skip_generating_board_args: By default, this template generates an '--board' 271# arg with corresponding '--flash' or '--use-vm' args for device and vm 272# respectively. This argument instructs the template to skip generating 273# them, and it's designed for use cases where one builds for one board 274# (e.g. amd64-generic), but tests on a different board (e.g. eve). 275# tast_vars: A list of "key=value" runtime variable pairs to pass to invoke 276# strip_chrome: If true, strips Chrome before deploying it for non-Tast tests. 277# the Tast tests. For more details, please see: 278# https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#Runtime-variables 279template("generate_runner_script") { 280 forward_variables_from(invoker, 281 [ 282 "deploy_chrome", 283 "generated_script", 284 "runtime_deps_file", 285 "skip_generating_board_args", 286 "strip_chrome", 287 "tast_attr_expr", 288 "tast_tests", 289 "tast_vars", 290 "testonly", 291 "test_exe", 292 ]) 293 294 if (!defined(skip_generating_board_args)) { 295 # --board should be assigned by the autotest wrapper on skylab builders 296 skip_generating_board_args = is_skylab 297 } 298 299 if (skip_generating_board_args) { 300 # cros_board is not needed, so setting it to empty to avoid being used 301 # accidentally below. 302 cros_board = "" 303 not_needed([ cros_board ]) 304 } 305 306 if (!defined(deploy_chrome)) { 307 deploy_chrome = false 308 } 309 if (!defined(strip_chrome)) { 310 strip_chrome = false 311 } 312 is_tast = defined(tast_attr_expr) || defined(tast_tests) 313 assert(!(is_tast && defined(test_exe)), 314 "Tast tests are invoked from binaries shipped with the VM image. " + 315 "There should be no locally built binary needed.") 316 assert(is_tast || !defined(tast_vars), 317 "tast_vars is only support for Tast tests") 318 319 if (is_tast) { 320 not_needed([ "strip_chrome" ]) 321 } 322 323 # If we're in the cros chrome-sdk (and not the raw ebuild), the test will 324 # need some additional runtime data located in the SDK cache. 325 if (cros_sdk_version != "") { 326 assert(defined(generated_script), 327 "Must specify where to place generated test launcher script via " + 328 "'generated_script'") 329 330 generate_chromeos_sdk_deps(target_name + "_cros_deps__helper") { 331 is_tast = is_tast 332 deploy_chrome = deploy_chrome 333 } 334 } 335 336 generate_wrapper(target_name) { 337 executable = "//build/chromeos/test_runner.py" 338 wrapper_script = generated_script 339 executable_args = [] 340 341 if (defined(runtime_deps_file)) { 342 write_runtime_deps = runtime_deps_file 343 } 344 345 # Build executable_args for the three different test types: GTest, Tast, 346 # and host-side commands (eg telemetry). 347 if (defined(test_exe)) { 348 executable_args += [ 349 "gtest", 350 "--test-exe", 351 test_exe, 352 ] 353 354 # This target is not a gtest unit test, but an integration test suite. 355 # Similar to interactive ui tests, it would start a full browser and 356 # then do testing. 357 # See more at //docs/testing/chromeos_integration. 358 if (test_exe == "chromeos_integration_tests") { 359 # Run the test sudo helper. 360 executable_args += [ "--run-test-sudo-helper" ] 361 362 if (is_chromeos_ash) { 363 # For ash, it need to first stop the existing ash. 364 executable_args += [ "--stop-ui" ] 365 366 # Use the deployed dbus configs. 367 executable_args += [ "--use-deployed-dbus-configs" ] 368 } 369 370 # Make the tests match the browser's selinux tags so it gets the same 371 # security context as the browser would. 372 executable_args += [ "--set-selinux-label=chromeos_integration_tests=u:object_r:chrome_browser_exec:s0" ] 373 } 374 if (defined(runtime_deps_file)) { 375 executable_args += [ 376 "--runtime-deps-path", 377 rebase_path(runtime_deps_file, root_build_dir), 378 ] 379 } 380 } else if (is_tast) { 381 # When --tast-tests is specified, test_runner.py will call 382 # local_test_runner on the VM to run the set of tests. 383 executable_args += [ 384 "tast", 385 "--suite-name", 386 target_name, 387 ] 388 if (defined(tast_attr_expr)) { 389 executable_args += [ 390 "--attr-expr", 391 tast_attr_expr, 392 ] 393 } else { 394 foreach(test, tast_tests) { 395 executable_args += [ 396 "-t", 397 test, 398 ] 399 } 400 } 401 if (defined(tast_vars)) { 402 foreach(var, tast_vars) { 403 executable_args += [ 404 "--tast-var", 405 var, 406 ] 407 } 408 } 409 if (dcheck_always_on) { 410 executable_args += [ 411 "--tast-extra-use-flags", 412 "chrome_dcheck", 413 ] 414 } 415 } else { 416 executable_args += [ "host-cmd" ] 417 } 418 executable_args += [ 419 "--cros-cache", 420 "build/cros_cache/", 421 "--path-to-outdir", 422 rebase_path(root_out_dir, "//"), 423 "-v", 424 ] 425 426 if (!is_tast && strip_chrome) { 427 executable_args += [ "--strip-chrome" ] 428 } 429 430 if (!skip_generating_board_args) { 431 executable_args += [ 432 "--board", 433 cros_board, 434 ] 435 436 _cros_is_vm = false 437 foreach(b, string_split(cros_boards_with_qemu_images, ":")) { 438 if (cros_board == b) { 439 _cros_is_vm = true 440 } 441 } 442 if (_cros_is_vm) { 443 executable_args += [ "--use-vm" ] 444 } else { 445 executable_args += [ "--flash" ] 446 } 447 } 448 449 # If we have public Chromium builds, use public Chromium OS images when 450 # flashing the test device. 451 if (!is_chrome_branded) { 452 executable_args += [ "--public-image" ] 453 } 454 455 if (deploy_chrome && !defined(test_exe)) { 456 executable_args += [ "--deploy-chrome" ] 457 } 458 459 # executable_args should be finished, now build the data and deps lists. 460 deps = [ "//testing/buildbot/filters:chromeos_filters" ] 461 if (defined(invoker.deps)) { 462 deps += invoker.deps 463 } 464 data = [ 465 "//.vpython3", 466 467 # We use android test-runner's results libs to construct gtest output 468 # json. 469 "//build/android/pylib/__init__.py", 470 "//build/android/pylib/base/", 471 "//build/android/pylib/results/", 472 "//build/chromeos/", 473 "//build/util/", 474 "//third_party/chromite/", 475 ] 476 477 if (defined(invoker.data)) { 478 data += invoker.data 479 } 480 481 data_deps = [ "//testing:test_scripts_shared" ] 482 if (cros_sdk_version != "") { 483 data_deps += [ ":" + target_name + "_cros_deps__helper" ] 484 } 485 if (defined(invoker.data_deps)) { 486 data_deps += invoker.data_deps 487 } 488 } 489} 490 491# Handy template to define a generated_script test prepended with the 492# cros_test_wrapper, which will automatically handle spinning up a CrOS VM 493# and/or deploying the browser to the DUT prior to test execution. 494template("cros_test_wrapper_script_test") { 495 generate_wrapper("${target_name}") { 496 forward_variables_from(invoker, 497 "*", 498 [ 499 "args", 500 "data_deps", 501 ]) 502 executable = "$root_out_dir/bin/cros_test_wrapper" 503 wrapper_script = "$root_out_dir/bin/run_${target_name}" 504 testonly = true 505 506 executable_args = [] 507 if (defined(invoker.args)) { 508 executable_args += invoker.args 509 } 510 511 data_deps = [ "//chromeos:cros_test_wrapper" ] 512 if (defined(invoker.data_deps)) { 513 data_deps += invoker.data_deps 514 } 515 } 516} 517 518template("tast_test") { 519 forward_variables_from(invoker, "*") 520 521 # Default the expression to match any chrome-related test. 522 if (!defined(tast_attr_expr) && !defined(tast_tests)) { 523 # The following expression filters out all non-critical tests. See the link 524 # below for more details: 525 # https://chromium.googlesource.com/chromiumos/platform/tast/+/main/docs/test_attributes.md 526 tast_attr_expr = "\"group:mainline\" && \"dep:chrome\"" 527 528 if (defined(enable_tast_informational_tests) && 529 enable_tast_informational_tests) { 530 tast_attr_expr += " && informational" 531 } else { 532 tast_attr_expr += " && !informational" 533 } 534 if (!is_chrome_branded) { 535 tast_attr_expr += " && !\"dep:chrome_internal\"" 536 } 537 } else { 538 assert(defined(tast_attr_expr) != defined(tast_tests), 539 "Specify one of tast_tests or tast_attr_expr.") 540 } 541 542 _data_deps = [ 543 "//:chromiumos_preflight", # Builds the browser. 544 "//chromeos:cros_chrome_deploy", # Adds additional browser run-time deps. 545 546 # Tools used to symbolize Chrome crash dumps. 547 # TODO(crbug.com/40160552): Remove these if/when all tests pick them up by 548 # default. 549 "//third_party/breakpad:dump_syms", 550 "//third_party/breakpad:minidump_dump", 551 "//third_party/breakpad:minidump_stackwalk", 552 ] 553 _data = [ "//components/crash/content/tools/generate_breakpad_symbols.py" ] 554 555 if (is_skylab) { 556 generate_skylab_tast_filter(target_name) { 557 # chromite.deploy_chrome is needed for sideloading Chrome. 558 data = _data + [ "//third_party/chromite/" ] 559 data_deps = _data_deps 560 561 # To disable a test on specific milestones, add it to the appropriate 562 # collection in the following file 563 tast_control = "//chromeos/tast_control.gni" 564 } 565 } else { 566 # Append any disabled tests to the expression. 567 if (defined(tast_disabled_tests)) { 568 assert(defined(tast_attr_expr), 569 "tast_attr_expr must be used when specifying tast_disabled_tests.") 570 foreach(_test_name, tast_disabled_tests) { 571 tast_attr_expr += " && !\"name:${_test_name}\"" 572 } 573 } 574 if (defined(tast_attr_expr)) { 575 tast_attr_expr = "( " + tast_attr_expr + " )" 576 } 577 generate_runner_script(target_name) { 578 testonly = true 579 generated_script = "$root_build_dir/bin/run_${target_name}" 580 runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" 581 deploy_chrome = true 582 data_deps = _data_deps 583 data = _data 584 } 585 } 586} 587