diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index c4f48058b70416..23e974cb2f4269 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -945,8 +945,6 @@ NitricOxideConcentrationMeasurement NitrogenDioxideConcentrationMeasurement nl nltest -NLUnitTest -NLUnitTests nmcli nmtui noc diff --git a/build/chip/chip_test.gni b/build/chip/chip_test.gni deleted file mode 100644 index b5b32f24d0b0b7..00000000000000 --- a/build/chip/chip_test.gni +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (c) 2020 Project CHIP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import("//build_overrides/build.gni") -import("//build_overrides/chip.gni") -import("//build_overrides/pigweed.gni") - -import("$dir_pw_build/python_action.gni") - -import("${chip_root}/build/chip/tests.gni") -import("${chip_root}/src/platform/device.gni") -import("${dir_pw_unit_test}/test.gni") - -assert(chip_build_tests) - -if (chip_link_tests) { - template("chip_test") { - _test_name = target_name - - _test_output_dir = "${root_out_dir}/tests" - if (defined(invoker.output_dir)) { - _test_output_dir = invoker.output_dir - } - - executable(_test_name) { - forward_variables_from(invoker, "*", [ "output_dir" ]) - output_dir = _test_output_dir - } - - group(_test_name + ".lib") { - } - - if (chip_pw_run_tests) { - pw_python_action(_test_name + ".run") { - deps = [ ":${_test_name}" ] - inputs = [ pw_unit_test_AUTOMATIC_RUNNER ] - module = "pw_unit_test.test_runner" - python_deps = [ - "$dir_pw_cli/py", - "$dir_pw_unit_test/py", - ] - args = [ - "--runner", - rebase_path(pw_unit_test_AUTOMATIC_RUNNER, root_build_dir), - "--test", - rebase_path("$_test_output_dir/$_test_name", root_build_dir), - ] - stamp = true - } - } - } -} else { - template("chip_test") { - group(target_name) { - } - group(target_name + ".lib") { - } - not_needed(invoker, "*") - } -} diff --git a/build/chip/chip_test_suite.gni b/build/chip/chip_test_suite.gni index 60f29346a48fa6..43eb4ec39fb768 100644 --- a/build/chip/chip_test_suite.gni +++ b/build/chip/chip_test_suite.gni @@ -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 @@ -41,50 +48,23 @@ 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 - } - 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, + "*", + [ + "tests", + "test_sources", + ]) output_dir = "${root_out_dir}/lib" @@ -102,79 +82,62 @@ template("chip_test_suite") { public_deps += [ "${chip_root}/src/platform/logging:default" ] } } - if (chip_link_tests) { - tests = [] - if (defined(invoker.test_sources)) { - foreach(_test, invoker.test_sources) { - _test_name = string_replace(_test, ".cpp", "") + tests = [] - _test_output_dir = "${root_out_dir}/tests" - if (defined(invoker.output_dir)) { - _test_output_dir = invoker.output_dir - } + if (defined(invoker.test_sources)) { + foreach(_test, invoker.test_sources) { + _test_name = string_replace(_test, ".cpp", "") - pw_test(_test_name) { - forward_variables_from(invoker, - [ - "deps", - "public_deps", - "cflags", - "configs", - ]) - public_deps += [ ":${_suite_name}.lib" ] - sources = [ _test ] - output_dir = _test_output_dir - } - tests += [ _test_name ] + _test_output_dir = "${root_out_dir}/tests" + if (defined(invoker.output_dir)) { + _test_output_dir = invoker.output_dir } - } - 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 + 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" ] + + # 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 - 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 ] + # Add the individual test source file (e.g. "TestSomething.cpp"). + sources = [ _test ] + + output_dir = _test_output_dir } + tests += [ _test_name ] + } + } + + group(_suite_name) { + deps = [] + + # Add each individual unit test. + foreach(_test, tests) { + deps += [ ":${_test}" ] } + } - group(_suite_name) { + if (chip_pw_run_tests) { + group("${_suite_name}_run") { deps = [] foreach(_test, tests) { - deps += [ ":${_test}" ] - } - } - - if (chip_pw_run_tests) { - group("${_suite_name}_run") { - deps = [] - foreach(_test, tests) { - deps += [ ":${_test}.run" ] - } + deps += [ ":${_test}.run" ] } } - } else { - group(_suite_name) { - deps = [ ":${_suite_name}.lib" ] - } } } diff --git a/build/toolchain/flashable_executable.gni b/build/toolchain/flashable_executable.gni index 6233d58382b43d..b7f96b95f46f08 100644 --- a/build/toolchain/flashable_executable.gni +++ b/build/toolchain/flashable_executable.gni @@ -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" @@ -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)) { @@ -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" ] } @@ -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 { @@ -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" ] } diff --git a/scripts/build/builders/efr32.py b/scripts/build/builders/efr32.py index 3972dc7bb48eff..7b518ff1227b89 100644 --- a/scripts/build/builders/efr32.py +++ b/scripts/build/builders/efr32.py @@ -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 @@ -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) @@ -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 += list(map(lambda x: os.path.basename(x), 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 map(lambda x: os.path.basename(x), 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): diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index 4ea5a9aae0f836..35721dd381e8e1 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -216,7 +216,7 @@ def OutputNames(self): elif self == HostApp.PYTHON_BINDINGS: yield 'controller/python' # Directory containing WHL files elif self == HostApp.EFR32_TEST_RUNNER: - yield 'chip_nl_test_runner_wheels' + yield 'chip_pw_test_runner_wheels' elif self == HostApp.TV_CASTING: yield 'chip-tv-casting-app' yield 'chip-tv-casting-app.map' diff --git a/scripts/flashing/silabs_firmware_utils.py b/scripts/flashing/silabs_firmware_utils.py index 5e0a689f5a62f4..52e952db2ae5e2 100755 --- a/scripts/flashing/silabs_firmware_utils.py +++ b/scripts/flashing/silabs_firmware_utils.py @@ -49,6 +49,8 @@ Do not reset device after flashing """ +import os +import subprocess import sys import firmware_utils @@ -169,6 +171,45 @@ def actions(self): return self + def _platform_wrapper_args(self, args): + """Called from make_wrapper() to optionally manipulate arguments.""" + # Generate the flashbundle.txt file and copy the firmware utils. + if args.flashbundle_file is not None: + # Generate the flashbundle contents. + # Copy the platform-specific and general firmware utils to the same directory as the wrapper. + flashbundle_contents = os.path.basename(args.output) + if args.application is not None: + flashbundle_contents += "\n" + os.path.basename(args.application) + output_dir = os.path.dirname(args.output) or "." + if args.platform_firmware_utils is not None: + flashbundle_contents += "\n" + os.path.basename(args.platform_firmware_utils) + subprocess.run(["cp", args.platform_firmware_utils, output_dir]) + if args.firmware_utils is not None: + flashbundle_contents += "\n" + os.path.basename(args.firmware_utils) + subprocess.run(["cp", args.firmware_utils, output_dir]) + + # Create the flashbundle file. + try: + with open(args.flashbundle_file, 'w') as flashbundle_file: + flashbundle_file.write(flashbundle_contents.strip()) + except OSError as exception: + print(exception, sys.stderr) + + def make_wrapper(self, argv): + self.parser.add_argument( + '--flashbundle-file', + metavar='FILENAME', + help='path and name of the flashbundle text file to create') + self.parser.add_argument( + '--platform-firmware-utils', + metavar='FILENAME', + help='path and file of the platform-specific firmware utils script') + self.parser.add_argument( + '--firmware-utils', + metavar='FILENAME', + help='path and file of the general firmware utils script') + super().make_wrapper(argv) + if __name__ == '__main__': sys.exit(Flasher().flash_command(sys.argv)) diff --git a/src/test_driver/efr32/BUILD.gn b/src/test_driver/efr32/BUILD.gn index 947ed482f4622e..68543d8a3c73c5 100644 --- a/src/test_driver/efr32/BUILD.gn +++ b/src/test_driver/efr32/BUILD.gn @@ -19,7 +19,6 @@ import("//build_overrides/pigweed.gni") import("${build_root}/config/defaults.gni") import("${efr32_sdk_build_root}/efr32_sdk.gni") -import("${efr32_sdk_build_root}/silabs_executable.gni") import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") import("${chip_root}/src/platform/device.gni") @@ -62,9 +61,8 @@ efr32_sdk("sdk") { ] } -silabs_executable("efr32_device_tests") { - output_name = "matter-silabs-device_tests.out" - +# This is the test runner. `pw_test` will dep this for each `silabs_executable` target. +source_set("efr32_test_main") { defines = [ "PW_RPC_ENABLED" ] sources = [ "${chip_root}/examples/common/pigweed/RpcService.cpp", @@ -83,7 +81,6 @@ silabs_executable("efr32_device_tests") { "$dir_pw_unit_test:rpc_service", "${chip_root}/config/efr32/lib/pw_rpc:pw_rpc", "${chip_root}/examples/common/pigweed:system_rpc_server", - "${chip_root}/src:tests", "${chip_root}/src/lib", "${chip_root}/src/lib/support:pw_tests_wrapper", "${chip_root}/src/platform/silabs/provision:provision-headers", @@ -106,27 +103,18 @@ silabs_executable("efr32_device_tests") { ] include_dirs = [ "${chip_root}/examples/common/pigweed/efr32" ] - - ldscript = "${examples_common_plat_dir}/ldscripts/${silabs_family}.ld" - - inputs = [ ldscript ] - - ldflags = [ - "-T" + rebase_path(ldscript, root_build_dir), - "-Wl,--no-warn-rwx-segment", - ] - - output_dir = root_out_dir } +# This target is referred to by BuildRoot in scripts/build/builders/efr32.py, as well as the example in README.md. +# It builds the root target "src:tests", which builds the chip_test_suite target in each test directory, which builds a pw_test target for each test source file, which builds a silabs_executable, which includes the "efr32_test_main" target defined above. group("efr32") { - deps = [ ":efr32_device_tests" ] + deps = [ "${chip_root}/src:tests" ] } group("runner") { deps = [ - "${efr32_project_dir}/py:nl_test_runner.install", - "${efr32_project_dir}/py:nl_test_runner_wheel", + "${efr32_project_dir}/py:pw_test_runner.install", + "${efr32_project_dir}/py:pw_test_runner_wheel", ] } diff --git a/src/test_driver/efr32/README.md b/src/test_driver/efr32/README.md index c36812e484fdee..dd1cdf6f93c57e 100644 --- a/src/test_driver/efr32/README.md +++ b/src/test_driver/efr32/README.md @@ -1,6 +1,6 @@ #CHIP EFR32 Test Driver -This builds and runs the NLUnitTest on the efr32 device +This builds and runs the unit tests on the efr32 device