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