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