1# Copyright 2015 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 5# ============================================================================== 6# TEST SETUP 7# ============================================================================== 8 9import("//build/config/chromeos/args.gni") 10import("//build/config/chromeos/ui_mode.gni") 11import("//build/config/devtools.gni") 12import("//build/config/gclient_args.gni") 13import("//build/rust/rust_static_library.gni") 14import("//build_overrides/build.gni") 15 16declare_args() { 17 # Some component repos (e.g. ANGLE) import //testing but do not have 18 # "location_tags.json", and so we don't want to try and upload the tags 19 # for their tests. 20 # And, some build configs may simply turn off generation altogether. 21 tests_have_location_tags = generate_location_tags 22} 23 24# On Fuchsia, the test executable has a suffix and is a dependency of the 25# common |target_name| target. For `visibility`, the executable must be 26# specified. Cross-platform targets that include `test` targets in their 27# visibility lists, add `${exec_target_suffix}` immediately after the test 28# target name. This is not necessary when the target is a `source_set`. 29if (is_fuchsia) { 30 exec_target_suffix = "__exec" 31} else { 32 exec_target_suffix = "" 33} 34 35if (is_android) { 36 import("//build/config/android/config.gni") 37 import("//build/config/android/create_unwind_table.gni") 38 import("//build/config/android/extract_unwind_tables.gni") 39 import("//build/config/android/rules.gni") 40 import("//build/config/sanitizers/sanitizers.gni") 41} else if (is_fuchsia) { 42 import("//build/config/fuchsia/generate_runner_scripts.gni") 43 import("//third_party/fuchsia-gn-sdk/src/cmc.gni") 44 import("//third_party/fuchsia-gn-sdk/src/component.gni") 45 import("//third_party/fuchsia-gn-sdk/src/package.gni") 46} else if (is_chromeos && is_chromeos_device) { 47 import("//build/config/chromeos/rules.gni") 48 import("//build/config/sanitizers/sanitizers.gni") 49 import("//build/util/generate_wrapper.gni") 50} else if (is_ios) { 51 import("//build/config/ios/ios_sdk.gni") 52 import("//build/config/ios/ios_test_runner_wrapper.gni") 53 import("//build/config/ios/rules.gni") 54} else { 55 import("//build/config/sanitizers/sanitizers.gni") 56 import("//build/util/generate_wrapper.gni") 57} 58 59# This template represents the core common functionality of a test target 60# on each platform. It includes: 61# * the ability to generate a rust library that includes all .rs files found 62# in sources and depends on that from the test target. 63# * the ability to recognize any declare fuzztests and build runners for them. 64template("mixed_test") { 65 assert(defined(invoker.target_type) && invoker.target_type != "") 66 67 # The crate_root variable would transform the target into a Rust binary 68 # which is incorrect. To not use a generated crate root set: 69 # ``` 70 # test_crate_root = "path/to/root.rs" 71 # ``` 72 assert(!defined(invoker.crate_root)) 73 74 _rs_vars = [ 75 "sources", # We split this list into two. 76 "crate_name", # Android test template overrides the crate name. 77 ] 78 79 if (defined(invoker.sources)) { 80 _rs_sources = filter_include(invoker.sources, [ "*.rs" ]) 81 _cc_sources = filter_exclude(invoker.sources, [ "*.rs" ]) 82 } else { 83 _rs_sources = [] 84 _cc_sources = [] 85 } 86 87 if (_rs_sources != []) { 88 # Note: as a weak convention, __ is usually used before a suffix for 89 # internally-generated targets. However, rust_target requires a strict 90 # snake_case name. 91 if (defined(invoker.crate_name)) { 92 _rust_target_name = "${invoker.crate_name}_rust_objects" 93 } else { 94 _rust_target_name = "${target_name}_rust_objects" 95 } 96 97 # We could automatically add `deps += [ "//testing/rust_gtest_interop" ]` 98 # if `rs_sources` is non-empty. But we don't automatically provide 99 # //testing/gtest either so it would be asymmetric and could break in that 100 # case. So, we act instead as if //testing/rust_gtest_interop is part of 101 # the //testing/gtest dependency. If you add one, and have `rs_sources` 102 # listed, you get both. 103 _gtest_is_in_deps = false 104 if (defined(invoker.deps) && invoker.deps != []) { 105 foreach(dep, invoker.deps) { 106 if (get_label_info(dep, "label_no_toolchain") == 107 "//testing/gtest:gtest") { 108 _gtest_is_in_deps = true 109 } 110 } 111 } 112 113 # TODO(danakj): This could be a rust_source_set perhaps, the point being 114 # that we need to link in all the .o object files inside the library, 115 # instead of dropping unreachable ones during linking (which would drop the 116 # tests). Alternatively we could use a special name suffix or other similar 117 # trick perhaps to ensure that all object files are linked in here. 118 rust_static_library(_rust_target_name) { 119 forward_variables_from(invoker, 120 TESTONLY_AND_VISIBILITY + [ 121 "allow_unsafe", 122 "deps", 123 "generate_crate_root", 124 "public_deps", 125 ]) 126 configs += [ "//build/rust:test" ] 127 if (defined(invoker.test_crate_root)) { 128 crate_root = invoker.test_crate_root 129 } else { 130 generate_crate_root = true 131 } 132 sources = _rs_sources 133 is_gtest_unittests = true 134 135 if (_gtest_is_in_deps) { 136 deps += [ "//testing/rust_gtest_interop" ] 137 } 138 } 139 } else { 140 not_needed(invoker, _rs_vars) 141 } 142 143 if (invoker.target_type == "shared_library_with_jni") { 144 # Needed for shared_library_with_jni. Keeping this import guarded so 145 # that projects who import //testing but not //third_party/jni_zero 146 # don't have issues. 147 import("//third_party/jni_zero/jni_zero.gni") 148 } 149 150 _building_fuzztest_fuzzer = 151 defined(invoker.fuzztests) && use_fuzzing_engine && is_linux 152 153 # Fuzz tests are small fuzzers that do not require particularly-powerful 154 # machines to run, so we do not build them when `high_end_fuzzer_targets` 155 # is true and we are building fuzztests in fuzzing mode. 156 if (_building_fuzztest_fuzzer && high_end_fuzzer_targets) { 157 not_needed(invoker, "*") 158 not_needed("*") 159 160 # We still want a reachable target, so make it a no-op empty group. This 161 # will let the fuzzer builders crawl the build graph and invoke ninja in 162 # the same way regardless of GN args. 163 group(target_name) { 164 } 165 } else { 166 target(invoker.target_type, target_name) { 167 forward_variables_from( 168 invoker, 169 "*", 170 TESTONLY_AND_VISIBILITY + _rs_vars + [ "fuzztests" ]) 171 forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) 172 sources = _cc_sources 173 if (!defined(deps)) { 174 deps = [] 175 } 176 if (!defined(ldflags)) { 177 ldflags = [] 178 } 179 180 if (_rs_sources != []) { 181 deps += [ ":${_rust_target_name}" ] 182 } 183 if (defined(invoker.fuzztests)) { 184 deps += [ "//third_party/fuzztest" ] 185 } 186 } 187 } 188 189 if (_building_fuzztest_fuzzer && !high_end_fuzzer_targets) { 190 # This test contains fuzztests. We want to package them up in a way 191 # which ClusterFuzz knows how to extract. We need to: 192 # 1) make an executable for each individual fuzz test; 193 # 2) check that the fuzztests variable is correct. 194 # At present, all this is likely to work only if invoker.target_type 195 # is 'executable', since we generate a wrapper script that assumes so. 196 # At the moment, we aim to fuzz these fuzztests only on Linux so that's 197 # fine. In future we may need to broaden this. 198 if (defined(invoker.output_name)) { 199 _output_name = invoker.output_name 200 } else { 201 _output_name = target_name 202 } 203 204 _fuzzer_binary_extension = "" 205 if (is_win) { 206 _fuzzer_binary_extension = ".exe" 207 } 208 209 # This will be the actual name of the fuzzer binary generated by 210 # `target_name`. 211 _fuzzer_binary_name = _output_name + _fuzzer_binary_extension 212 _fuzztest_target_name = target_name 213 214 # Confirming that the "fuzztests =" directive is correct can only 215 # be done on builds where we can confidently run the fuzzing binary. 216 # Let's be conservative about that -- so long as any failures are 217 # spotted by at least one CI bot we should be good. 218 confirm_fuzztest_contents = is_asan || !using_sanitizer 219 220 if (confirm_fuzztest_contents) { 221 # Confirm that the fuzztests GN variable matches with the 222 # actual fuzztests in the binary. The output of this action is unused. 223 # It just exists to fail the build if there's an error. 224 # We only do this on Linux, and not for any sanitizers other than 225 # ASAN, because that's specific for CI to show problems and there 226 # may be unknown problems running the fuzztest binary on other 227 # platforms. 228 _fuzztest_check_action = target_name + "__fuzztest_check" 229 action(_fuzztest_check_action) { 230 deps = [ ":" + _fuzztest_target_name ] 231 testonly = true 232 script = "//testing/libfuzzer/confirm_fuzztests.py" 233 _output_name = "$target_gen_dir/${target_name}__checked.txt" 234 outputs = [ _output_name ] 235 236 args = [ 237 "--executable", 238 rebase_path( 239 get_label_info(_fuzztest_target_name, "root_out_dir") + 240 "/" + _fuzzer_binary_name), 241 "--output", 242 rebase_path(_output_name), 243 "--fuzztests", 244 ] + invoker.fuzztests 245 } 246 } 247 248 # Make a wrapper executable for each individual fuzz test 249 foreach(fuzztest_unit, invoker.fuzztests) { 250 _fuzzer_name = target_name + "_" + 251 string_replace(fuzztest_unit, ".", "_") + "_fuzzer" 252 253 # We generate an actual executable because currently our fuzz 254 # builder recipes use `gn refs --type=executable` to find things 255 # to build. Otherwise we could use generate_wrapper or equivalent 256 # to make a python script. We could alter the recipe, or rearrange 257 # deps arragenements so that some other executable depends on these 258 # scripts, but that seems worse. The executable might be more cross- 259 # platform too. 260 _fuzztest_generate_fuzzer = _fuzzer_name + "__generate" 261 262 generated_file(_fuzztest_generate_fuzzer + "_constants") { 263 outputs = [ "$target_gen_dir/$target_name/constants.cpp" ] 264 265 # If we're building for libfuzzer, we have to pass -undefok=max_len 266 # etc. for every conceivable libfuzzer argument, so that gtest doesn't 267 # get discombobulated by them. List is from https://llvm.org/docs/LibFuzzer.html 268 if (use_libfuzzer) { 269 known_libfuzzer_args = [ 270 "help", 271 "seed", 272 "runs", 273 "max_len", 274 "len_control", 275 "timeout", 276 "rss_limit_mb", 277 "malloc_limit_mb", 278 "timeout_exitcode", 279 "error_exitcode", 280 "max_total_time", 281 "merge", 282 "merge_control_file", 283 "minimize_crash", 284 "reload", 285 "jobs", 286 "workers", 287 "dict", 288 "use_counters", 289 "reduce_inputs", 290 "use_value_profile", 291 "only_ascii", 292 "artifact_prefix", 293 "exact_artifact_path", 294 "print_pcs", 295 "print_final_stats", 296 "detect_leaks", 297 "close_fd_mask", 298 "fork", 299 ] 300 fuzzer_args = 301 "-undefok=" + string_join(",", known_libfuzzer_args) + " " 302 } else { 303 fuzzer_args = "" 304 } 305 fuzzer_args += "--fuzz=$fuzztest_unit" 306 contents = [ "const char* kFuzzerArgs = \"${fuzzer_args}\"; const char* kFuzzerBinary = \"${_fuzzer_binary_name}\";" ] 307 } 308 309 _fuzzer_target_name = target_name 310 executable(_fuzztest_generate_fuzzer) { 311 testonly = true 312 data_deps = [ 313 ":" + _fuzztest_target_name, 314 ":" + _fuzzer_target_name, 315 ] 316 deps = [ 317 # Depend on fuzzing_engine so that our recipes know to build all 318 # these wrapper script targets. 319 "//testing/libfuzzer:fuzzing_engine", 320 "//testing/libfuzzer:individual_fuzztest_wrapper", 321 ":" + _fuzztest_generate_fuzzer + "_constants", 322 ] 323 if (confirm_fuzztest_contents) { 324 deps += [ ":" + _fuzztest_check_action ] 325 } 326 output_name = _fuzzer_name 327 sources = 328 get_target_outputs(":" + _fuzztest_generate_fuzzer + "_constants") 329 write_runtime_deps = "$root_build_dir/${_fuzzer_name}.runtime_deps" 330 } 331 } 332 } 333} 334 335# Define a test as an executable (or apk on Android) with the "testonly" flag 336# set. 337# Variable: 338# use_xvfb: (optional) whether to run the executable under Xvfb. 339# use_raw_android_executable: Use executable() rather than android_apk(). 340# use_native_activity: Test implements ANativeActivity_onCreate(). 341# test_runner_shard: (Fuchsia, optional): for CFv2 tests, use the given test 342# runner shard rather than the default shard for the ELF runner when 343# assembling the test component. This is useful, for example, to use the 344# elf_test_ambient_exec_runner for tests that require 345# job_policy_ambient_mark_vmo_exec. 346# fuchsia_package_deps: (Fuchsia, optional) List of fuchsia_component() 347# targets that this test package contains. 348# is_xctest: (iOS, optional) whether to build the executable as XCTest. 349# Similar to the GN arg 'enable_run_ios_unittests_with_xctest' but 350# for build targets. 351# allow_cleartext_traffic: (Android, optional) whether to allow cleartext 352# network requests during the test. 353# fuzztests: a list of instances of the FUZZ_TEST macro to 354# include fuzzing tests alongside unit tests. This introduces an 355# extra dependency and also creates additional metadata so that our 356# fuzzing infrastructure can find and run such tests. 357# This should be a list of the test names, for example 358# fuzztests = [ "MyTestClass.MyTestName" ] 359template("test") { 360 testonly = true 361 if (!is_ios) { 362 assert(!defined(invoker.is_xctest) || !invoker.is_xctest, 363 "is_xctest can be set only for iOS builds") 364 } 365 if (!is_android) { 366 assert(!defined(invoker.allow_cleartext_traffic), 367 "allow_cleartext_traffic can be set only for Android tests") 368 } 369 370 if (is_android) { 371 assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb) 372 373 _use_default_launcher = 374 !defined(invoker.use_default_launcher) || invoker.use_default_launcher 375 if (!defined(invoker.use_raw_android_executable)) { 376 # Checkouts where build_with_chromium == false often have a custom GN 377 # template wrapper around test() which sets use_default_launcher == false. 378 # Set the _use_raw_android_executable default so that test() targets which 379 # do not use the custom wrapper 380 # (1) Do not cause "gn gen" to fail 381 # (2) Do not need to be moved into if(build_with_chromium) block. 382 _use_raw_android_executable = 383 !build_with_chromium && _use_default_launcher 384 } else { 385 not_needed([ "_use_default_launcher" ]) 386 _use_raw_android_executable = invoker.use_raw_android_executable 387 } 388 389 # output_name is used to allow targets with the same name but in different 390 # packages to still produce unique runner scripts. 391 _output_name = invoker.target_name 392 if (defined(invoker.output_name)) { 393 _output_name = invoker.output_name 394 } 395 396 _test_runner_target = "${_output_name}__test_runner_script" 397 _wrapper_script_vars = [ 398 "android_test_runner_script", 399 "extra_args", 400 "ignore_all_data_deps", 401 "shard_timeout", 402 ] 403 404 assert(_use_raw_android_executable || enable_java_templates) 405 406 if (_use_raw_android_executable) { 407 not_needed(invoker, [ "add_unwind_tables_in_apk" ]) 408 409 _exec_target = "${target_name}__exec" 410 _dist_target = "${target_name}__dist" 411 _exec_output = 412 "$target_out_dir/${invoker.target_name}/${invoker.target_name}" 413 _crate_name = "${target_name}" 414 415 mixed_test(_exec_target) { 416 target_type = "executable" 417 418 # Use a crate name that avoids creating a warning due to double 419 # underscore (ie. `__`). 420 crate_name = _crate_name 421 422 # Configs will always be defined since we set_defaults in 423 # BUILDCONFIG.gn. 424 configs = [] 425 forward_variables_from( 426 invoker, 427 "*", 428 TESTONLY_AND_VISIBILITY + _wrapper_script_vars + [ 429 "data_deps", 430 "extra_dist_files", 431 ]) 432 433 # Thanks to the set_defaults() for test(), configs are initialized with 434 # the default shared_library configs rather than executable configs. 435 configs -= [ 436 "//build/config:shared_library_config", 437 "//build/config/android:hide_all_but_jni", 438 ] 439 configs += [ "//build/config:executable_config" ] 440 441 if (defined(invoker.data_deps)) { 442 data_deps = invoker.data_deps 443 } else { 444 data_deps = [] 445 } 446 if (!defined(data)) { 447 data = [] 448 } 449 if (tests_have_location_tags) { 450 data += [ "//testing/location_tags.json" ] 451 } 452 if (!defined(deps)) { 453 deps = [] 454 } 455 456 # Don't output to the root or else conflict with the group() below. 457 output_name = rebase_path(_exec_output, root_out_dir) 458 } 459 460 create_native_executable_dist(_dist_target) { 461 dist_dir = "$root_out_dir/$target_name" 462 binary = _exec_output 463 deps = [ ":$_exec_target" ] 464 if (defined(invoker.extra_dist_files)) { 465 extra_files = invoker.extra_dist_files 466 } 467 } 468 } else { 469 _library_target_name = "${target_name}__library" 470 _library_crate_name = "${target_name}_library" 471 _apk_target_name = "${target_name}__apk" 472 _apk_specific_vars = [ 473 "allow_cleartext_traffic", 474 "android_manifest", 475 "android_manifest_dep", 476 "android_manifest_template", 477 "app_as_shared_lib", 478 "keystore_name", 479 "keystore_password", 480 "keystore_path", 481 "loadable_module_deps", 482 "loadable_modules", 483 "min_sdk_version", 484 "product_config_java_packages", 485 "proguard_configs", 486 "proguard_enabled", 487 "srcjar_deps", 488 "target_sdk_version", 489 "use_default_launcher", 490 "use_native_activity", 491 ] 492 493 _add_unwind_tables_in_apk = 494 defined(invoker.add_unwind_tables_in_apk) && 495 invoker.add_unwind_tables_in_apk && target_cpu == "arm" 496 497 # Adds the unwind tables from unstripped binary as an asset file in the 498 # apk, if |add_unwind_tables_in_apk| is specified by the test. 499 if (_add_unwind_tables_in_apk) { 500 # TODO(crbug.com/1315603): Remove generation of v1 unwind asset when 501 # `CFIBacktraceAndroid` is replaced with `ChromeUnwinderAndroid`. 502 _unwind_table_name = "${_library_target_name}_unwind_v1" 503 unwind_table_v1(_unwind_table_name) { 504 library_target = ":$_library_target_name" 505 } 506 507 if (use_android_unwinder_v2) { 508 _unwind_table_v2_name = "${_library_target_name}_unwind_v2" 509 unwind_table_v2(_unwind_table_v2_name) { 510 library_target = ":$_library_target_name" 511 } 512 } 513 514 _unwind_table_asset_name = "${target_name}__unwind_assets" 515 android_assets(_unwind_table_asset_name) { 516 sources = [ "$target_out_dir/$_unwind_table_name/$unwind_table_asset_v1_filename" ] 517 disable_compression = true 518 deps = [ ":$_unwind_table_name" ] 519 if (use_android_unwinder_v2) { 520 sources += [ "$target_out_dir/$_unwind_table_v2_name/$unwind_table_asset_v2_filename" ] 521 deps += [ ":$_unwind_table_v2_name" ] 522 } 523 } 524 } 525 526 _generate_final_jni = 527 !defined(invoker.generate_final_jni) || invoker.generate_final_jni 528 mixed_test(_library_target_name) { 529 if (_generate_final_jni) { 530 target_type = "shared_library_with_jni" 531 java_targets = [ ":$_apk_target_name" ] 532 } else { 533 target_type = "shared_library" 534 } 535 536 # Configs will always be defined since we set_defaults in 537 # BUILDCONFIG.gn. 538 configs = [] # Prevent list overwriting warning. 539 configs = invoker.configs 540 541 forward_variables_from( 542 invoker, 543 "*", 544 [ 545 "configs", 546 "deps", 547 ] + _apk_specific_vars + _wrapper_script_vars + 548 TESTONLY_AND_VISIBILITY) 549 550 # Use a crate name that avoids creating a warning due to double 551 # underscore (ie. `__`). 552 crate_name = _library_crate_name 553 554 # Native targets do not need to depend on java targets. Filter them out 555 # so that the shared library can be built without needing to wait for 556 # dependent java targets. 557 if (!defined(deps)) { 558 deps = [] 559 } 560 if (defined(invoker.deps)) { 561 deps += filter_exclude(invoker.deps, java_target_patterns) 562 } 563 564 if (_use_default_launcher) { 565 deps += [ "//testing/android/native_test:native_test_native_code" ] 566 } 567 } 568 unittest_apk(_apk_target_name) { 569 forward_variables_from(invoker, _apk_specific_vars) 570 shared_library = ":$_library_target_name" 571 if (_generate_final_jni) { 572 srcjar_deps = [ "${shared_library}__jni_registration" ] 573 } 574 apk_name = invoker.target_name 575 if (defined(invoker.output_name)) { 576 apk_name = invoker.output_name 577 } 578 579 if (defined(invoker.deps)) { 580 deps = invoker.deps 581 } else { 582 deps = [] 583 } 584 if (defined(loadable_module_deps)) { 585 deps += loadable_module_deps 586 } 587 588 # Add the Java classes so that each target does not have to do it. 589 if (_use_default_launcher) { 590 deps += [ "//base/test:test_support_java" ] 591 } 592 593 if (defined(_unwind_table_asset_name)) { 594 deps += [ ":${_unwind_table_asset_name}" ] 595 } 596 } 597 } 598 599 test_runner_script(_test_runner_target) { 600 forward_variables_from(invoker, _wrapper_script_vars) 601 602 if (_use_raw_android_executable) { 603 executable_dist_dir = "$root_out_dir/$_dist_target" 604 data_deps = [ ":$_exec_target" ] 605 } else { 606 apk_target = ":$_apk_target_name" 607 incremental_apk = incremental_install 608 609 # Dep needed for the test runner .runtime_deps file to pick up data 610 # deps from the forward_variables_from(invoker, "*") on the library. 611 data_deps = [ ":$_library_target_name" ] 612 } 613 test_name = _output_name 614 test_suite = _output_name 615 test_type = "gtest" 616 } 617 618 # Create a wrapper script rather than using a group() in order to ensure 619 # "ninja $target_name" always works. If this was a group(), then GN would 620 # not create a top-level alias for it if a target exists in another 621 # directory with the same $target_name. 622 # Also - bots run this script directly for "components_perftests". 623 generate_wrapper(target_name) { 624 forward_variables_from(invoker, [ "visibility" ]) 625 executable = "$root_build_dir/bin/run_$_output_name" 626 wrapper_script = "$root_build_dir/$_output_name" 627 deps = [ ":$_test_runner_target" ] 628 if (_use_raw_android_executable) { 629 deps += [ ":$_dist_target" ] 630 } else { 631 # Dep needed for the swarming .isolate file to pick up data 632 # deps from the forward_variables_from(invoker, "*") on the library. 633 deps += [ 634 ":$_apk_target_name", 635 ":$_library_target_name", 636 ] 637 } 638 639 if (defined(invoker.data_deps)) { 640 data_deps = invoker.data_deps 641 } else { 642 data_deps = [] 643 } 644 645 data_deps += [ "//testing:test_scripts_shared" ] 646 647 if (tests_have_location_tags) { 648 data = [ "//testing/location_tags.json" ] 649 } 650 } 651 } else if (is_fuchsia) { 652 assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb) 653 654 _output_name = invoker.target_name 655 _pkg_target = "${_output_name}_pkg" 656 _exec_target = "${_output_name}__exec" 657 _program_name = get_label_info(":${_exec_target}", "name") 658 _crate_name = _output_name 659 660 # Generate a CML fragment that provides the program name. 661 _test_program_fragment_target = "${target_name}_program-fragment" 662 _test_program_fragment = "${target_out_dir}/${target_name}_program.test-cml" 663 generated_file(_test_program_fragment_target) { 664 contents = { 665 program = { 666 binary = _program_name 667 } 668 } 669 outputs = [ _test_program_fragment ] 670 output_conversion = "json" 671 } 672 673 _test_runner_shard = 674 "//build/config/fuchsia/test/elf_test_runner.shard.test-cml" 675 if (defined(invoker.test_runner_shard)) { 676 _test_runner_shard = invoker.test_runner_shard 677 } 678 679 # Collate the complete set of elements to include in the test component's 680 # manifest. 681 682 _manifest_fragments = [ 683 _test_program_fragment, 684 _test_runner_shard, 685 ] 686 687 # Select the Fuchsia test realm in which to run the test. 688 if (defined(invoker.run_as_chromium_system_test) && 689 invoker.run_as_chromium_system_test) { 690 _manifest_fragments += [ 691 "//build/config/fuchsia/test/chromium_system_test_facet.shard.test-cml", 692 "//build/config/fuchsia/test/system_test_minimum.shard.test-cml", 693 ] 694 } else { 695 _manifest_fragments += [ 696 "//build/config/fuchsia/test/chromium_test_facet.shard.test-cml", 697 "//build/config/fuchsia/test/minimum.shard.test-cml", 698 ] 699 } 700 701 if (is_asan) { 702 # TODO(crbug.com/1465997): Remove the extra cml segment for asan. 703 _manifest_fragments += 704 [ "//build/config/fuchsia/test/asan_options.shard.test-cml" ] 705 } 706 707 _test_component_manifest = "${target_out_dir}/${target_name}.cml" 708 _merged_manifest_name = "${_output_name}.cml" 709 710 if (defined(invoker.additional_manifest_fragments)) { 711 _manifest_fragments += invoker.additional_manifest_fragments 712 } 713 714 # Generate the test component manifest from the specified elements. 715 _test_component_manifest_target = "${target_name}_component-manifest" 716 cmc_merge(_test_component_manifest_target) { 717 sources = _manifest_fragments 718 output_name = "${_merged_manifest_name}" 719 deps = [ ":${_test_program_fragment_target}" ] 720 } 721 722 # Define the test component, dependent on the generated manifest, and the 723 # test executable target. 724 _test_component_target = "${target_name}_component" 725 fuchsia_component(_test_component_target) { 726 deps = [ ":$_test_component_manifest_target" ] 727 data_deps = [ ":$_exec_target" ] 728 manifest = _test_component_manifest 729 visibility = [ ":*" ] 730 } 731 732 _test_component_targets = [ ":${_test_component_target}" ] 733 734 # Define components for each entry in |additional_manifests|, if any. Since 735 # manifests may themselves depend-on the outputs of |deps|, these components 736 # must each individually depend on |invoker.deps|. 737 if (defined(invoker.additional_manifests)) { 738 foreach(filename, invoker.additional_manifests) { 739 _additional_component_target = 740 target_name + "_" + get_path_info(filename, "name") 741 _test_component_targets += [ ":${_additional_component_target}" ] 742 fuchsia_component(_additional_component_target) { 743 forward_variables_from(invoker, [ "testonly" ]) 744 data_deps = [ ":$_exec_target" ] 745 visibility = [ ":*" ] 746 manifest = filename 747 748 # Depend on |invoker.deps|, in case it includes a dependency that 749 # creates this additional component's manifest. 750 if (defined(invoker.deps)) { 751 deps = invoker.deps 752 } 753 } 754 } 755 } 756 757 # Define the package target that will bundle the test and additional 758 # components and their data. 759 fuchsia_package(_pkg_target) { 760 forward_variables_from(invoker, 761 [ 762 "excluded_files", 763 "excluded_dirs", 764 "excluded_paths", 765 ]) 766 package_name = _output_name 767 deps = _test_component_targets 768 769 if (defined(invoker.fuchsia_package_deps)) { 770 deps += invoker.fuchsia_package_deps 771 } 772 if (!defined(excluded_paths)) { 773 excluded_paths = [] 774 } 775 excluded_paths += [ 776 "${devtools_root_location}/*", 777 "*.git/*", 778 "*.svn/*", 779 "*.hg/*", 780 ] 781 if (devtools_root_location != "") { 782 excluded_paths += [ "${devtools_root_location}/*" ] 783 } 784 } 785 786 # |target_name| refers to the package-runner rule, so that building 787 # "base_unittests" will build not only the executable, component, and 788 # package, but also the script required to run them. 789 fuchsia_test_runner(target_name) { 790 forward_variables_from(invoker, 791 [ 792 "data", 793 "data_deps", 794 "package_deps", 795 "use_test_server", 796 ]) 797 798 is_test_exe = true 799 package = ":$_pkg_target" 800 package_name = _output_name 801 802 if (!defined(deps)) { 803 deps = [] 804 } 805 if (defined(invoker.deps)) { 806 deps += invoker.deps 807 } 808 809 if (!defined(data)) { 810 data = [] 811 } 812 if (tests_have_location_tags) { 813 data += [ "//testing/location_tags.json" ] 814 } 815 816 if (!defined(data_deps)) { 817 data_deps = [] 818 } 819 820 data_deps += [ "//testing:test_scripts_shared" ] 821 } 822 823 mixed_test(_exec_target) { 824 target_type = "executable" 825 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 826 output_name = _exec_target 827 828 if (!defined(deps)) { 829 deps = [] 830 } 831 832 # Use a crate name that avoids creating a warning due to double 833 # underscore (ie. `__`). 834 crate_name = _crate_name 835 } 836 } else if (is_ios) { 837 assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb) 838 _runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" 839 840 declare_args() { 841 # Keep the unittest-as-xctest functionality defaulted to off for 842 # local builds and test executions. 843 enable_run_ios_unittests_with_xctest = false 844 } 845 846 _test_target = target_name 847 848 _wrapper_output_name = "run_${target_name}" 849 ios_test_runner_wrapper(_wrapper_output_name) { 850 forward_variables_from(invoker, 851 [ 852 "clones", 853 "data", 854 "deps", 855 "executable_args", 856 "retries", 857 ]) 858 859 _root_build_dir = rebase_path("${root_build_dir}", root_build_dir) 860 861 if (!defined(executable_args)) { 862 executable_args = [] 863 } 864 executable_args += [ 865 "--app", 866 "@WrappedPath(${_root_build_dir}/${_test_target}.app)", 867 ] 868 869 wrapper_output_name = "${_wrapper_output_name}" 870 871 if (!defined(data)) { 872 data = [] 873 } 874 if (tests_have_location_tags) { 875 data += [ "//testing/location_tags.json" ] 876 } 877 } 878 879 _resources_bundle_data = target_name + "_resources_bundle_data" 880 881 bundle_data(_resources_bundle_data) { 882 visibility = [ ":$_test_target" ] 883 sources = [ "//testing/gtest_ios/Default.png" ] 884 outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] 885 } 886 887 force_xctest = enable_run_ios_unittests_with_xctest || 888 (defined(invoker.is_xctest) && invoker.is_xctest) 889 890 mixed_test(_test_target) { 891 if (force_xctest) { 892 target_type = "ios_xctest_test" 893 } else { 894 target_type = "ios_app_bundle" 895 } 896 testonly = true 897 898 if (force_xctest && build_with_chromium) { 899 xctest_module_target = "//base/test:google_test_runner" 900 } 901 902 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 903 904 # Provide sensible defaults in case invoker did not define any of those 905 # required variables. 906 if (!defined(info_plist) && !defined(info_plist_target)) { 907 info_plist = "//testing/gtest_ios/unittest-Info.plist" 908 } 909 910 bundle_identifier = shared_bundle_id_for_test_apps 911 912 if (!defined(bundle_deps)) { 913 bundle_deps = [] 914 } 915 bundle_deps += [ ":$_resources_bundle_data" ] 916 917 if (!defined(data_deps)) { 918 data_deps = [] 919 } 920 921 data_deps += [ "//testing:test_scripts_shared" ] 922 923 # Include the generate_wrapper as part of data_deps 924 data_deps += [ ":${_wrapper_output_name}" ] 925 write_runtime_deps = _runtime_deps_file 926 if (!defined(deps)) { 927 deps = [] 928 } 929 } 930 } else if ((is_chromeos_ash || (is_chromeos_lacros && is_chromeos_device)) && 931 cros_board != "") { 932 assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb) 933 934 # Building for a cros board (ie: not linux-chromeos or linux-lacros). 935 936 _gen_runner_target = "${target_name}__runner" 937 _runtime_deps_file = 938 "$root_out_dir/gen.runtime/" + get_label_info(target_name, "dir") + 939 "/" + get_label_info(target_name, "name") + ".runtime_deps" 940 941 if (is_skylab && (defined(tast_attr_expr) || defined(tast_tests) || 942 defined(tast_disabled_tests))) { 943 generate_skylab_tast_filter(_gen_runner_target) { 944 } 945 } else { 946 generate_runner_script(_gen_runner_target) { 947 generated_script = "$root_build_dir/bin/run_" + invoker.target_name 948 test_exe = invoker.target_name 949 runtime_deps_file = _runtime_deps_file 950 951 if (is_chromeos_lacros) { 952 # At build time, Lacros tests don't know whether they'll run on VM or 953 # HW, and instead, these flags are specified at runtime when invoking 954 # the generated runner script. 955 skip_generating_board_args = true 956 } 957 958 if (tests_have_location_tags) { 959 data = [ "//testing/location_tags.json" ] 960 } 961 } 962 } 963 964 mixed_test(target_name) { 965 target_type = "executable" 966 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 967 forward_variables_from(invoker, [ "visibility" ]) 968 if (!defined(deps)) { 969 deps = [] 970 } 971 if (!defined(data)) { 972 data = [] 973 } 974 975 # We use a special trigger script for CrOS hardware tests. 976 data += [ "//testing/trigger_scripts/chromeos_device_trigger.py" ] 977 978 write_runtime_deps = _runtime_deps_file 979 data += [ _runtime_deps_file ] 980 deps += [ ":$_gen_runner_target" ] 981 982 if (!defined(data_deps)) { 983 data_deps = [] 984 } 985 986 data_deps += [ "//testing:test_scripts_shared" ] 987 } 988 } else if (is_chromeos_lacros && !is_chromeos_device) { 989 _runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" 990 _executable = target_name 991 _gen_runner_target = "${target_name}__runner" 992 993 if (defined(invoker.use_xvfb)) { 994 _use_xvfb = invoker.use_xvfb 995 } else { 996 _use_xvfb = false 997 } 998 999 # When use_xvfb is set by the invoker, it indicates that running this test 1000 # target requires a window, and in lacros build, ash-chrome serves as the 1001 # display server. Note that even though the tests themselves do not require 1002 # xvfb anymore, xvfb.py is still needed to invoke the lacros test runner 1003 # because ash-chrome is based on x11. 1004 _use_ash_chrome = _use_xvfb 1005 1006 generate_wrapper(_gen_runner_target) { 1007 wrapper_script = "$root_build_dir/bin/run_" + _executable 1008 1009 data = [] 1010 data_deps = [ "//testing:test_scripts_shared" ] 1011 1012 if (_use_xvfb) { 1013 executable = "//testing/xvfb.py" 1014 data += [ "//.vpython3" ] 1015 } else { 1016 executable = "//testing/test_env.py" 1017 } 1018 if (tests_have_location_tags) { 1019 data += [ "//testing/location_tags.json" ] 1020 } 1021 1022 executable_args = [ 1023 "@WrappedPath(../../build/lacros/test_runner.py)", 1024 "test", 1025 "@WrappedPath(./${_executable})", 1026 "--test-launcher-bot-mode", 1027 ] 1028 1029 if (_use_ash_chrome) { 1030 executable_args += [ "--ash-chrome-path" ] 1031 1032 # Can't use --ash-chrome-path=path because WrappedPath 1033 # won't be expanded for that usage. 1034 executable_args += [ "@WrappedPath(./ash_clang_x64/test_ash_chrome)" ] 1035 } 1036 1037 if (is_asan) { 1038 executable_args += [ "--asan=1" ] 1039 } 1040 if (is_msan) { 1041 executable_args += [ "--msan=1" ] 1042 } 1043 if (is_tsan) { 1044 executable_args += [ "--tsan=1" ] 1045 } 1046 if (use_cfi_diag) { 1047 executable_args += [ "--cfi-diag=1" ] 1048 } 1049 if (fail_on_san_warnings) { 1050 executable_args += [ "--fail-san=1" ] 1051 } 1052 1053 data += [ "//build/lacros/test_runner.py" ] 1054 } 1055 1056 mixed_test(target_name) { 1057 target_type = "executable" 1058 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 1059 forward_variables_from(invoker, [ "visibility" ]) 1060 if (!defined(deps)) { 1061 deps = [] 1062 } 1063 1064 if (!defined(data_deps)) { 1065 data_deps = [] 1066 } 1067 1068 data_deps += [ "//testing:test_scripts_shared" ] 1069 1070 write_runtime_deps = _runtime_deps_file 1071 deps += [ ":$_gen_runner_target" ] 1072 if (_use_ash_chrome && also_build_ash_chrome) { 1073 data_deps += [ "//chrome/test:test_ash_chrome(//build/toolchain/linux:ash_clang_x64)" ] 1074 } 1075 } 1076 } else if (!is_nacl) { 1077 if (is_mac || is_win) { 1078 assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb) 1079 } 1080 1081 _runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps" 1082 _executable = target_name 1083 _gen_runner_target = "${target_name}__runner" 1084 1085 if ((is_linux || is_chromeos) && defined(invoker.use_xvfb)) { 1086 _use_xvfb = invoker.use_xvfb 1087 } else { 1088 _use_xvfb = false 1089 } 1090 1091 generate_wrapper(_gen_runner_target) { 1092 wrapper_script = "$root_build_dir/bin/run_" + _executable 1093 1094 data = [] 1095 data_deps = [ "//testing:test_scripts_shared" ] 1096 1097 if (_use_xvfb) { 1098 executable = "//testing/xvfb.py" 1099 } else { 1100 executable = "//testing/test_env.py" 1101 } 1102 if (tests_have_location_tags) { 1103 data += [ "//testing/location_tags.json" ] 1104 } 1105 1106 executable_args = [ 1107 "@WrappedPath(./${_executable})", 1108 "--test-launcher-bot-mode", 1109 ] 1110 if (is_asan) { 1111 executable_args += [ "--asan=1" ] 1112 } 1113 if (is_msan) { 1114 executable_args += [ "--msan=1" ] 1115 } 1116 if (is_tsan) { 1117 executable_args += [ "--tsan=1" ] 1118 } 1119 if (use_cfi_diag) { 1120 executable_args += [ "--cfi-diag=1" ] 1121 } 1122 if (fail_on_san_warnings) { 1123 executable_args += [ "--fail-san=1" ] 1124 } 1125 } 1126 1127 mixed_test(target_name) { 1128 target_type = "executable" 1129 forward_variables_from(invoker, 1130 "*", 1131 TESTONLY_AND_VISIBILITY + [ "use_xvfb" ]) 1132 forward_variables_from(invoker, [ "visibility" ]) 1133 if (!defined(deps)) { 1134 deps = [] 1135 } 1136 1137 deps += [ 1138 # Give tests the default manifest on Windows (a no-op elsewhere). 1139 "//build/win:default_exe_manifest", 1140 ] 1141 1142 write_runtime_deps = _runtime_deps_file 1143 deps += [ ":$_gen_runner_target" ] 1144 1145 if (!defined(data_deps)) { 1146 data_deps = [] 1147 } 1148 1149 data_deps += [ "//testing:test_scripts_shared" ] 1150 } 1151 } else { 1152 # This is a catch-all clause for NaCl toolchains and other random 1153 # configurations that might define tests; test() in these configs 1154 # will just define the underlying executables. 1155 assert(!defined(invoker.use_xvfb) || !invoker.use_xvfb, 1156 "use_xvfb should not be defined for a non-linux configuration") 1157 mixed_test(target_name) { 1158 target_type = "executable" 1159 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 1160 forward_variables_from(invoker, [ "visibility" ]) 1161 if (!defined(deps)) { 1162 deps = [] 1163 } 1164 1165 if (!defined(data_deps)) { 1166 data_deps = [] 1167 } 1168 1169 data_deps += [ "//testing:test_scripts_shared" ] 1170 } 1171 } 1172} 1173 1174# Defines a type of test that invokes a script to run, rather than 1175# invoking an executable. 1176# 1177# The script must implement the 1178# [test executable API](//docs/testing/test_executable_api.md). 1179# 1180# The template must be passed the `script` parameter, which specifies the path 1181# to the script to run. It may optionally be passed a `args` parameter, which 1182# can be used to include a list of args to be specified by default. The 1183# template will produce a `$root_build_dir/run_$target_name` wrapper and write 1184# the runtime_deps for the target to 1185# $root_build_dir/${target_name}.runtime_deps, as per the conventions listed in 1186# the [test wrapper API](//docs/testing/test_wrapper_api.md). 1187template("script_test") { 1188 generate_wrapper(target_name) { 1189 testonly = true 1190 wrapper_script = "${root_build_dir}/bin/run_${target_name}" 1191 1192 executable = "//testing/test_env.py" 1193 1194 executable_args = 1195 [ "@WrappedPath(" + rebase_path(invoker.script, root_build_dir) + ")" ] 1196 if (defined(invoker.args)) { 1197 executable_args += invoker.args 1198 } 1199 1200 data = [ invoker.script ] 1201 1202 if (defined(invoker.data)) { 1203 data += invoker.data 1204 } 1205 if (tests_have_location_tags) { 1206 data += [ "//testing/location_tags.json" ] 1207 } 1208 1209 data_deps = [ "//testing:test_scripts_shared" ] 1210 if (defined(invoker.data_deps)) { 1211 data_deps += invoker.data_deps 1212 } 1213 1214 forward_variables_from(invoker, 1215 "*", 1216 TESTONLY_AND_VISIBILITY + [ 1217 "args", 1218 "data", 1219 "data_deps", 1220 "script", 1221 ]) 1222 forward_variables_from(invoker, [ "visibility" ]) 1223 1224 write_runtime_deps = "${root_build_dir}/${target_name}.runtime_deps" 1225 } 1226} 1227 1228# Defines a test target that uses exit code for pass/fail. 1229template("isolated_script_test") { 1230 script_test(target_name) { 1231 forward_variables_from(invoker, 1232 "*", 1233 TESTONLY_AND_VISIBILITY + [ 1234 "args", 1235 "deps", 1236 "script", 1237 ]) 1238 forward_variables_from(invoker, [ "visibility" ]) 1239 deps = [ "//testing:run_isolated_script_test" ] 1240 if (defined(invoker.deps)) { 1241 deps += invoker.deps 1242 } 1243 script = "//testing/scripts/run_isolated_script_test.py" 1244 data = [ invoker.script ] 1245 args = [ 1246 rebase_path(invoker.script, root_build_dir), 1247 "--script-type=bare", 1248 ] 1249 if (defined(invoker.args)) { 1250 args += invoker.args 1251 } 1252 } 1253} 1254 1255# Test defaults. 1256set_defaults("test") { 1257 if (is_android) { 1258 configs = default_shared_library_configs 1259 configs -= [ "//build/config/android:hide_all_but_jni_onload" ] 1260 configs += [ "//build/config/android:hide_all_but_jni" ] 1261 1262 # Compress sections to stay under 4gb hard limit on 32-bit current_cpu. 1263 # https://crbug.com/1354616 1264 if (symbol_level == 2 && !use_debug_fission && 1265 (current_cpu == "arm" || current_cpu == "x86")) { 1266 configs += [ "//build/config:compress_debug_sections" ] 1267 } 1268 } else { 1269 configs = default_executable_configs 1270 } 1271} 1272