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