blob: b27ed7437e1a9a65d5902e232cfb6c2785e9b0d5 [file] [log] [blame]
#################################
Adding TF-M Regression Test Suite
#################################
.. contents:: Table of Contents
*************************************
Introduction of TF-M regression tests
*************************************
TF-M regression tests test whether changes to TF-M code work as expected.
A new regression test can consist of following 3 components:
1. ``test suite``: A series of tests of a certain function.
2. ``test case``: A specific test instance in test suites.
3. ``test service or partition``: Optional secure services or partitions to
support related test suites.
Source structure
================
+---------------------------------------+---------------------------------------------------------------+
| Folder name | Description |
+=======================================+===============================================================+
| test/bl1 | TF-M bl1 test suites source code. |
+---------------------------------------+---------------------------------------------------------------+
| test/bl2 | TF-M bL2 test suites source code. |
+---------------------------------------+---------------------------------------------------------------+
| test/config | The CMAKE test configurations files. |
+---------------------------------------+---------------------------------------------------------------+
| test/framework | Source code for test framework code, managing test suites. |
+---------------------------------------+---------------------------------------------------------------+
| test/secure_fw/suites | Test suites divided into subdirectories. |
+---------------------------------------+---------------------------------------------------------------+
| test/secure_fw/suites/<suite>/service | Test service divided into corresponding suite subdirectories. |
+---------------------------------------+---------------------------------------------------------------+
| test/secure_fw/common_test_services | Common test services. |
+---------------------------------------+---------------------------------------------------------------+
***********************
Adding a new test suite
***********************
This section introduces how to add a new test suite and control its compilation
with a test configuration in ``tf-m-tests`` repository.
Source code
===========
The test suite example subdirectory named ``<test_name>`` is located under the
path ``tf-m-tests/test/secure_fw/suites``. If the new test suite includes both
non-secure and secure parts, the source code shall be divided shared code and
specific code. An example test suite folder can be organized as the figure
below.
.. code-block:: bash
.
├── CMakeLists.txt
├── <test_name>_tests_common.c
├── non_secure
│ ├── <test_name>_ns_interface_testsuite.c
│ └── <test_name>_ns_tests.h
└── secure
├── <test_name>_s_interface_testsuite.c
└── <test_name>_s_tests.h
Creating test configurations
============================
A test configuration controls whether one or multiple test suites are enabled.
The doc `TF-M Build Instructions <https://tf-m-user-guide.trustedfirmware.org/technical_references/instructions/tfm_build_instruction.html>`_.
shows some test configurations which are already supported in current TF-M.
An example usage of test configuration shows below.
.. code-block:: bash
cmake -S . -B cmake_build -DTFM_PLATFORM=arm/mps2/an521 \
-DTFM_TOOLCHAIN_FILE=toolchain_GNUARM.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DTEST_NS_ATTESTATION=ON
With this command, only non-secure initial attestation test suite will be built.
Developers shall assign corresponding test configurations to control the test
suites.
Naming test configurations
--------------------------
The test configurations of example test suites are ``TEST_NS_<TEST_NAME>``
in non-secure and ``TEST_S_<TEST_NAME>`` in secure.
.. Note::
The test configurations must be named with the prefixes ``TEST_S_`` and
``TEST_NS_``, for secure regression tests and non-secure regression tests
respectively. Otherwise, tf-m-tests build system may not recognize it.
Setting test configurations
---------------------------
When the test configurations have dependences, the default value need to be set.
The setting is performed in following four steps.
#. Command line input: The configuration can be enabled or disabled by the
command ``-DTEST_NS_<TEST_NAME>=ON/OFF -DTEST_S_<TEST_NAME>=ON/OFF``, and
the value cannot be changed throughout the whole compilation of TF-M tests.
#. ``tf-m-tests/config/set_config.cmake``: The test configurations shall be
OFF if its dependences are not supported. The dependences are probably
from:
#. TF-M partitions configurations like ``TFM_PARTITION_CRYPTO``,
``TFM_PARTITION_INITIAL_ATTESTATION``, etc.
#. TF-M build mode configuration like ``CONFIG_TFM_SPM_BACKEND``.
#. TF-M other configurations like ``TFM_PARTITION_FIRMWARE_UPDATE``, etc.
#. ``tf-m-tests/config/default_ns_test_config.cmake`` or
``tf-m-tests/config/default_s_test_config.cmake``: It is required to give
the default value of the new test configuration in these two files when
``TEST_NS`` or ``TEST_S`` is ON. The recommended value is ON unless the
single test's code or data size is very large.
#. ``tf-m-tests/config/default_test_config.cmake``: It is required to give the
default value of the new test configuration in the file when both
``TEST_NS`` and ``TEST_S`` are OFF. The default value must be OFF.
.. Note::
The test configurations must be set as CACHE value in CMAKE files. The CACHE
set cannot replace the value from command line, see
`Set Cache Entry <https://cmake.org/cmake/help/latest/command/set.html#set-cache-entry>`_.
Checking test configurations
----------------------------
The new test configurations must be checked by function ``tfm_invalid_config()``
if they have any dependence. The value comes from command line may be wrong when
the dependences are conflicting. In addition to the dependences quoted in
``tf-m-tests/config/set_config.cmake``, some other test configurations may be
necessary.
Applying test configurations
============================
The mission of test configurations is to control the build. They are applied
in ``test/secure_fw/suites/<test_name>/CMakeLists.txt`` like the example below.
.. code-block:: cmake
cmake_policy(SET CMP0079 NEW)
if (NOT TEST_NS_<TEST_NAME> AND NOT TEST_S_<TEST_NAME>)
return()
endif()
####################### Non Secure #########################################
if (TEST_NS_<TEST_NAME>)
add_library(tfm_test_suite_<test_name>_ns STATIC EXCLUDE_FROM_ALL)
# target_sources()
# target_include_directories()
target_compile_definitions(tfm_test_suite_<test_name>_ns
INTERFACE
TEST_NS_<TEST_NAME>
)
# target_link_libraries()
endif()
####################### Secure #############################################
if (TEST_S_<TEST_NAME>)
add_library(tfm_test_suite_<test_name>_s STATIC EXCLUDE_FROM_ALL)
# target_sources()
# target_include_directories()
target_compile_definitions(tfm_test_suite_<test_name>_s
INTERFACE
TEST_S_<TEST_NAME>
)
# target_link_libraries()
endif()
The function ``target_compile_definitions`` will export the macros
``TEST_NS_<TEST_NAME>`` or ``TEST_S_<TEST_NAME>`` into source code. and in the
file ``tf-m-tests/framework/non_secure_suites.c`` or
``tests/framework/secure_suites.c``, the definitions of these macros will be
checked, and then the head file will be included and test cases will be
registered if the macro is defined.
.. code-block:: c
#ifdef TEST_NS_<TEST_NAME>
#include "<test_name>_ns_tests.h"
#endif
static struct test_suite_t test_suites[] = {
/* Non-secure example test cases */
// ......
#ifdef TEST_NS_<TEST_NAME>
{&register_testsuite_ns_<test_name>_interface, 0, 0, 0},
#endif
};
.. code-block:: c
#ifdef TEST_S_<TEST_NAME>
#include "<test_name>_s_tests.h"
#endif
static struct test_suite_t test_suites[] = {
/* Secure example test cases */
// ......
#ifdef TEST_S_<TEST_NAME>
{&register_testsuite_s_<test_name>_interface, 0, 0, 0},
#endif
};
.. Note::
On most platforms non-secure tests and secure tests run on the same CPU
core, but dual-core platform is an exception. So secure test library and
secure services shall be linked together in the file
``tf-m-tests/test/secure_fw/secure_tests.cmake``. Thus they can be built on
secure CPU core and non-secure tests library and RTOS are built on
non-secure CPU core.
.. code-block:: cmake
# ...
if (TEST_S_<TEST_NAME>)
add_library(tfm_test_suite_<test_name>_s STATIC EXCLUDE_FROM_ALL)
endif()
************************************
Adding a new test case in test suite
************************************
The test cases usually express as a function in source code. They will be added
into an array with structure type called ``test_t`` defined in
``tf-m-tests/test/framework/test_framework.h``.
.. code-block:: c
struct test_t {
TEST_FUN * const test; /*!< Test function to call */
const char *name; /*!< Test name */
const char *desc; /*!< Test description */
};
For example, a new test case called ``TFM_NS_<TEST_NAME>_TEST_1001`` is created
and the function ``tfm_<test_name>_test_1001`` needs to be defined in file
``<test_name>_ns_interface_testsuite.c``. Then the function shall be appended
into the array which will be quoted in function
``register_testsuite_ns_<test_name>_interface``. See the reference code below.
.. code-block:: c
/* List of test cases */
static void tfm_<test_name>_test_1001(struct test_result_t *ret);
/* Append test cases */
static struct test_t <test_name>_tests[] = {
{&tfm_<test_name>_test_1001, "TFM_NS_<TEST_NAME>_TEST_1001",
"Example test case"},
};
/* Register test case into test suites */
void register_testsuite_ns_<test_name>_interface(struct test_suite_t *p_test_suite)
{
uint32_t list_size;
list_size = (sizeof(<test_name>_tests) / sizeof(<test_name>_tests[0]));
set_testsuite("<TEST_NAME> non-secure interface test (TFM_NS_<TEST_NAME>_TEST_1XXX)",
<test_name>_tests, list_size, p_test_suite);
}
static void tfm_<test_name>_test_1001(struct test_result_t *ret)
{
/* test case code */
}
********************
Adding test services
********************
Some test group may need specific test services. These test services may support
one or more groups thus developers shall determine the proper test scope. Refer
to
`Adding partitions for regression tests <https://git.trustedfirmware.org/TF-M/tf-m-tests.git/tree/docs/tfm_test_services_addition.rst>`_
to get more information.
**********************************
Out-of-tree regression test suites
**********************************
TF-M supports out-of-tree regression test suites build, whose source code
folder is outside tf-m-tests repo. There are two configurations for developers
to include the source code.
- ``EXTRA_NS_TEST_SUITE_PATH``
An absolute directory of the out-of-tree non-secure test suite
source code folder. TF-M build system searches ``CMakeLists.txt`` of
non-secure test suite in the source code folder.
- ``EXTRA_S_TEST_SUITE_PATH``
An absolute directory of the out-of-tree secure test suite
source code folder.
Example usage
=============
Take non-secure test as an example in
`tf-m-extras <https://git.trustedfirmware.org/TF-M/tf-m-extras.git/>`_.
A single out-of-tree test suite folder can be organized as the figure below:
.. code-block:: bash
extra_ns
├── CMakeLists.txt
├── ns_test.c
└── ns_test_config.cmake
In the example above, ``EXTRA_NS_TEST_SUITE_PATH`` in the build command can be
specified as listed below.
.. code-block:: bash
-DEXTRA_NS_TEST_SUITE_PATH=<Absolute-path-extra-test-folder>
Coding instructions
===================
This is a demo of source code so the structure has been simplified. Files like
``.c`` and ``.h`` can be expanded to ``src`` and ``include`` folders
respectively. The ``CMakeLists.txt`` is required in the root path and
``ns_test_config.cmake`` is optional.
Header Files
------------
The header file ``extra_ns_tests.h`` must be included by out-of-tree source
code. This file contains the declaration of
``void register_testsuite_extra_ns_interface(struct test_suite_t *p_test_suite)``.
Source code
-----------
To connect the out-of-tree source code and tf-m-tests framework, the test case
function/functions must be defined first. An example format is:
.. code-block:: c
void ns_test(struct test_result_t *ret)
{
/* Add platform specific non-secure test suites code here. */
ret->val = TEST_PASSED;
}
This function follows the standard TF-M test case function prototype.
.. note::
Extra tests can have one or more test cases. This is simplified example so
only one test case is added.
After ``ns_test()`` is defined, a structure variable need to be created like:
.. code-block:: c
static struct test_t plat_ns_t[] = {
{&ns_test, "TFM_EXTRA_TEST_1001",
"Extra Non-Secure test"},
};
It will be used by function ``register_testsuite_extra_ns_interface()`` to
register the test by calling the ``set_testsuite()`` function:
.. code-block:: c
void register_testsuite_extra_ns_interface(struct test_suite_t *p_test_suite)
{
uint32_t list_size;
list_size = (sizeof(plat_ns_t) /
sizeof(plat_ns_t[0]));
set_testsuite("Extra Non-Secure interface tests"
"(TFM_NS_EXTRA_TEST_1XXX)",
plat_ns_t, list_size, p_test_suite);
}
The platform initialization code can be added in this function because it runs
before ``ns_test()``.
.. Note::
Function ``register_testsuite_extra_ns_interface()`` is declared in
tf-m-tests repository without definition. It is supplied to out-of-tree
source code and need to be defined with no change of its format, like
returns error code and parameter name.
CMakeLists.txt
--------------
After extra test suite file were created they must be linked to
``tfm_test_suite_extra_ns`` CMAKE target:
.. code-block:: cmake
target_sources(tfm_test_suite_extra_ns
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/ns_test.c
)
ns_test_config.cmake
--------------------
The CMAKE configuration file is optional. If out-of-tree source already exists
another configuration file, a new one can be ignored.
--------------
*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
*Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company)
or an affiliate of Cypress Semiconductor Corporation. All rights reserved.*