• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}+sys-firmware/seabios"),
73        rebase_path("${_cache_path_prefix}+chromiumos_test_image.tar.xz"),
74        rebase_path("${_cache_path_prefix}+app-emulation/qemu"),
75      ]
76    }
77    _symlink_map += [ [
78          b,
79          _symlinks,
80        ] ]
81  }
82
83  _all_symlinks = []
84  foreach(m, _symlink_map) {
85    _all_symlinks += m[1]
86  }
87  _all_symlink_targets =
88      exec_script("//build/get_symlink_targets.py", _all_symlinks, "list lines")
89  _index = 0
90  foreach(m, _symlink_map) {
91    _symlink_targets = []
92    foreach(_, m[1]) {
93      _symlink_targets += [ _all_symlink_targets[_index] ]
94      _index += 1
95    }
96
97    _symlink_targets_map += [ [
98          m[0],
99          _symlink_targets,
100        ] ]
101  }
102}
103
104template("generate_chromeos_sdk_deps") {
105  forward_variables_from(invoker,
106                         [
107                           "deploy_chrome",
108                           "is_tast",
109                         ])
110  if (!defined(deploy_chrome)) {
111    deploy_chrome = false
112  }
113  if (!defined(is_tast)) {
114    is_tast = false
115  }
116
117  _sdk_data = []
118  assert(cros_sdk_version != "", "cros sdk version is not defined")
119  foreach(b, _potential_test_boards) {
120    _cros_is_vm = false
121    foreach(b1, string_split(cros_boards_with_qemu_images, ":")) {
122      if (b == b1) {
123        _cros_is_vm = true
124      }
125    }
126
127    # Determine the real paths for various items in the SDK, which may be used
128    # in the 'generate_runner_script' template below.
129    if (is_tast || _cros_is_vm || deploy_chrome) {
130      _symlink_targets = []
131      foreach(m, _symlink_targets_map) {
132        if (b == m[0]) {
133          _symlink_targets = []
134          _symlink_targets = m[1]
135        }
136      }
137
138      if (is_tast) {
139        # Add tast sdk items.
140        _sdk_data += [ _symlink_targets[0] ]
141      }
142      if (deploy_chrome) {
143        # To deploy chrome to the VM, it needs to be stripped down to fit into
144        # the VM. This is done by using binutils in the toolchain. So add the
145        # toolchain to the data.
146        _sdk_data += [
147          _symlink_targets[1],
148          _symlink_targets[2],
149        ]
150      }
151      if (_cros_is_vm) {
152        # Add vm sdk items.
153        _sdk_data += [
154          _symlink_targets[3],
155          _symlink_targets[4],
156          _symlink_targets[5],
157        ]
158      }
159    }
160  }
161  group(target_name) {
162    data = _sdk_data
163    data += [
164      # Needed for various SDK components used below.
165      "//build/cros_cache/chrome-sdk/misc/",
166      "//build/cros_cache/chrome-sdk/symlinks/",
167      "//chrome/VERSION",
168
169      # The LKGM file controls what version of the VM image to download. Add it
170      # as data here so that changes to it will trigger analyze.
171      "//chromeos/CHROMEOS_LKGM",
172    ]
173  }
174}
175
176# Creates tast filter files for skylab tast tests.
177# Args:
178#   tast_attr_expr: Tast expression to determine tests to run. This creates the
179#       initial set of tests that can be further filtered..
180#   tast_tests: Names of tests to enable in tast. All other tests will be
181#       disabled that are not listed.
182#   tast_disabled_tests: Names of tests to disable in tast. All other tests that
183#       match the tast expression will still run.
184#   tast_control: gni file with collections of tests to be used for specific
185#       filters (e.g. "//chromeos/tast_control.gni"). Any lists of strings in
186#       this file will be used to generate additional tast expressions with
187#       those strings expanded into tests to disable (i.e. as && !"name:test").
188#       The name of those lists are then intended to be used to specify in
189#       test_suites.pyl which collection to be used on specific test suites.
190template("generate_skylab_tast_filter") {
191  forward_variables_from(invoker,
192                         [
193                           "tast_attr_expr",
194                           "tast_tests",
195                           "tast_disabled_tests",
196                           "tast_control",
197                         ])
198
199  if (defined(tast_disabled_tests)) {
200    assert(defined(tast_attr_expr),
201           "tast_attr_expr must be used when specifying tast_disabled_tests.")
202  }
203  _generated_filter = "$root_build_dir/bin/${target_name}.filter"
204  _skylab_args = [
205    "generate-filter",
206    "--output",
207    rebase_path(_generated_filter),
208  ]
209  if (defined(tast_control)) {
210    _skylab_args += [
211      "--tast-control",
212      rebase_path(tast_control),
213    ]
214  }
215  if (defined(tast_attr_expr)) {
216    _skylab_args += [
217      "--tast-expr",
218      tast_attr_expr,
219    ]
220  }
221  if (defined(tast_tests)) {
222    foreach(_test, tast_tests) {
223      _skylab_args += [
224        "--enabled-tests",
225        _test,
226      ]
227    }
228  }
229  if (defined(tast_disabled_tests)) {
230    foreach(_test, tast_disabled_tests) {
231      _excluded_test_name_and_board = []
232      _excluded_test_name_and_board = string_split(_test, "@") + [ "" ]
233      _excluded_test_name = _excluded_test_name_and_board[0]
234      _excluded_board = _excluded_test_name_and_board[1]
235      if (_excluded_board == "" || _excluded_board == cros_board) {
236        _skylab_args += [
237          "--disabled-tests",
238          _excluded_test_name,
239        ]
240      }
241    }
242  }
243  action(target_name) {
244    testonly = true
245    script = "//build/chromeos/generate_skylab_tast_filter.py"
246    if (defined(tast_control)) {
247      sources = [ tast_control ]
248    }
249    outputs = [ _generated_filter ]
250    args = _skylab_args
251    if (defined(invoker.data_deps)) {
252      data_deps = invoker.data_deps
253    }
254    data = [ _generated_filter ]
255    if (defined(invoker.data)) {
256      data += invoker.data
257    }
258    if (defined(invoker.deps)) {
259      deps = invoker.deps
260    }
261  }
262}
263
264# Creates a script at $generated_script that can be used to launch a cros VM
265# and optionally run a test within it.
266# Args:
267#   test_exe: Name of test binary located in the out dir. This will get copied
268#       to the VM and executed there.
269#   tast_attr_expr: Tast expression to pass to local_test_runner on the VM.
270#   tast_tests: List of Tast tests to run on the VM. Note that when this is
271#       specified, the target name used to invoke this template will be
272#       designated as the "name" of this test and will primarly used for test
273#       results tracking and displaying (eg: flakiness dashboard).
274#   generated_script: Path to place the generated script.
275#   deploy_chrome: If true, deploys a locally built chrome located in the root
276#       build dir to the VM or DUT after launching it.
277#   deploy_lacros: If true, deploys a locally built Lacros located in the root
278#       build dir to the VM or DUT after launching it.
279#   runtime_deps_file: Path to file listing runtime deps for the test. If set,
280#       all files listed will be copied to the VM before testing.
281#   skip_generating_board_args: By default, this template generates an '--board'
282#       arg with corresponding '--flash' or '--use-vm' args for device and vm
283#       respectively. This argument instructs the template to skip generating
284#       them, and it's designed for use cases where one builds for one board
285#       (e.g. amd64-generic), but tests on a different board (e.g. eve).
286#   tast_vars: A list of "key=value" runtime variable pairs to pass to invoke
287#   strip_chrome: If true, strips Chrome before deploying it for non-Tast tests.
288#       the Tast tests. For more details, please see:
289#       https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/docs/writing_tests.md#Runtime-variables
290template("generate_runner_script") {
291  forward_variables_from(invoker,
292                         [
293                           "deploy_chrome",
294                           "deploy_lacros",
295                           "generated_script",
296                           "runtime_deps_file",
297                           "skip_generating_board_args",
298                           "strip_chrome",
299                           "tast_attr_expr",
300                           "tast_tests",
301                           "tast_vars",
302                           "testonly",
303                           "test_exe",
304                         ])
305
306  if (!defined(skip_generating_board_args)) {
307    # --board should be assigned by the autotest wrapper on skylab builders
308    skip_generating_board_args = is_skylab
309  }
310
311  if (skip_generating_board_args) {
312    # cros_board is not needed, so setting it to empty to avoid being used
313    # accidentally below.
314    cros_board = ""
315    not_needed([ cros_board ])
316  }
317
318  if (!defined(deploy_chrome)) {
319    deploy_chrome = false
320  }
321  if (!defined(deploy_lacros)) {
322    deploy_lacros = false
323  }
324  if (!defined(strip_chrome)) {
325    strip_chrome = false
326  }
327  is_tast = defined(tast_attr_expr) || defined(tast_tests)
328  assert(!(is_tast && defined(test_exe)),
329         "Tast tests are invoked from binaries shipped with the VM image. " +
330             "There should be no locally built binary needed.")
331  assert(is_tast || !defined(tast_vars),
332         "tast_vars is only support for Tast tests")
333
334  if (is_tast) {
335    not_needed([ "strip_chrome" ])
336  }
337
338  # If we're in the cros chrome-sdk (and not the raw ebuild), the test will
339  # need some additional runtime data located in the SDK cache.
340  if (cros_sdk_version != "") {
341    assert(defined(generated_script),
342           "Must specify where to place generated test launcher script via " +
343               "'generated_script'")
344
345    generate_chromeos_sdk_deps(target_name + "_cros_deps__helper") {
346      is_tast = is_tast
347      deploy_chrome = deploy_chrome
348    }
349  }
350
351  generate_wrapper(target_name) {
352    executable = "//build/chromeos/test_runner.py"
353    wrapper_script = generated_script
354    executable_args = []
355
356    if (defined(runtime_deps_file)) {
357      write_runtime_deps = runtime_deps_file
358    }
359
360    # Build executable_args for the three different test types: GTest, Tast,
361    # and host-side commands (eg telemetry).
362    if (defined(test_exe)) {
363      executable_args += [
364        "gtest",
365        "--test-exe",
366        test_exe,
367      ]
368
369      # This target is not a gtest unit test, but an integration test suite.
370      # Similar to interactive ui tests, it would start a full browser and
371      # then do testing.
372      # See more at //docs/testing/chromeos_integration.
373      if (test_exe == "chromeos_integration_tests") {
374        # Run the test sudo helper.
375        executable_args += [ "--run-test-sudo-helper" ]
376
377        if (is_chromeos_ash) {
378          # For ash, it need to first stop the existing ash.
379          executable_args += [ "--stop-ui" ]
380        }
381
382        # Lacros need to know the wayland socket file created by Ash.
383        # In this way, Lacros will be connected to the system Ash.
384        if (is_chromeos_lacros) {
385          executable_args += [
386            "--env-var",
387            "XDG_RUNTIME_DIR",
388            "/run/chrome",
389          ]
390        }
391
392        # Make the tests match the browser's selinux tags so it gets the same
393        # security context as the browser would.
394        executable_args += [ "--set-selinux-label=chromeos_integration_tests=u:object_r:chrome_browser_exec:s0" ]
395      }
396      if (defined(runtime_deps_file)) {
397        executable_args += [
398          "--runtime-deps-path",
399          rebase_path(runtime_deps_file, root_build_dir),
400        ]
401      }
402    } else if (is_tast) {
403      # When --tast-tests is specified, test_runner.py will call
404      # local_test_runner on the VM to run the set of tests.
405      executable_args += [
406        "tast",
407        "--suite-name",
408        target_name,
409      ]
410      if (defined(tast_attr_expr)) {
411        executable_args += [
412          "--attr-expr",
413          tast_attr_expr,
414        ]
415      } else {
416        foreach(test, tast_tests) {
417          executable_args += [
418            "-t",
419            test,
420          ]
421        }
422      }
423      if (defined(tast_vars)) {
424        foreach(var, tast_vars) {
425          executable_args += [
426            "--tast-var",
427            var,
428          ]
429        }
430      }
431      if (dcheck_always_on) {
432        executable_args += [
433          "--tast-extra-use-flags",
434          "chrome_dcheck",
435        ]
436      }
437    } else {
438      executable_args += [ "host-cmd" ]
439    }
440    executable_args += [
441      "--cros-cache",
442      "build/cros_cache/",
443      "--path-to-outdir",
444      rebase_path(root_out_dir, "//"),
445      "-v",
446    ]
447
448    if (!is_tast && strip_chrome) {
449      executable_args += [ "--strip-chrome" ]
450    }
451
452    if (!skip_generating_board_args) {
453      executable_args += [
454        "--board",
455        cros_board,
456      ]
457
458      _cros_is_vm = false
459      foreach(b, string_split(cros_boards_with_qemu_images, ":")) {
460        if (cros_board == b) {
461          _cros_is_vm = true
462        }
463      }
464      if (_cros_is_vm) {
465        executable_args += [ "--use-vm" ]
466      } else {
467        executable_args += [ "--flash" ]
468      }
469    }
470
471    # If we have public Chromium builds, use public Chromium OS images when
472    # flashing the test device.
473    if (!is_chrome_branded) {
474      executable_args += [ "--public-image" ]
475    }
476
477    if (deploy_lacros) {
478      executable_args += [ "--deploy-lacros" ]
479    }
480
481    if (deploy_chrome && !defined(test_exe)) {
482      executable_args += [ "--deploy-chrome" ]
483    }
484
485    # executable_args should be finished, now build the data and deps lists.
486    deps = [ "//testing/buildbot/filters:chromeos_filters" ]
487    if (defined(invoker.deps)) {
488      deps += invoker.deps
489    }
490    data = [
491      "//.vpython3",
492
493      # We use android test-runner's results libs to construct gtest output
494      # json.
495      "//build/android/pylib/__init__.py",
496      "//build/android/pylib/base/",
497      "//build/android/pylib/results/",
498      "//build/chromeos/",
499      "//build/util/",
500      "//third_party/chromite/",
501    ]
502
503    if (defined(invoker.data)) {
504      data += invoker.data
505    }
506
507    data_deps = [ "//testing:test_scripts_shared" ]
508    if (cros_sdk_version != "") {
509      data_deps += [ ":" + target_name + "_cros_deps__helper" ]
510    }
511    if (defined(invoker.data_deps)) {
512      data_deps += invoker.data_deps
513    }
514  }
515}
516
517template("tast_test") {
518  forward_variables_from(invoker, "*")
519
520  # Default the expression to match any chrome-related test.
521  if (!defined(tast_attr_expr) && !defined(tast_tests)) {
522    # The following expression filters out all non-critical tests. See the link
523    # below for more details:
524    # https://chromium.googlesource.com/chromiumos/platform/tast/+/main/docs/test_attributes.md
525    tast_attr_expr = "\"group:mainline\" && \"dep:chrome\""
526
527    if (defined(enable_tast_informational_tests) &&
528        enable_tast_informational_tests) {
529      tast_attr_expr += " && informational"
530    } else {
531      tast_attr_expr += " && !informational"
532    }
533    if (!is_chrome_branded) {
534      tast_attr_expr += " && !\"dep:chrome_internal\""
535    }
536  } else {
537    assert(defined(tast_attr_expr) != defined(tast_tests),
538           "Specify one of tast_tests or tast_attr_expr.")
539  }
540
541  _data_deps = [
542    "//:chromiumos_preflight",  # Builds the browser.
543    "//chromeos:cros_chrome_deploy",  # Adds additional browser run-time deps.
544
545    # Tools used to symbolize Chrome crash dumps.
546    # TODO(crbug.com/1156772): Remove these if/when all tests pick them up by
547    # default.
548    "//third_party/breakpad:dump_syms",
549    "//third_party/breakpad:minidump_dump",
550    "//third_party/breakpad:minidump_stackwalk",
551  ]
552  _data = [ "//components/crash/content/tools/generate_breakpad_symbols.py" ]
553
554  if (is_skylab) {
555    generate_skylab_tast_filter(target_name) {
556      # chromite.deploy_chrome is needed for sideloading Chrome.
557      data = _data + [ "//third_party/chromite/" ]
558      data_deps = _data_deps
559
560      # To disable a test on specific milestones, add it to the appropriate
561      # collection in the following file
562      tast_control = "//chromeos/tast_control.gni"
563    }
564  } else {
565    # Append any disabled tests to the expression.
566    if (defined(tast_disabled_tests)) {
567      assert(defined(tast_attr_expr),
568             "tast_attr_expr must be used when specifying tast_disabled_tests.")
569      foreach(_test, tast_disabled_tests) {
570        _excluded_test_name_and_board = []
571        _excluded_test_name_and_board = string_split(_test, "@") + [ "" ]
572        _excluded_test_name = _excluded_test_name_and_board[0]
573        _excluded_board = _excluded_test_name_and_board[1]
574        if (_excluded_board == "" || _excluded_board == cros_board) {
575          tast_attr_expr += " && !\"name:${_excluded_test_name}\""
576        }
577      }
578    }
579    if (defined(tast_attr_expr)) {
580      tast_attr_expr = "( " + tast_attr_expr + " )"
581    }
582    generate_runner_script(target_name) {
583      testonly = true
584      generated_script = "$root_build_dir/bin/run_${target_name}"
585      runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps"
586      deploy_chrome = true
587
588      data_deps = _data_deps
589      if (!defined(deploy_lacros_chrome)) {
590        deploy_lacros_chrome = false
591      }
592      deploy_lacros = deploy_lacros_chrome
593      data = _data
594      if (deploy_lacros_chrome) {
595        data += [
596          # A script needed to launch Lacros in Lacros Tast tests.
597          "//build/lacros/mojo_connection_lacros_launcher.py",
598        ]
599
600        # By default, tast tests download a lacros-chrome from a gcs location and
601        # use it for testing. To support running lacros tast tests from Chromium CI,
602        # a Var is added to support pointing the tast tests to use a specified
603        # pre-deployed lacros-chrome. The location is decided by:
604        # https://source.chromium.org/chromium/chromium/src/+/main:third_party/chromite/scripts/deploy_chrome.py;l=80;drc=86f1234a4be8e9574442e076cdc835897f7bea61
605        tast_vars = [ "lacros.DeployedBinary=/usr/local/lacros-chrome" ]
606      }
607    }
608  }
609}
610
611template("lacros_tast_tests") {
612  forward_variables_from(invoker,
613                         [
614                           "tast_attr_expr",
615                           "tast_disabled_tests",
616                           "tast_tests",
617                           "tast_control",
618                         ])
619  assert(defined(tast_attr_expr) != defined(tast_tests),
620         "Specify one of tast_tests or tast_attr_expr.")
621
622  _lacros_data_deps = [
623    "//chrome",  # Builds the browser.
624
625    # Tools used to symbolize Chrome crash dumps.
626    # TODO(crbug.com/1156772): Remove these if/when all tests pick them up by
627    # default.
628    "//third_party/breakpad:dump_syms",
629    "//third_party/breakpad:minidump_dump",
630    "//third_party/breakpad:minidump_stackwalk",
631  ]
632
633  _lacros_data = [
634    "//components/crash/content/tools/generate_breakpad_symbols.py",
635
636    # A script needed to launch Lacros in Lacros Tast tests.
637    "//build/lacros/mojo_connection_lacros_launcher.py",
638  ]
639
640  if (is_skylab) {
641    generate_skylab_tast_filter(target_name) {
642      data = _lacros_data + [
643               "//.vpython3",
644               "//third_party/chromite/",
645             ]
646      data_deps = _lacros_data_deps
647
648      # To disable a test on specific milestones, add it to the appropriate
649      # collection in the following file
650      tast_control = "//chromeos/tast_control.gni"
651    }
652  } else {
653    # Append any disabled tests to the expression.
654    if (defined(tast_disabled_tests)) {
655      assert(defined(tast_attr_expr),
656             "tast_attr_expr must be used when specifying tast_disabled_tests.")
657      foreach(_test, tast_disabled_tests) {
658        _excluded_test_name_and_board = []
659        _excluded_test_name_and_board = string_split(_test, "@") + [ "" ]
660        _excluded_test_name = _excluded_test_name_and_board[0]
661        _excluded_board = _excluded_test_name_and_board[1]
662        if (_excluded_board == "" || _excluded_board == cros_board) {
663          tast_attr_expr += " && !\"name:${_excluded_test_name}\""
664        }
665      }
666    }
667    if (defined(tast_attr_expr)) {
668      tast_attr_expr = "( " + tast_attr_expr + " )"
669    }
670    generate_runner_script(target_name) {
671      testonly = true
672      deploy_lacros = true
673      generated_script = "$root_build_dir/bin/run_${target_name}"
674      runtime_deps_file = "$root_out_dir/${target_name}.runtime_deps"
675
676      # At build time, Lacros tests don't know whether they'll run on VM or HW,
677      # and instead, these flags are specified at runtime when invoking the
678      # generated runner script.
679      skip_generating_board_args = true
680
681      # By default, tast tests download a lacros-chrome from a gcs location and
682      # use it for testing. To support running lacros tast tests from Chromium CI,
683      # a Var is added to support pointing the tast tests to use a specified
684      # pre-deployed lacros-chrome. The location is decided by:
685      # https://source.chromium.org/chromium/chromium/src/+/main:third_party/chromite/scripts/deploy_chrome.py;l=80;drc=86f1234a4be8e9574442e076cdc835897f7bea61
686      tast_vars = [ "lacros.DeployedBinary=/usr/local/lacros-chrome" ]
687
688      data_deps = _lacros_data_deps
689
690      data = _lacros_data
691    }
692  }
693}
694