-
Notifications
You must be signed in to change notification settings - Fork 0
UT‐Core: How to Build and Run a HAL Testing Suite
This guide shows you how to build and run a testing suite, using the ut-core
framework.
Think of ut-core
as a set of tools for generating a framework for building your tests. This guide focuses on how to use those tools, but the underlying principles how to structure your tests, is defined by your own requirements.
Essentially, we're using ut-core
to demonstrate a general approach to testing. You can adapt this approach to your own needs and preferences, even if you're using a different testing framework. In this case we've created template scripts that use ut-core
in a HAL interface testing scenario.
First, navigate to the directory containing the header file you want to test.
For example:
If you want to run the testing suite against the rdk-halif-hdmi_cec
repository, you would first clone the repository and then navigate into the newly created directory:
git clone [email protected]:rdkcentral/rdk-halif-hdmi_cec.git
cd rdk-halif-hdmi_cec
From this directory, execute the following command in your terminal:
build_ut.sh TARGET=arm
This script will create a new directory named ut
where your testing suite will be created.
Note: Running build_ut.sh
without specifying a target will build a Linux version of the testing suite, which can be useful for debugging the structure of your tests.
All binaries to be transferred to the platform will be created under ut/bin
Building the testing suite requires a tool-chain. This can be a vendor-independent tool-chain, an SDK, or any other tool-chain as required.
Requirements for building
The unitTest(ut)
for a module is triggered from scripts, which inturn that clone the ut-core
framework (at a fixed version) and builds the defined tests. This allows for independent upgrades to the ut-core
framework if desired.
Script templates are provided in the template
directory to illustrate the necessary files for each layer, starting from the HAL. See template/README.md
The testing relationship is as follows:
erDiagram
HAL }|..|{ hal_ut: triggers
hal_ut }|--o{ ut_core: uses
The unit testing core subsystem can be cloned from:
git clone [email protected]:rdkcentral/ut-core
Recommended Reading:
- https://github.com/rdkcentral/ut-core/blob/master/README.md
- https://github.com/rdkcentral/ut-core/blob/master/docs/pages/hal_unit_testing_requirements.md
Note: C++ Support is available after Version 4.0.0
The ut-core
directory structure is as follows:
.
├── docs
│ └── pages
│ └── images
├── framework
│ └── cunit
│ ├── arm-rdk-linux-gnueabi -> Arm prebuild version of cunit.so
│ └── i686-pc-linux-gnu -> -> Linux prebuild version of cunit.so
│ └── xxx -> Other framework as required
├── include -> ut-core header files
├── src -> ut-core source files
├── template
│ ├── hal_template -> example files for the top level hal directories
│ └── ut_template -> example files for the ut directories
└── tools
├── libs -> (Vendor .so)
└── Makefile
Vendors or developers must provide one of the following:
- Prebuilt libraries included in the SDK.
- Prebuilt libraries in the
libs
directory to link against. - Link the
libs
directory to libraries being worked on in the RDK tree.
The libs
directory can be linked to prebuilt libraries generated by the vendor or the RDK build system. Symbolic links can be used to set up these directories.
The toolchain is provided by the vendor or through an SDK built with the Yocto build system. It's recommended to install the toolchain in the ./tools/2.0
directory.
./rdk-glibc-x86_64-arm-toolchain-2.0.sh
This script installs the toolchain and sysroots
(typically in /opt/rdk/2.0
, but it's recommended to change this to ${PWD}../2.0
).
To use the cross-development toolchain, source the environment setup script:
chmod +x /opt/rdk/2.0/environment-setup-cortexa9t2-vfp-rdk-linux-gnueabi
source /opt/rdk/2.0/environment-setup-cortexa9t2-vfp-rdk-linux-gnueabi
echo $CC
The tool-chain and common environment can be launched by the following sc
commands see :- FAQ:-RDK-Docker-Toolchain
sc docker rdk-dunfell /bin/bash
. /opt/toolchains/rdk-glibc-x86_64-arm-toolchain/environment-setup-armv7at2hf-neon-oe-linux-gnueabi
sc docker list
will list out the environments available (from outside the docker).
There are two platform targets:
-
linux
(default): Builds all tests, the test application, and stubs. -
arm
(TARGET=arm
): Builds all tests and the test application for the target.
make
This builds the src/*.c
files, core functions from ut-core/src/c_source
, and links against libraries in ut-core/framework
. The skeletons/src
directory is included for stub compilation.
Ensure the toolchain is sourced.
make TARGET=arm
This builds the src/*.c
files, core functions from ut-core/src/c_source
, links against libraries in ut-core/framework
, and links against libraries in the libs
directory or the SDK sysroot
. The final binary (hal_test
) is located in the bin
directory.
make VARIANT=CPP
This builds the src/*.c
files, core functions from ut-core/src/cpp_source
, and links against libraries in ut-core/framework
. The skeletons/src
directory is included for stub compilation.
Ensure the toolchain is sourced.
make VARIANT=CPP TARGET=arm
This builds the src/*.c
files, core functions from ut-core/src/cpp_source
, links against libraries in ut-core/framework
, and links against libraries in the libs
directory or the SDK sysroot
. The final binary (hal_test
) is located in the bin
directory.
Copy the files from the bin
directory to the target.
On the target, set the LD_LIBRARY_PATH
environment variable:
export LD_LIBRARY_PATH=/usr/lib:/lib:/home/root:./
Alternatively, use the run.sh
script in the bin
directory.
Execute the hal_test
application:
./hal_test -h
The following flags will only work in C Mode
- Console Mode (
-c
): Opens an interactive console. - Automated Mode (
-a
): Outputs results in xUnit format as an XML file. - Basic Mode (
-b
): Runs all tests and redirects output to the shell.
The tests follow the structure defined in template/ut_template/
:
├── bin
│ └── run.sh
├── build.sh
├── docs
│ ├── generate_docs.sh
│ └── pages
│ ├── L1_TestSpecification.md
│ ├── L2_TestSpecification.md
│ └── README.md -> ../../README.md
├── Makefile
├── README.md
├── skeletons
│ └── src
├── src
│ ├── main.c
│ ├── test_l1_test_example.c
│ └── test_l2_tests_example.c
└── tools
The main.c
file in the src
directory is the main launch point for the test application.
Since the ut-core interfaces will change over time, and in order to be consistant when creating tests engineers should select the major release they wish to fixed too. (Although it's recommended to periodically upgrade to a later revision )
The interface will not change between minor versions, but the most recent bugfix version should be selected.
The versioning format for the testing suites is therefore <major.minor.bugfix/patch/documentation>
In the file ut_template/build.sh
you can see the template version of the script.
This is selected via UT_CORE_PROJECT_VERSION
variable as an input in the default build script for the tests suite e.g. ut/build.sh UT_CORE_PROJECT_VERSION=2.0.0
or by changing the fixed version set in your unit testing build.sh
trigger script.
For best practice and receive bug fixes define UT_PROJECT_MAJOR_VERSION
in ut/build.sh
to choose the major revision that the testing suite should compile against.
ut-core
will assure backwards compatibility in major versions. This means that the bugfixes and minor changes you will automatically acquire on the next test run.
# Change this to upgrade your UT-Core Major versions. Non ABI Changes 1.x.x are supported, between major revisions
UT_PROJECT_MAJOR_VERSION="1."
The main test app will register all the tests and kick off the framework.
#include <string.h>
#include <stdlib.h>
#include <ut.h>
void test_l1_function1(void)
{
UT_FAIL("Need to implement");
/* Positive */
/* Negative */
}
void test_l1_function2(void)
{
UT_FAIL("Need to implement");
/* Positive */
/* Negative */
}
static UT_test_suite_t *pSuite = NULL;
/**
* @brief Register the main tests for this module
*
* @return int - 0 on success, otherwise failure
*/
int test_l1_register( void )
{
/* add a suite to the registry */
pSuite = UT_add_suite("[L1 test_Example]", NULL, NULL);
if (NULL == pSuite)
{
return -1;
}
UT_add_test( pSuite, "blah_level1_test_function", test_l1_function1);
UT_add_test( pSuite, "blah_level1_test_function", test_l1_function2);
return 0;
}
Each module has a optional init
and clean
function, which can be setup via UT_add_suite(), in the above example these are defaulted to NULL
, since in this example case they are not used.