blob: cd4612d38e814ee9289e9ae634b81774c92b9868 [file] [log] [blame]
# Copyright 2018 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/testing/platforms.gni")
# Extension identifying a test spec JSON file.
_test_spec_ext = "spec.json"
# TODO(joshuaseaton): Only used in package() today; consider a scheme in which
# test specs are re-used for host tests.
# Describes the target device environment in which a test should run. This
# specification is written in JSON to the build directory, to be aggregated
# at test-time.
#
# Parameters
#
# location (required)
# [string]: Unique reference to a test, e.g., a filesystem path or a
# fuchsia URI.
#
# output_dir (required)
# [string]: Directory where the test spec will be written.
#
# environments (required)
# [list of scopes] Device environments in which the test should run.
#
# Each scope in $environments contains:
#
# dimensions (required)
# [scope] Dimensions of bots to target. Valid dimensions are
# element-wise subsets of the test platform entries defined in
# //build/testing/platforms.gni.
#
# label (optional)
# [string] A key on which tests may be grouped. Tests with a given
# label will be run (1) together, and (2) only with support from the
# Infrastructure team. Labels are used as an escape hatch from the
# default testing pipeline for special tests or environments.
#
template("test_spec") {
assert(defined(invoker.location), "location must be defined.")
assert(defined(invoker.output_dir), "output_dir must be defined.")
assert(defined(invoker.environments) && invoker.environments != [],
"environments must be defined.")
foreach(env, invoker.environments) {
empty_scope = { # Clear from previous iteration
}
assert(defined(env.dimensions) && env.dimensions != empty_scope,
"each environment must specify dimensions")
}
# Call "expanding" the operation that takes a scope
# {
# x = a
# y = b
# z = c
# ...
# }
# and converts it to a list [{x=a}, {y=b}, {z=c},...].
#
# Expand each scope of test platform dimensions and group them by architecture
# (i.e., cpu). The same thing is done below with each environment's dimensions
# scope to more easily compare.
target_platform_dims = []
other_platform_dims = []
foreach(platform, test_platforms) {
platform_dims = [] # Clear from previous iteration.
foreach(key, all_dimension_keys) {
platform_dims += [
{
forward_variables_from(platform, [ key ])
},
]
}
if (platform.cpu == current_cpu) {
target_platform_dims += [ platform_dims ]
} else {
other_platform_dims += [ platform_dims ]
}
}
target_envs = []
foreach(env, invoker.environments) {
dims = [] # Clear from previous iteration.
if (defined(env.dimensions)) {
foreach(key, all_dimension_keys) {
dims += [
{
forward_variables_from(env.dimensions, [ key ])
},
]
}
}
# Empty scopes may have been introduced to dims, corresponding to unset keys;
# Add and then subtract an empty scope to remove them.
empty_dim = { # Clear from previous iteration.
}
dims += [ empty_dim ]
dims -= [ empty_dim ]
# Check if the environment's dimensions match those of a platform of the
# target architecture; if a match, include the environment among the
# test spec's.
# Note that in GN "A is a subset of B" is equivalent to `A + B - B == []`.
match = false
foreach(platform_dims, target_platform_dims) {
if (dims + platform_dims - platform_dims == []) {
match = true
target_envs += [ env ]
}
}
# If the environment's dimensions do not match a target architecture, ensure
# that they match those of a platform of another architecture.
if (!match) {
foreach(platform_dims, other_platform_dims) {
match = match || dims + platform_dims - platform_dims == []
}
if (!match) {
print("Could not match environment specifications for '$target_name':")
print("$env")
assert(
match,
"Consult //build/testing/platforms.gni for all allowable specifications")
}
}
}
test_spec = {
test = {
name = get_label_info(":$target_name", "label_no_toolchain")
location = invoker.location
}
environments = target_envs
}
# TODO(IN-571): Delete this block once vim2s are ready to be targeted.
foreach(env, target_envs) {
dims = [] # Clear from previous iteration.
dims = env.dimensions
if (defined(dims.device_type) && dims.device_type == "Khadas Vim2 Max") {
assert(defined(env.label) && env.label == "vim2",
"vim2s may not yet be targeted.")
}
}
# We take the basename just to make sure no other path components are given
# in the name, for which we have no guarantees.
target_base_name = get_path_info(target_name, "name")
write_file("${invoker.output_dir}/${target_base_name}.${_test_spec_ext}",
test_spec,
"json")
}