Skip to content

UT‐Core: How to Build and Run a HAL Testing Suite

Ulrond edited this page Nov 14, 2024 · 5 revisions

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.

1. Navigate to the Header File

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 

2. Build the Testing Suite

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

3. Build Environment Requirements

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
Loading

4. Core UT Framework

The unit testing core subsystem can be cloned from:

git clone [email protected]:rdkcentral/ut-core

Recommended Reading:

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

5. Vendor or Developer Requirements

Vendors or developers must provide one of the following:

  1. Prebuilt libraries included in the SDK.
  2. Prebuilt libraries in the libs directory to link against.
  3. 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.

7. Toolchain

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.

7.1. How to Use the SDK Toolchain

./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

7.2. Docker Based Toolchain

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).

8. Testing Environment and Making the Code

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.

9. Build the linux environment with C language

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.

10. Build the target arm environment with C language

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.

11. Build the linux environment with CPP language

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.

12. Build the target arm environment with CPP language

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.

13. Running on the Target

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 

14. Modes of Operation

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.

15. Source Tree UT Unit Test Directory

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.

16. Choosing a Major Version of the UT-Core

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."

17. Example of Registering Test Functions

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.

Clone this wiki locally