[Tizen] Add code coverage for tests on QEMU (#36245)
* Add -coverage target
* Allow to specify runner
* Fix the .gcda files output location
* Allow runner in interactive mode
* Remove wrap
* Fix expected test output
* Collect common lcov args
* Update scripts/build/builders/tizen.py
Co-authored-by: Arkadiusz Bokowy <arkadiusz.bokowy@gmail.com>
---------
Co-authored-by: Andrei Litvin <andy314@gmail.com>
Co-authored-by: Arkadiusz Bokowy <arkadiusz.bokowy@gmail.com>
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index d86c36f..52696de 100755
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -692,6 +692,8 @@
target.AppendModifier("no-wifi", enable_wifi=False)
target.AppendModifier("asan", use_asan=True)
target.AppendModifier("ubsan", use_ubsan=True)
+ target.AppendModifier('coverage', use_coverage=True).OnlyIfRe(
+ '-tests')
target.AppendModifier('with-ui', with_ui=True)
return target
diff --git a/scripts/build/builders/tizen.py b/scripts/build/builders/tizen.py
index 8c79688..e886558 100644
--- a/scripts/build/builders/tizen.py
+++ b/scripts/build/builders/tizen.py
@@ -89,6 +89,7 @@
use_asan: bool = False,
use_tsan: bool = False,
use_ubsan: bool = False,
+ use_coverage: bool = False,
with_ui: bool = False,
):
super(TizenBuilder, self).__init__(
@@ -130,9 +131,59 @@
raise Exception("TSAN sanitizer not supported by Tizen toolchain")
if use_ubsan:
self.extra_gn_options.append('is_ubsan=true')
+ self.use_coverage = use_coverage
+ if use_coverage:
+ self.extra_gn_options.append('use_coverage=true')
if with_ui:
self.extra_gn_options.append('chip_examples_enable_ui=true')
+ def generate(self):
+ super(TizenBuilder, self).generate()
+ if self.app == TizenApp.TESTS and self.use_coverage:
+ self.coverage_dir = os.path.join(self.output_dir, 'coverage')
+ self._Execute(['mkdir', '-p', self.coverage_dir], title="Create coverage output location")
+
+ def lcov_args(self):
+ gcov = os.path.join(os.environ['TIZEN_SDK_TOOLCHAIN'], 'bin/arm-linux-gnueabi-gcov')
+ return [
+ 'lcov', '--gcov-tool', gcov, '--ignore-errors', 'unused,mismatch', '--capture', '--directory', os.path.join(
+ self.output_dir, 'obj'),
+ '--exclude', '**/src/controller/*',
+ '--exclude', '**/connectedhomeip/zzz_generated/*',
+ '--exclude', '**/connectedhomeip/third_party/*',
+ '--exclude', '/opt/*',
+ ]
+
+ def PreBuildCommand(self):
+ if self.app == TizenApp.TESTS and self.use_coverage:
+ cmd = ['ninja', '-C', self.output_dir]
+
+ if self.ninja_jobs is not None:
+ cmd.append('-j' + str(self.ninja_jobs))
+
+ cmd.append('Tizen')
+
+ self._Execute(cmd, title="Build-only")
+
+ self._Execute(self.lcov_args() + [
+ '--initial',
+ '--output-file', os.path.join(self.coverage_dir, 'lcov_base.info')
+ ], title="Initial coverage baseline")
+
+ def PostBuildCommand(self):
+ if self.app == TizenApp.TESTS and self.use_coverage:
+
+ self._Execute(self.lcov_args() + ['--output-file', os.path.join(self.coverage_dir,
+ 'lcov_test.info')], title="Update coverage")
+
+ gcov = os.path.join(os.environ['TIZEN_SDK_TOOLCHAIN'], 'bin/arm-linux-gnueabi-gcov')
+ self._Execute(['lcov', '--gcov-tool', gcov, '--add-tracefile', os.path.join(self.coverage_dir, 'lcov_base.info'),
+ '--add-tracefile', os.path.join(self.coverage_dir, 'lcov_test.info'),
+ '--output-file', os.path.join(self.coverage_dir, 'lcov_final.info')
+ ], title="Final coverage info")
+ self._Execute(['genhtml', os.path.join(self.coverage_dir, 'lcov_final.info'), '--output-directory',
+ os.path.join(self.coverage_dir, 'html')], title="HTML coverage")
+
def GnBuildArgs(self):
# Make sure that required ENV variables are defined
for env in ('TIZEN_SDK_ROOT', 'TIZEN_SDK_SYSROOT'):
diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt
index 58a1fc1..5e17f58 100644
--- a/scripts/build/testdata/all_targets_linux_x64.txt
+++ b/scripts/build/testdata/all_targets_linux_x64.txt
@@ -21,6 +21,6 @@
nuttx-x64-light
qpg-qpg6105-{lock,light,shell,persistent-storage,light-switch,thermostat}[-updateimage][-data-model-disabled][-data-model-enabled]
stm32-stm32wb5mm-dk-light
-tizen-arm-{all-clusters,chip-tool,light,tests}[-no-ble][-no-thread][-no-wifi][-asan][-ubsan][-with-ui]
+tizen-arm-{all-clusters,chip-tool,light,tests}[-no-ble][-no-thread][-no-wifi][-asan][-ubsan][-coverage][-with-ui]
telink-{tlsr9118bdk40d,tlsr9518adk80d,tlsr9528a,tlsr9528a_retention,tlsr9258a,tlsr9258a_retention}-{air-quality-sensor,all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-ota][-dfu][-shell][-rpc][-factory-data][-4mb][-mars][-usb][-data-model-disabled][-data-model-enabled]
openiotsdk-{shell,lock}[-mbedtls][-psa]
diff --git a/src/test_driver/tizen/chip_tests/BUILD.gn b/src/test_driver/tizen/chip_tests/BUILD.gn
index 47be879..ba72060 100644
--- a/src/test_driver/tizen/chip_tests/BUILD.gn
+++ b/src/test_driver/tizen/chip_tests/BUILD.gn
@@ -24,12 +24,15 @@
virtio_net = true
# Share tests directory.
- share = "${root_out_dir}/tests"
+ share = "${root_out_dir}"
+
+ # Runner script file name.
+ runner = "runner-${target_name}.sh"
# Copy runner script to shared directory.
copy("${target_name}:runner") {
sources = [ "runner.sh" ]
- outputs = [ share + "/runner.sh" ]
+ outputs = [ share + "/" + runner ]
}
# Build CHIP unit tests.
diff --git a/src/test_driver/tizen/chip_tests/runner.sh b/src/test_driver/tizen/chip_tests/runner.sh
index 1cc4016..cad90e2 100755
--- a/src/test_driver/tizen/chip_tests/runner.sh
+++ b/src/test_driver/tizen/chip_tests/runner.sh
@@ -21,6 +21,10 @@
# Print CHIP logs on stdout
dlogutil CHIP &
+# Set the correct path for .gcda files
+export GCOV_PREFIX=/mnt/chip
+export GCOV_PREFIX_STRIP=5
+
FAILED=()
STATUS=0
@@ -43,7 +47,7 @@
echo -e "DONE: \e[31mFAIL\e[0m"
fi
-done < <(find /mnt/chip -type f -executable ! -name runner.sh)
+done < <(find /mnt/chip/tests -type f -executable ! -name runner.sh)
if [ ! "$STATUS" -eq 0 ]; then
echo
diff --git a/src/test_driver/tizen/integration_tests/lighting-app/BUILD.gn b/src/test_driver/tizen/integration_tests/lighting-app/BUILD.gn
index 67de6ab..49eabcc 100644
--- a/src/test_driver/tizen/integration_tests/lighting-app/BUILD.gn
+++ b/src/test_driver/tizen/integration_tests/lighting-app/BUILD.gn
@@ -26,10 +26,13 @@
# Share output directory.
share = "${root_out_dir}"
+ # Runner script file name.
+ runner = "runner-${target_name}.sh"
+
# Copy runner script to shared directory.
copy("${target_name}:runner") {
sources = [ "runner.sh" ]
- outputs = [ share + "/runner.sh" ]
+ outputs = [ share + "/" + runner ]
}
# Build applications used in the test.
diff --git a/src/test_driver/tizen/integration_tests/lighting-app/runner.sh b/src/test_driver/tizen/integration_tests/lighting-app/runner.sh
index 52e7562..54ae160 100755
--- a/src/test_driver/tizen/integration_tests/lighting-app/runner.sh
+++ b/src/test_driver/tizen/integration_tests/lighting-app/runner.sh
@@ -21,6 +21,10 @@
# Print CHIP logs on stdout
dlogutil CHIP &
+# Set the correct path for .gcda files
+export GCOV_PREFIX=/mnt/chip
+export GCOV_PREFIX_STRIP=5
+
# Install lighting Matter app
pkgcmd -i -t tpk -p /mnt/chip/org.tizen.matter.*/out/org.tizen.matter.*.tpk
# Launch lighting Matter app
diff --git a/third_party/tizen/tizen_qemu.py b/third_party/tizen/tizen_qemu.py
index 93bdfd3..7b7eb41 100755
--- a/third_party/tizen/tizen_qemu.py
+++ b/third_party/tizen/tizen_qemu.py
@@ -66,9 +66,10 @@
"default: $TIZEN_SDK_ROOT/iot-sysdata.img"))
parser.add_argument(
'--share', type=str,
- help=("host directory to share with the guest; if file named 'runner.sh' "
- "is present at the root of that directory, it will be executed "
- "automatically after boot"))
+ help=("host directory to share with the guest"))
+parser.add_argument(
+ '--runner', type=str,
+ help=("path to the runner script which will run automatically after boot. path should be relative to shared directory"))
parser.add_argument(
'--output', metavar='FILE', default="/dev/null",
help="store the QEMU output in a FILE")
@@ -136,6 +137,9 @@
# Run root shell instead of the runner script.
kernel_args += " rootshell"
+if args.runner:
+ kernel_args += " runner=/mnt/chip/%s" % args.runner
+
qemu_args += [
'-kernel', args.kernel,
'-append', kernel_args,
@@ -153,7 +157,7 @@
for line in iter(proc.stdout.readline, b''):
# Forward the output to the stdout and the log file.
- sys.stdout.write(line.decode(sys.stdout.encoding))
+ sys.stdout.write(line.decode(sys.stdout.encoding, errors='ignore'))
sys.stdout.flush()
output.write(line)
diff --git a/third_party/tizen/tizen_sdk.gni b/third_party/tizen/tizen_sdk.gni
index 72fb207..fbf8275 100644
--- a/third_party/tizen/tizen_sdk.gni
+++ b/third_party/tizen/tizen_sdk.gni
@@ -175,6 +175,7 @@
testonly = true
assert(defined(invoker.share), "It is required to specify path to share.")
+ assert(defined(invoker.runner), "It is required to specify runner script.")
# Store QEMU output in a dedicated log file.
output_log_file = "${root_out_dir}/tizen-qemu-" + target_name + ".log"
@@ -186,6 +187,7 @@
args = [
"--share=" + invoker.share,
+ "--runner=" + invoker.runner,
"--output=" + rebase_path(output_log_file),
]
if (defined(invoker.virtio_net) && invoker.virtio_net) {