Skip to content

Commit

Permalink
Generating separate binaries for each unit test for EFR32 (#35028)
Browse files Browse the repository at this point in the history
* silabs full changes, flashable just if

* silabs full changes, flashable just if (corrected)

* silabs changes, flashable changes

* yes executables.gni, cts.gni, args.gni, test_driver build.gn

* yes executables.gni, args.gni, test_driver build.gn

* Modified chip_test_suite to handle logic for both efr32 test_driver and chip_link_test

* Doc update

* Added final newline

* Comment updates

* Remove deprecated `tests` variable for per-test custom mains.

* switched to shutil.copy instead of subprocess copy

* Added chip_link_tests to test_driver/efr32/args.gni and removed special logic from chip_test_suite

* Restyled by gn

* Restyled by autopep8

* Punctuation change

* Added special exception for darwin to always include test_sources in common lib.

* Added comment re darwin exception

* Restyled by gn

* Revisions to builder scripts - removing map() usage and propagating OSError to make_wrapper.

* Restyled by autopep8

---------

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
feasel0 and restyled-commits authored Sep 4, 2024
1 parent 44f8837 commit 6144736
Show file tree
Hide file tree
Showing 17 changed files with 265 additions and 378 deletions.
2 changes: 0 additions & 2 deletions .github/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -950,8 +950,6 @@ NitricOxideConcentrationMeasurement
NitrogenDioxideConcentrationMeasurement
nl
nltest
NLUnitTest
NLUnitTests
nmcli
nmtui
noc
Expand Down
71 changes: 0 additions & 71 deletions build/chip/chip_test.gni

This file was deleted.

101 changes: 42 additions & 59 deletions build/chip/chip_test_suite.gni
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@

import("//build_overrides/build.gni")
import("//build_overrides/chip.gni")
import("//build_overrides/pigweed.gni")

import("${chip_root}/build/chip/chip_test.gni")
import("${chip_root}/build/chip/tests.gni")
import("${dir_pw_unit_test}/test.gni")

assert(chip_build_tests)

declare_args() {
# These may be overridden in args.gni to build platform-specific test binaries.
test_executable_output_name = ""
test_executable_output_name_suffix = ""
test_executable_ldflags = []
}

# Define CHIP unit tests
#
# Simple usage
Expand All @@ -41,50 +48,34 @@ assert(chip_build_tests)
# "${chip_root}/src/lib/foo", # add dependencies here
# ]
# }
#
#
# Deprecated usage (writing own driver files):
#
# chip_test_suite("tests") {
# output_name = "libFooTests"
#
# sources = [
# "TestDeclarations.h",
# "TestFoo.cpp",
# "TestBar.cpp",
# ]
#
# public_deps = [
# "${chip_root}/src/lib/foo", # add dependencies here
# ]
#
# tests = [
# "TestFoo", # Assumes TestFooDriver.cpp exists
# "TestBar", # Assumes TestBarDriver.cpp exists
# ]
# }

#
template("chip_test_suite") {
_suite_name = target_name

# Ensures that the common library has sources containing both common
# and individual unit tests.
if (!defined(invoker.sources)) {
invoker.sources = []
}

if (defined(invoker.test_sources)) {
invoker.sources += invoker.test_sources
exclude_variables = [ "tests" ]
if (chip_link_tests && chip_device_platform != "darwin") {
# Common library shouldn't have all the individual unit tests, only the common sources.
exclude_variables += [ "test_sources" ]
# NOTE: For `Build on Darwin (clang, python_lib, simulated)` the test_sources must be in common lib.
} else {
# Common library should have all the individual unit tests, in addition to the common sources.
if (!defined(invoker.sources)) {
invoker.sources = []
}
if (defined(invoker.test_sources)) {
invoker.sources += invoker.test_sources
}
}

# Target for the common library. Contains all the common sources, and sometimes all the individual test sources.
if (chip_build_test_static_libraries) {
_target_type = "static_library"
} else {
_target_type = "source_set"
}
target(_target_type, "${_suite_name}.lib") {
forward_variables_from(invoker, "*", [ "tests" ])
forward_variables_from(invoker, "*", exclude_variables)

output_dir = "${root_out_dir}/lib"

Expand All @@ -102,6 +93,8 @@ template("chip_test_suite") {
public_deps += [ "${chip_root}/src/platform/logging:default" ]
}
}

# Build a source_set or a flashable executable for each individual unit test source, which also includes the common files.
if (chip_link_tests) {
tests = []

Expand All @@ -115,50 +108,38 @@ template("chip_test_suite") {
}

pw_test(_test_name) {
# Forward certain variables from the invoker.
forward_variables_from(invoker,
[
"deps",
"public_deps",
"cflags",
"configs",
])

# Link to the common lib for this suite so we get its `sources`.
public_deps += [ ":${_suite_name}.lib" ]
sources = [ _test ]
output_dir = _test_output_dir
}
tests += [ _test_name ]
}
}

if (defined(invoker.tests)) {
foreach(_test, invoker.tests) {
_test_output_dir = "${root_out_dir}/tests"
if (defined(invoker.output_dir)) {
_test_output_dir = invoker.output_dir
}
# Set variables that the platform executable may need.
if (test_executable_output_name != "") {
output_name = test_executable_output_name + _test_name +
test_executable_output_name_suffix
}
ldflags = test_executable_ldflags

# Add the individual test source file (e.g. "TestSomething.cpp").
sources = [ _test ]

pw_test(_test) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"cflags",
"configs",
])
public_deps += [ ":${_suite_name}.lib" ]
test_main = ""
sources = [
"${_test}.cpp",
"${_test}Driver.cpp",
]
output_dir = _test_output_dir
}
tests += [ _test ]
tests += [ _test_name ]
}
}

group(_suite_name) {
deps = []

# Add each individual unit test.
foreach(_test, tests) {
deps += [ ":${_test}" ]
}
Expand All @@ -167,6 +148,8 @@ template("chip_test_suite") {
if (chip_pw_run_tests) {
group("${_suite_name}_run") {
deps = []

# Add the .run targets created by pw_test.
foreach(_test, tests) {
deps += [ ":${_test}.run" ]
}
Expand Down
18 changes: 13 additions & 5 deletions build/toolchain/flashable_executable.gni
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ template("gen_flashing_script") {
template("flashable_executable") {
executable_target = "$target_name.executable"

if (!defined(invoker.output_dir)) {
invoker.output_dir = root_out_dir
}

if (defined(invoker.flashing_script_name)) {
# Generating the flashing script is the final target.
final_target = "$target_name.flashing"
Expand All @@ -110,7 +114,10 @@ template("flashable_executable") {
data_deps += invoker.data_deps
}

write_runtime_deps = "${root_out_dir}/${flashbundle_name}"
# Invoker can stop this template from creating the flashbundle.txt by setting flashbundle_name to empty string.
if (flashbundle_name != "") {
write_runtime_deps = "${invoker.output_dir}/${flashbundle_name}"
}
}

if (defined(invoker.objcopy_image_name)) {
Expand All @@ -124,8 +131,8 @@ template("flashable_executable") {
objcopy = invoker.objcopy

objcopy_convert(image_target) {
conversion_input = "${root_out_dir}/${invoker.output_name}"
conversion_output = "${root_out_dir}/${image_name}"
conversion_input = "${invoker.output_dir}/${invoker.output_name}"
conversion_output = "${invoker.output_dir}/${image_name}"
conversion_target_format = image_format
deps = [ ":$executable_target" ]
}
Expand All @@ -141,7 +148,8 @@ template("flashable_executable") {
gen_flashing_script("$target_name.flashing") {
flashing_script_generator = invoker.flashing_script_generator
flashing_script_inputs = invoker.flashing_script_inputs
flashing_script_name = "$root_out_dir/${invoker.flashing_script_name}"
flashing_script_name =
"${invoker.output_dir}/${invoker.flashing_script_name}"
if (defined(invoker.flashing_options)) {
flashing_options = invoker.flashing_options
} else {
Expand All @@ -155,7 +163,7 @@ template("flashable_executable") {

flashing_options += [
"--application",
rebase_path(image_name, root_out_dir, root_out_dir),
rebase_path(image_name, invoker.output_dir, invoker.output_dir),
]
data_deps = [ ":$image_target" ]
}
Expand Down
55 changes: 47 additions & 8 deletions scripts/build/builders/efr32.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import glob
import logging
import os
import shlex
import subprocess
Expand Down Expand Up @@ -78,7 +80,7 @@ def FlashBundleName(self):
elif self == Efr32App.PUMP:
return 'pump_app.flashbundle.txt'
elif self == Efr32App.UNIT_TEST:
return 'efr32_device_tests.flashbundle.txt'
return os.path.join('tests', 'efr32_device_tests.flashbundle.txt')
else:
raise Exception('Unknown app type: %r' % self)

Expand Down Expand Up @@ -259,27 +261,64 @@ def __init__(self,
def GnBuildArgs(self):
return self.extra_gn_options

def _bundle(self):
# Only unit-test needs to generate the flashbundle here. All other examples will generate a flashbundle via the silabs_executable template.
if self.app == Efr32App.UNIT_TEST:
flash_bundle_path = os.path.join(self.output_dir, self.app.FlashBundleName())
logging.info(f'Generating flashbundle {flash_bundle_path}')

patterns = [
os.path.join(self.output_dir, "tests", "*.flash.py"),
os.path.join(self.output_dir, "tests", "*.s37"),
os.path.join(self.output_dir, "tests", "silabs_firmware_utils.py"),
os.path.join(self.output_dir, "tests", "firmware_utils.py"),
]

# Generate the list of files by globbing each pattern.
files = []
for pattern in patterns:
files.extend([os.path.basename(x) for x in glob.glob(pattern)])

# Create the bundle file.
with open(flash_bundle_path, 'w') as bundle_file:
bundle_file.write("\n".join(files))

def build_outputs(self):
extensions = ["out", "hex"]
if self.options.enable_link_map_file:
extensions.append("out.map")
for ext in extensions:
name = f"{self.app.AppNamePrefix()}.{ext}"
yield BuilderOutput(os.path.join(self.output_dir, name), name)

if self.app == Efr32App.UNIT_TEST:
# Efr32 unit-test generates the "tests" subdir with a set of files for each individual unit test source.
for ext in extensions:
pattern = os.path.join(self.output_dir, "tests", f"*.{ext}")
for name in [os.path.basename(x) for x in glob.glob(pattern)]:
yield BuilderOutput(os.path.join(self.output_dir, "tests", name), name)
else:
# All other examples have just one set of files.
for ext in extensions:
name = f"{self.app.AppNamePrefix()}.{ext}"
yield BuilderOutput(os.path.join(self.output_dir, name), name)

if self.app == Efr32App.UNIT_TEST:
# Include test runner python wheels
for root, dirs, files in os.walk(os.path.join(self.output_dir, 'chip_nl_test_runner_wheels')):
for root, dirs, files in os.walk(os.path.join(self.output_dir, 'chip_pw_test_runner_wheels')):
for file in files:
yield BuilderOutput(
os.path.join(root, file),
os.path.join("chip_nl_test_runner_wheels", file))
os.path.join("chip_pw_test_runner_wheels", file))

# Figure out flash bundle files and build accordingly
def bundle_outputs(self):
# If flashbundle creation is enabled, the outputs will include the s37 and flash.py files, plus the two firmware utils scripts that support flash.py.
# For the unit-test example, there will be a s37 and flash.py file for each unit test source.
with open(os.path.join(self.output_dir, self.app.FlashBundleName())) as f:
for name in filter(None, [x.strip() for x in f.readlines()]):
if self.app == Efr32App.UNIT_TEST:
sourcepath = os.path.join(self.output_dir, "tests", name) # Unit tests are in the "tests" subdir.
else:
sourcepath = os.path.join(self.output_dir, name)
yield BuilderOutput(
os.path.join(self.output_dir, name),
sourcepath,
os.path.join("flashbundle", name))

def generate(self):
Expand Down
Loading

0 comments on commit 6144736

Please sign in to comment.