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