feat(tfut): add build support for unit testing
With this patch, the CI is now capable of configuring and building
unit tests by adding the proper component to the test group
variable.
Signed-off-by: Juan Pablo Conde <juanpablo.conde@arm.com>
Signed-off-by: Edward Potapov <edward.potapov@arm.com>
Change-Id: Iba487106a9dc5aa8358b358d385599a36f38b121
diff --git a/script/build_package.sh b/script/build_package.sh
index 7087cc6..d15071c 100755
--- a/script/build_package.sh
+++ b/script/build_package.sh
@@ -20,6 +20,7 @@
# Directory to where the source code e.g. for Trusted Firmware is checked out.
export tf_root="${tf_root:-$workspace/trusted_firmware}"
export tftf_root="${tftf_root:-$workspace/trusted_firmware_tf}"
+export tfut_root="${tfut_root:-$workspace/tfut}"
cc_root="${cc_root:-$ccpathspec}"
spm_root="${spm_root:-$workspace/spm}"
rmm_root="${rmm_root:-$workspace/tf-rmm}"
@@ -29,6 +30,7 @@
tftf_refspec="$TFTF_REFSPEC"
spm_refspec="$SPM_REFSPEC"
rmm_refspec="$RMM_REFSPEC"
+tfut_gerrit_refspec="$TFUT_GERRIT_REFSPEC"
test_config="${TEST_CONFIG:?}"
test_group="${TEST_GROUP:?}"
@@ -196,6 +198,20 @@
fi
}
+collect_tfut_artefacts() {
+ if [ ! -d "${from:?}" ]; then
+ return
+ fi
+
+ pushd "$tfut_root/build"
+ artefact_list=$(python3 "$ci_root/script/get_ut_test_list.py")
+ for artefact in $artefact_list; do
+ cp -t "${to:?}" "$from/$artefact"
+ done
+ echo "$artefact_list" | tr ' ' '\n' > "${to:?}/tfut_artefacts.txt"
+ popd
+}
+
# Map the UART ID used for expect with the UART descriptor and port
# used by the FPGA automation tools.
map_uart() {
@@ -746,6 +762,62 @@
)
}
+build_tfut() {
+ (
+ config_file="${tfut_build_config:-$tfut_config_file}"
+
+ # Build tfut target by default
+ build_targets="${tfut_build_targets:-all}"
+
+ source "$config_file"
+
+ mkdir -p "$tfut_root/build"
+ cd "$tfut_root/build"
+
+ # Always distclean when running on Jenkins. Skip distclean when running
+ # locally and explicitly requested.
+ if upon "$jenkins_run" || not_upon "$dont_clean"; then
+ #make clean &>>"$build_log" || fail_build
+ rm -Rf * || fail_build
+ fi
+
+ #Override build targets only if the run config did not set them.
+ if [ $build_targets == "all" ]; then
+ tests_line=$(cat "$config_file" | { grep "tests=" || :; })
+ if [ -z "$tests_line" ]; then
+ build_targets=$(echo "$tests_line" | awk -F= '{ print $NF }')
+ fi
+ fi
+
+ config=$(cat "$config_file" | grep -v "tests=")
+ cmake_config=$(echo "$config" | sed -e 's/^/\-D/')
+
+ # Check if cmake is installed
+ if ! command -v cmake &> /dev/null
+ then
+ echo "cmake could not be found"
+ exit 1
+ fi
+
+ # Log build command line
+ cat <<EOF | log_separator >/dev/null
+
+Build command line:
+ cmake $(echo "$cmake_config") -G"Unix Makefiles" --debug-output -DCMAKE_VERBOSE_MAKEFILE -DUNIT_TEST_PROJECT_PATH="$tf_root" ..
+ make $(echo "$config" | tr '\n' ' ') DEBUG=$DEBUG V=1 $build_targets
+
+EOF
+ cmake $(echo "$cmake_config") -G"Unix Makefiles" --debug-output \
+ -DCMAKE_VERBOSE_MAKEFILE=ON \
+ -DUNIT_TEST_PROJECT_PATH="$tf_root" \
+ .. &>> "$build_log" || fail_build
+ echo "Done with cmake" >> "$build_log"
+ make $(echo "$config") VERBOSE=1 \
+ $build_targets &>> "$build_log" || fail_build
+ )
+
+}
+
# Set metadata for the whole package so that it can be used by both Jenkins and
# shell
set_package_var() {
@@ -767,6 +839,11 @@
set_hook_var "spm_build_targets" "$targets"
}
+set_tfut_build_targets() {
+ echo "Set build target to '${targets:?}'"
+ set_hook_var "tfut_build_targets" "$targets"
+}
+
set_spm_out_dir() {
echo "Set SPMC binary build to '${out_dir:?}'"
set_hook_var "spm_secure_out_dir" "$out_dir"
@@ -1018,6 +1095,7 @@
tftf_config="$(echo "$build_configs" | awk -F, '{print $2}')"
spm_config="$(echo "$build_configs" | awk -F, '{print $3}')"
rmm_config="$(echo "$build_configs" | awk -F, '{print $4}')"
+tfut_config="$(echo "$build_configs" | awk -F, '{print $5}')"
test_config_file="$ci_root/group/$test_group/$test_config"
@@ -1025,6 +1103,7 @@
tftf_config_file="$ci_root/tftf_config/$tftf_config"
spm_config_file="$ci_root/spm_config/$spm_config"
rmm_config_file="$ci_root/rmm_config/$rmm_config"
+tfut_config_file="$ci_root/tfut_config/$tfut_config"
# File that keeps track of applied patches
tf_patch_record="$workspace/tf_patches"
@@ -1071,11 +1150,20 @@
echo
fi
+if ! config_valid "$tfut_config"; then
+ tfut_config=
+else
+ echo "TFUT config:"
+ echo
+ sort "$tfut_config_file" | sed '/^\s*$/d;s/^/\t/'
+ echo
+fi
+
if ! config_valid "$run_config"; then
run_config=
fi
-if [ "$tf_config" ] && assert_can_git_clone "tf_root"; then
+if { [ "$tf_config" ] || [ "$tfut_config" ]; } && assert_can_git_clone "tf_root"; then
# If the Trusted Firmware repository has already been checked out, use
# that location. Otherwise, clone one ourselves.
echo "Cloning Trusted Firmware..."
@@ -1145,6 +1233,15 @@
show_head "$rmm_root"
fi
+if [ "$tfut_config" ] && assert_can_git_clone "tfut_root"; then
+ # If the Trusted Firmware UT repository has already been checked out,
+ # use that location. Otherwise, clone one ourselves.
+ echo "Cloning Trusted Firmware UT..."
+ clone_url="${TFUT_CHECKOUT_LOC:-$tfut_src_repo_url}" where="$tfut_root" \
+ refspec="$TFUT_GERRIT_REFSPEC" clone_repo &>>"$build_log"
+ show_head "$tfut_root"
+fi
+
if [ "$run_config" ]; then
# Get candidates for run config
run_config_candidates="$("$ci_root/script/gen_run_config_candidates.py" \
@@ -1189,6 +1286,24 @@
source "$ci_root/script/install_python_deps.sh"
fi
+# Install c-picker dependency
+if config_valid "$tfut_config"; then
+ echo "started building"
+ python3 -m venv .venv
+ source .venv/bin/activate
+
+ if ! python3 -m pip show c-picker &> /dev/null; then
+ echo "Installing c-picker"
+ pip install git+https://git.trustedfirmware.org/TS/trusted-services.git@topics/c-picker || {
+ echo "c-picker was not installed!"
+ exit 1
+ }
+ echo "c-picker was installed"
+ else
+ echo "c-picker is already installed"
+ fi
+fi
+
# Print CMake version
cmake_ver=$(echo `cmake --version | sed -n '1p'`)
echo "Using $cmake_ver"
@@ -1430,10 +1545,35 @@
)
fi
+ # TFUT build
+ if config_valid "$tfut_config"; then
+ (
+ echo "##########"
+
+ archive="$build_archive"
+ tfut_build_root="$tfut_root/build"
+
+ echo "Building Trusted Firmware UT ($mode) ..." |& log_separator
+
+ # Call pre-build hook
+ call_hook pre_tfut_build
+
+ build_tfut
+
+ from="$tfut_build_root" to="$archive" collect_tfut_artefacts
+
+ echo "##########"
+ echo
+ )
+ fi
echo
echo
done
+if config_valid "$tfut_config"; then
+ deactivate
+fi
+
call_hook pre_package
call_hook post_package
diff --git a/script/get_ut_test_list.py b/script/get_ut_test_list.py
new file mode 100644
index 0000000..b45fe69
--- /dev/null
+++ b/script/get_ut_test_list.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2024 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import json
+import subprocess
+
+cmdres = subprocess.run(["ctest", "--show-only=json-v1"], stdout=subprocess.PIPE)
+
+tests_info = json.loads(cmdres.stdout.decode("utf-8"))
+tests = []
+for test in tests_info["tests"]:
+ if "command" in test:
+ tests.append(test["name"])
+
+tests_str = ' '.join(tests)
+print(tests_str)
+
diff --git a/tfut_config/default b/tfut_config/default
new file mode 100644
index 0000000..b057c32
--- /dev/null
+++ b/tfut_config/default
@@ -0,0 +1 @@
+COVERAGE=OFF
diff --git a/utils.sh b/utils.sh
index 98f9f84..8811939 100644
--- a/utils.sh
+++ b/utils.sh
@@ -602,6 +602,8 @@
tf_m_tests_src_repo_url="${tf_m_tests_src_repo_url:-https://$tforg_gerrit_url/TF-M/tf-m-tests}"
tf_m_extras_src_repo_url="${tf_m_extras_src_repo_url:-$TF_M_EXTRAS_REPO_URL}"
tf_m_extras_src_repo_url="${tf_m_extras_src_repo_url:-https://$tforg_gerrit_url/TF-M/tf-m-extras}"
+tfut_src_repo_url="${tfut_src_repo_url:-$TFUT_SRC_REPO_URL}"
+tfut_src_repo_url="${tfut_src_repo_url:-https://$tforg_gerrit_url/TF-A/tf-a-unit-tests}"
tf_downloads="${tf_downloads:-file:///downloads/}"
tfa_downloads="${tfa_downloads:-file:///downloads/tf-a}"