diff --git a/.github/workflows/examples-openiotsdk.yaml b/.github/workflows/examples-openiotsdk.yaml index f7a574877ad49f..65c7b69b18bd14 100644 --- a/.github/workflows/examples-openiotsdk.yaml +++ b/.github/workflows/examples-openiotsdk.yaml @@ -26,7 +26,7 @@ concurrency: jobs: openiotsdk: name: Open IoT SDK examples building - timeout-minutes: 90 + timeout-minutes: 140 env: TEST_NETWORK_NAME: OIStest @@ -87,6 +87,12 @@ jobs: examples/lock-app/openiotsdk/build/chip-openiotsdk-lock-app-example.elf \ /tmp/bloat_reports/ + - name: Build unit tests + id: build_unit_tests + timeout-minutes: 10 + run: | + scripts/examples/openiotsdk_example.sh unit-tests + - name: Test shell example if: steps.build_shell.outcome == 'success' timeout-minutes: 5 @@ -100,3 +106,9 @@ jobs: scripts/setup/openiotsdk/network_setup.sh -n $TEST_NETWORK_NAME up scripts/run_in_ns.sh ${TEST_NETWORK_NAME}ns scripts/examples/openiotsdk_example.sh -C test -n ${TEST_NETWORK_NAME}tap lock-app scripts/setup/openiotsdk/network_setup.sh -n $TEST_NETWORK_NAME down + + - name: Run unit tests + if: steps.build_unit_tests.outcome == 'success' && github.event_name == 'pull_request' + timeout-minutes: 90 + run: | + scripts/examples/openiotsdk_example.sh -C run unit-tests diff --git a/.vscode/launch.json b/.vscode/launch.json index 26d362a17794fc..bf83cc0d85d6e4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -439,6 +439,20 @@ "runToEntryPoint": "main", "preLaunchTask": "Debug Open IoT SDK example", "showDevDebugOutput": "parsed" + }, + { + "name": "Debug Open IoT SDK unit-tests application", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}/src/test_driver/openiotsdk/unit-tests", + "executable": "./build/${input:openiotsdkUnittest}.elf", + "armToolchainPath": "${env:ARM_GCC_TOOLCHAIN_PATH}/bin", + "servertype": "external", + "gdbTarget": ":31627", //GDBserver port on FVP + "overrideLaunchCommands": ["-enable-pretty-printing"], + "runToEntryPoint": "main", + "preLaunchTask": "Debug Open IoT SDK unit-tests", + "showDevDebugOutput": "parsed" } ], "inputs": [ @@ -507,6 +521,39 @@ "id": "openiotsdkRemoteHost", "description": "Type the hostname/IP address of external GDB target that you want to connect to. Leave blank for internal GDB server", "default": "" + }, + { + "type": "pickString", + "id": "openiotsdkUnittest", + "description": "What Open IoT SDK unit test do you want to use?", + "options": [ + "accesstest", + "AppTests", + "ASN1Tests", + "BDXTests", + "ChipCryptoTests", + "ControllerTests", + "CoreTests", + "CredentialsTest", + "DataModelTests", + "InetLayerTests", + "MdnsTests", + "MessagingLayerTests", + "MinimalMdnsCoreTests", + "MinimalMdnsRecordsTests", + "MinimalMdnsRespondersTests", + "PlatformTests", + "RawTransportTests", + "RetransmitTests", + "SecureChannelTests", + "SetupPayloadTests", + "SupportTests", + "SystemLayerTests", + "TestShell", + "TransportLayerTests", + "UserDirectedCommissioningTests" + ], + "default": "accesstest" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b6b5c5c5fa95ae..fd815494affee7 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -262,6 +262,21 @@ } } }, + { + "label": "Build Open IoT SDK unit-tests", + "type": "shell", + "command": "scripts/examples/openiotsdk_example.sh", + "args": ["-Cbuild", "-d${input:openiotsdkDebugMode}", "unit-tests"], + "group": "build", + "problemMatcher": { + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "message": 5 + } + } + }, { "label": "Run Open IoT SDK example", "type": "shell", @@ -283,6 +298,21 @@ } } }, + { + "label": "Run Open IoT SDK unit-tests", + "type": "shell", + "command": "scripts/examples/openiotsdk_example.sh", + "args": ["-Crun", "unit-tests", "${input:openiotsdkUnitTest}"], + "group": "test", + "problemMatcher": { + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "message": 5 + } + } + }, { "label": "Test Open IoT SDK example", "type": "shell", @@ -331,6 +361,32 @@ "endsPattern": "^.*Connected to localhost*" } } + }, + { + "label": "Debug Open IoT SDK unit-tests", + "type": "shell", + "command": "scripts/examples/openiotsdk_example.sh", + "args": [ + "-Crun", + "-dtrue", + "unit-tests", + "${input:openiotsdkUnitTest}" + ], + "group": "none", + "isBackground": true, + "problemMatcher": { + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "message": 5 + }, + "background": { + "activeOnStart": true, + "beginsPattern": "^.*Trying*", + "endsPattern": "^.*Connected to localhost*" + } + } } ], "inputs": [ @@ -390,6 +446,40 @@ "options": ["shell", "lock-app"], "default": "shell" }, + { + "type": "pickString", + "id": "openiotsdkUnitTest", + "description": "What unit test do you want to use?", + "options": [ + "all", + "accesstest", + "AppTests", + "ASN1Tests", + "BDXTests", + "ChipCryptoTests", + "ControllerTests", + "CoreTests", + "CredentialsTest", + "DataModelTests", + "InetLayerTests", + "MdnsTests", + "MessagingLayerTests", + "MinimalMdnsCoreTests", + "MinimalMdnsRecordsTests", + "MinimalMdnsRespondersTests", + "PlatformTests", + "RawTransportTests", + "RetransmitTests", + "SecureChannelTests", + "SetupPayloadTests", + "SupportTests", + "SystemLayerTests", + "TestShell", + "TransportLayerTests", + "UserDirectedCommissioningTests" + ], + "default": "all" + }, { "type": "promptString", "id": "openiotsdkNetworkNamespace", diff --git a/scripts/examples/openiotsdk_example.sh b/scripts/examples/openiotsdk_example.sh index faf1ae80349a7e..d700a227d0b767 100755 --- a/scripts/examples/openiotsdk_example.sh +++ b/scripts/examples/openiotsdk_example.sh @@ -40,11 +40,13 @@ TELNET_TERMINAL_PORT=5000 FAILED_TESTS=0 FVP_NETWORK="user" +readarray -t TEST_NAMES <"$CHIP_ROOT"/src/test_driver/openiotsdk/unit-tests/testnames.txt + function show_usage() { cat < parameter as [test_name] + +The "test" command can be used for all supported examples expect the unit-tests. + EOF } @@ -112,7 +126,11 @@ function run_fvp() { exit 1 fi - EXAMPLE_EXE_PATH="$BUILD_PATH/chip-openiotsdk-$EXAMPLE-example.elf" + if [[ $IS_TEST -eq 0 ]]; then + EXAMPLE_EXE_PATH="$BUILD_PATH/chip-openiotsdk-$EXAMPLE-example.elf" + else + EXAMPLE_EXE_PATH="$BUILD_PATH/$EXAMPLE.elf" + fi # Check if executable file exists if ! [ -f "$EXAMPLE_EXE_PATH" ]; then @@ -138,10 +156,30 @@ function run_fvp() { "$FVP_BIN" "${RUN_OPTIONS[@]}" -f "$FVP_CONFIG_FILE" --application "$EXAMPLE_EXE_PATH" >/dev/null 2>&1 & FVP_PID=$! sleep 1 - telnet localhost "$TELNET_TERMINAL_PORT" + + if [[ $IS_TEST -eq 1 ]]; then + set +e + expect <"$EXAMPLE_PATH"/test_report.json + else + telnet localhost "$TELNET_TERMINAL_PORT" + fi # stop the fvp kill -9 "$FVP_PID" || true + set -e sleep 1 } @@ -246,7 +284,7 @@ if [[ $# -lt 1 ]]; then fi case "$1" in - shell | lock-app) + shell | unit-tests | lock-app) EXAMPLE=$1 ;; *) @@ -256,6 +294,29 @@ case "$1" in ;; esac +if [[ "$EXAMPLE" == "unit-tests" ]]; then + if [ ! -z "$2" ]; then + if [[ " ${TEST_NAMES[*]} " =~ " $2 " ]]; then + if [[ "$COMMAND" != *"run"* ]]; then + echo "Test suites can only accept --command run" + show_usage + exit 2 + fi + EXAMPLE=$2 + echo "Run specific unit test $EXAMPLE" + elif [[ "$2" == "all" ]]; then + echo "Use all unit tests" + else + echo " Wrong unit test name" + show_usage + exit 2 + fi + else + echo "Use all unit tests" + fi + IS_TEST=1 +fi + case "$COMMAND" in build | run | test | build-run) ;; *) @@ -266,7 +327,16 @@ case "$COMMAND" in esac TOOLCHAIN_PATH="toolchains/toolchain-$TOOLCHAIN.cmake" -EXAMPLE_PATH="$CHIP_ROOT/examples/$EXAMPLE/openiotsdk" + +if [[ $IS_TEST -eq 0 ]]; then + EXAMPLE_PATH="$CHIP_ROOT/examples/$EXAMPLE/openiotsdk" +else + EXAMPLE_PATH="$CHIP_ROOT/src/test_driver/openiotsdk/unit-tests" + if [[ -f $EXAMPLE_PATH/test_report.json ]]; then + rm -rf "$EXAMPLE_PATH"/test_report.json + fi + echo "{}" >"$EXAMPLE_PATH"/test_report.json +fi if [ -z "$BUILD_PATH" ]; then BUILD_PATH="$EXAMPLE_PATH/build" @@ -277,12 +347,35 @@ if [[ "$COMMAND" == *"build"* ]]; then fi if [[ "$COMMAND" == *"run"* ]]; then - run_fvp + # If user wants to run unit-tests we need to loop through all test names + if [[ "$EXAMPLE" == "unit-tests" ]]; then + if "$DEBUG"; then + echo "You have to specify the test suites to run in debug mode" + show_usage + exit 2 + else + for NAME in "${TEST_NAMES[@]}"; do + EXAMPLE=$NAME + echo "$EXAMPLE_PATH" + echo "Run specific unit test $EXAMPLE" + run_fvp + done + echo "Failed tests total: $FAILED_TESTS" + fi + else + run_fvp + fi fi if [[ "$COMMAND" == *"test"* ]]; then - IS_TEST=1 - run_test + if [[ "$EXAMPLE" == "unit-tests" ]]; then + echo "The test command can not be applied to the unit-tests example" + show_usage + exit 2 + else + IS_TEST=1 + run_test + fi fi if [[ $IS_TEST -eq 1 ]]; then diff --git a/src/BUILD.gn b/src/BUILD.gn index c495ca83d1d908..2a24d53c8fce01 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -107,10 +107,13 @@ if (chip_build_tests) { if (chip_device_platform != "nrfconnect" && chip_device_platform != "efr32") { # TODO(#10447): Controller test has HF on EFR32. - deps += [ - "${chip_root}/src/controller/tests", - "${chip_root}/src/controller/tests/data_model", - ] + deps += [ "${chip_root}/src/controller/tests/data_model" ] + + # Skip controller test for Open IoT SDK + # https://github.com/project-chip/connectedhomeip/issues/23747 + if (chip_device_platform != "openiotsdk") { + deps += [ "${chip_root}/src/controller/tests" ] + } } if (current_os != "zephyr" && current_os != "mbed" && diff --git a/src/app/tests/TestFailSafeContext.cpp b/src/app/tests/TestFailSafeContext.cpp index 9e5d11dc320b73..f0631cd7a92386 100644 --- a/src/app/tests/TestFailSafeContext.cpp +++ b/src/app/tests/TestFailSafeContext.cpp @@ -50,8 +50,10 @@ constexpr FabricIndex kTestAccessingFabricIndex2 = 2; static void TestPlatformMgr_Init(nlTestSuite * inSuite, void * inContext) { +#if !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) CHIP_ERROR err = PlatformMgr().InitChipStack(); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); +#endif // !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) } static void TestFailSafeContext_ArmFailSafe(nlTestSuite * inSuite, void * inContext) @@ -121,7 +123,9 @@ int TestFailSafeContext_Setup(void * inContext) */ int TestFailSafeContext_Teardown(void * inContext) { +#if !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) PlatformMgr().Shutdown(); +#endif // !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) chip::Platform::MemoryShutdown(); return SUCCESS; } diff --git a/src/controller/tests/BUILD.gn b/src/controller/tests/BUILD.gn index ec7f26b6d7d2d4..0528c977c95a3b 100644 --- a/src/controller/tests/BUILD.gn +++ b/src/controller/tests/BUILD.gn @@ -26,9 +26,9 @@ chip_test_suite("tests") { if (chip_device_platform != "mbed" && chip_device_platform != "efr32" && chip_device_platform != "esp32") { test_sources += [ "TestServerCommandDispatch.cpp" ] - test_sources += [ "TestReadChunking.cpp" ] test_sources += [ "TestEventChunking.cpp" ] test_sources += [ "TestEventCaching.cpp" ] + test_sources += [ "TestReadChunking.cpp" ] test_sources += [ "TestWriteChunking.cpp" ] } diff --git a/src/credentials/tests/BUILD.gn b/src/credentials/tests/BUILD.gn index 041d26e20e3138..fd24132e4cab1b 100644 --- a/src/credentials/tests/BUILD.gn +++ b/src/credentials/tests/BUILD.gn @@ -46,7 +46,6 @@ chip_test_suite("tests") { test_sources = [ "TestCertificationDeclaration.cpp", "TestChipCert.cpp", - "TestCommissionerDUTVectors.cpp", "TestDeviceAttestationConstruction.cpp", "TestDeviceAttestationCredentials.cpp", "TestFabricTable.cpp", @@ -54,6 +53,11 @@ chip_test_suite("tests") { "TestPersistentStorageOpCertStore.cpp", ] + # DUTVectors test requires which is not supported on all platforms + if (chip_device_platform != "openiotsdk") { + test_sources += [ "TestCommissionerDUTVectors.cpp" ] + } + cflags = [ "-Wconversion" ] public_deps = [ diff --git a/src/inet/tests/TestInetCommonPosix.cpp b/src/inet/tests/TestInetCommonPosix.cpp index e7e658e0252a2c..d7820303a9a995 100644 --- a/src/inet/tests/TestInetCommonPosix.cpp +++ b/src/inet/tests/TestInetCommonPosix.cpp @@ -287,7 +287,9 @@ void InitNetwork() } } #endif // CHIP_TARGET_STYLE_UNIX +#if !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) tcpip_init(OnLwIPInitComplete, NULL); +#endif // !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) // Lock LwIP stack LOCK_TCPIP_CORE(); @@ -457,6 +459,13 @@ void ServiceEvents(uint32_t aSleepTimeMilliseconds) if (sRemainingSystemLayerEventDelay == 0) { +#if defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) + // We need to terminate event loop after performance single step. + // Event loop processing work items until StopEventLoopTask is called. + // Scheduling StopEventLoop task guarantees correct operation of the loop. + chip::DeviceLayer::PlatformMgr().ScheduleWork( + [](intptr_t) -> void { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); }, (intptr_t) nullptr); +#endif // CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK chip::DeviceLayer::PlatformMgr().RunEventLoop(); sRemainingSystemLayerEventDelay = gNetworkOptions.EventDelay; } diff --git a/src/platform/tests/BUILD.gn b/src/platform/tests/BUILD.gn index d34c8b00c88ce4..1de55b7be409ce 100644 --- a/src/platform/tests/BUILD.gn +++ b/src/platform/tests/BUILD.gn @@ -83,7 +83,7 @@ if (chip_device_platform != "none" && chip_device_platform != "fake") { } if (current_os == "zephyr" || current_os == "android" || - current_os == "mbed") { + current_os == "mbed" || current_os == "cmsis-rtos") { test_sources += [ "TestKeyValueStoreMgr.cpp" ] } diff --git a/src/system/tests/TestSystemTimer.cpp b/src/system/tests/TestSystemTimer.cpp index 19a179b2114585..9188d63656a06a 100644 --- a/src/system/tests/TestSystemTimer.cpp +++ b/src/system/tests/TestSystemTimer.cpp @@ -625,12 +625,14 @@ static int TestSetup(void * aContext) return FAILURE; } +#if !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) #if CHIP_SYSTEM_CONFIG_USE_LWIP && LWIP_VERSION_MAJOR == 2 && LWIP_VERSION_MINOR == 0 static sys_mbox_t * sLwIPEventQueue = NULL; sys_mbox_new(sLwIPEventQueue, 100); tcpip_init(NULL, NULL); #endif // CHIP_SYSTEM_CONFIG_USE_LWIP && LWIP_VERSION_MAJOR == 2 && LWIP_VERSION_MINOR == 0 +#endif // !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) sLayer.Init(); @@ -650,9 +652,11 @@ static int TestTeardown(void * aContext) lContext.mLayer->Shutdown(); +#if !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) #if CHIP_SYSTEM_CONFIG_USE_LWIP && (LWIP_VERSION_MAJOR == 2) && (LWIP_VERSION_MINOR == 0) tcpip_finish(NULL, NULL); #endif // CHIP_SYSTEM_CONFIG_USE_LWIP && (LWIP_VERSION_MAJOR == 2) && (LWIP_VERSION_MINOR == 0) +#endif // !defined(CHIP_DEVICE_LAYER_TARGET_OPEN_IOT_SDK) ::chip::Platform::MemoryShutdown(); return (SUCCESS); diff --git a/src/test_driver/openiotsdk/unit-tests/.gitignore b/src/test_driver/openiotsdk/unit-tests/.gitignore new file mode 100644 index 00000000000000..bcd261e241a6c2 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/.gitignore @@ -0,0 +1,2 @@ +build/ +test_report.json diff --git a/src/test_driver/openiotsdk/unit-tests/CMakeLists.txt b/src/test_driver/openiotsdk/unit-tests/CMakeLists.txt new file mode 100644 index 00000000000000..15470ba12589f8 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/CMakeLists.txt @@ -0,0 +1,83 @@ +# +# Copyright (c) 2022 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 3.21) + +get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. REALPATH) +get_filename_component(OPEN_IOT_SDK_CONFIG ${CHIP_ROOT}/config/openiotsdk REALPATH) +get_filename_component(OPEN_IOT_SDK_EXAMPLE_COMMON ${CHIP_ROOT}/examples/platform/openiotsdk REALPATH) + +list(APPEND CMAKE_MODULE_PATH ${OPEN_IOT_SDK_CONFIG}/cmake) + +# Toolchain files need to exist before first call to project +include(toolchain) + +project(chip-open-iot-sdk-unit-tests LANGUAGES C CXX ASM) + +include(sdk) +include(linker) + +# LwIP configuration +if(TARGET lwip-cmsis-port) + # lwip requires user_lwipopts.h, we use the custom settings + target_include_directories(lwipopts + INTERFACE + lwip-config + ) +endif() + +# Application CHIP build configuration +set(CONFIG_CHIP_LIB_TESTS YES) +set(CONFIG_CHIP_DETAIL_LOGGING NO) +set(CONFIG_CHIP_PROGRESS_LOGGING NO) +set(CONFIG_CHIP_AUTOMATION_LOGGING YES) +set(CONFIG_CHIP_ERROR_LOGGING NO) + +include(chip) + +add_subdirectory(${OPEN_IOT_SDK_EXAMPLE_COMMON}/app ./app_build) + +file(STRINGS testnames.txt TEST_NAMES_FROM_FILE) +STRING(REGEX REPLACE "\n" ";" TEST_NAMES_FROM_FILE "${TEST_NAMES_FROM_FILE}") + +foreach(TEST_NAME IN LISTS TEST_NAMES_FROM_FILE) + add_executable(${TEST_NAME}) + target_include_directories(${TEST_NAME} + PRIVATE + main/include + ${CHIP_ROOT}/third_party/nlunit-test/repo/src + ) + + target_sources(${TEST_NAME} + PRIVATE + main/main.cpp + ) + + target_link_libraries(${TEST_NAME} + openiotsdk-app + ) + + # Link the *whole-archives* to keep the static test objects. + target_link_options(${TEST_NAME} + PUBLIC + -Wl,--whole-archive "${CMAKE_CURRENT_BINARY_DIR}/chip_build/lib/lib${TEST_NAME}.a" + -Wl,--no-whole-archive "${CMAKE_CURRENT_BINARY_DIR}/chip_build/lib/libCHIP_tests.a" + -Wl,--no-whole-archive) + + # set_target_link requires APP_TARGET to be defined + set(APP_TARGET ${TEST_NAME}) + set_target_link(${TEST_NAME}) +endforeach() diff --git a/src/test_driver/openiotsdk/unit-tests/README.md b/src/test_driver/openiotsdk/unit-tests/README.md new file mode 100644 index 00000000000000..584f31aea71e0d --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/README.md @@ -0,0 +1,86 @@ +# Matter Open IoT Unit Tests Application + +The Open IoT SDK Unit Tests Application executes all supported unit tests on the +target. + +The Matter unit tests are included in a set of libraries and allow to validate +most of the components used by Matter examples applications. The main goal of +this application is to run registered tests on Open IoT SDK target and check the +results. The final result is the number of tests that failed. + +## Environment setup + +The required environment is the same as for the Matter examples. For information +on how to setup it see +[Open IoT SDK examples](../../../../docs/examples/openiotsdk_examples.md#Environment-setup). + +## Building + +The build process means creating separate executable file for each Matter tested +component. It assumes the use of all supported test libraries and creating +independent applications from them. + +You build using a vscode task or call the script directly from the command line. + +### Building using vscode task + +``` +Command Palette (F1) => Run Task... => Build Open IoT SDK unit-tests => (debug on/off) +``` + +This will call the scripts with the selected parameters. + +### Building using CLI + +You can call the script directly yourself. + +``` +${MATTER_ROOT}/scripts/examples/openiotsdk_example.sh unit-tests +``` + +Use `--help` to get more information about the script options. + +## Running + +Unit-tests applications can be run independently or as an entire set. It runs in +the background and opens a telnet session. The script will open telnet for you +and connect to the port used by the `FVP`. When the telnet process is terminated +it will also terminate the `FVP` instance. + +You can run the application script from a vscode task or call the script +directly. + +Expected output of each executed test: + +``` + [ATM] Open IoT SDK unit-tests start + [ATM] Open IoT SDK unit-tests run... + ... + [ATM] Test status: 0 +``` + +### Running using vscode task + +``` +Command Palette (F1) => Run Task... => Run Open IoT SDK unit-tests => or all (to run all tests) +``` + +### Running using CLI + +You can call the script directly yourself. + +``` +${MATTER_ROOT}/scripts/examples/openiotsdk_example.sh -C run unit-tests (optional to run specific test) +``` + +## Debugging + +Debugging can be started using a VS code launch task: + +``` +Run and Debug (Ctrl+Shift+D) => Debug Open IoT SDK unit-tests application => Start Debugging (F5) => => +``` + +As you can see above, you will need to select the name of the test twice. This +is because the debug task needs to launch the run task and currently VS code has +no way of passing parameters between tasks. diff --git a/src/test_driver/openiotsdk/unit-tests/cmsis-config/RTE_Components.h b/src/test_driver/openiotsdk/unit-tests/cmsis-config/RTE_Components.h new file mode 100644 index 00000000000000..e86df2b4e44e06 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/cmsis-config/RTE_Components.h @@ -0,0 +1,22 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RTE_COMPONENTS_H +#define RTE_COMPONENTS_H + +#endif // RTE_COMPONENTS_H diff --git a/src/test_driver/openiotsdk/unit-tests/freertos-config/FreeRTOSConfig.h b/src/test_driver/openiotsdk/unit-tests/freertos-config/FreeRTOSConfig.h new file mode 100644 index 00000000000000..6011c1e9d6bf79 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/freertos-config/FreeRTOSConfig.h @@ -0,0 +1,257 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +#if (defined(__ARMCC_VERSION) || defined(__GNUC__) || defined(__ICCARM__)) +#include + +extern uint32_t SystemCoreClock; +#endif + +// Minimal stack size [words] <0-65535> +// Stack for idle task and default task stack in words. +// Default: 128 +#define configMINIMAL_STACK_SIZE ((uint16_t)(4 * 1024)) + +// Total heap size [bytes] <0-0xFFFFFFFF> +// Heap memory size in bytes. +// Default: 8192 +#define configTOTAL_HEAP_SIZE ((size_t) 8192) + +// Kernel tick frequency [Hz] <0-0xFFFFFFFF> +// Kernel tick rate in Hz. +// Default: 1000 +#define configTICK_RATE_HZ ((TickType_t) 1000) + +// Timer task stack depth [words] <0-65535> +// Stack for timer task in words. +// Default: 80 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +// Timer task priority <0-56> +// Timer task priority. +// Default: 40 (High) +#define configTIMER_TASK_PRIORITY 40 + +// Timer queue length <0-1024> +// Timer command queue length. +// Default: 5 +#define configTIMER_QUEUE_LENGTH 5 + +// Preemption interrupt priority +// Maximum priority of interrupts that are safe to call FreeRTOS API. +// Default: 16 +#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << (8 - configPRIO_BITS)) + +// Use time slicing +// Enable setting to use timeslicing. +// Default: 1 +#define configUSE_TIME_SLICING 1 + +// Idle should yield +// Control Yield behaviour of the idle task. +// Default: 1 +#define configIDLE_SHOULD_YIELD 1 + +// Check for stack overflow +// <0=>Disable <1=>Method one <2=>Method two +// Enable or disable stack overflow checking. +// Callback function vApplicationStackOverflowHook implementation is required when stack checking is enabled. +// Default: 0 +#define configCHECK_FOR_STACK_OVERFLOW 2 + +// Use idle hook +// Enable callback function call on each idle task iteration. +// Callback function vApplicationIdleHook implementation is required when idle hook is enabled. +// Default: 0 +#define configUSE_IDLE_HOOK 0 + +// Use tick hook +// Enable callback function call during each tick interrupt. +// Callback function vApplicationTickHook implementation is required when tick hook is enabled. +// Default: 0 +#define configUSE_TICK_HOOK 0 + +// Use deamon task startup hook +// Enable callback function call when timer service starts. +// Callback function vApplicationDaemonTaskStartupHook implementation is required when deamon task startup hook is +// enabled. Default: 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +// Use malloc failed hook +// Enable callback function call when out of dynamic memory. +// Callback function vApplicationMallocFailedHook implementation is required when malloc failed hook is enabled. +// Default: 0 +#define configUSE_MALLOC_FAILED_HOOK 0 + +// Queue registry size +// Define maximum number of queue objects registered for debug purposes. +// The queue registry is used by kernel aware debuggers to locate queue and semaphore structures and display +// associated text names. Default: 0 +#define configQUEUE_REGISTRY_SIZE 0 + +// Event Recorder configuration +// Initialize and setup Event Recorder level filtering. +// Settings have no effect when Event Recorder is not present. + +// Initialize Event Recorder +// Initialize Event Recorder before FreeRTOS kernel start. +// Default: 1 +#define configEVR_INITIALIZE 1 + +// Setup recording level filter +// Enable configuration of FreeRTOS events recording level +// Default: 1 +#define configEVR_SETUP_LEVEL 1 + +// Tasks functions +// Define event recording level bitmask for events generated from Tasks functions. +// Default: 0x05 +// <0x00=>Off <0x01=>Errors <0x05=>Errors + Operation <0x0F=>All +#define configEVR_LEVEL_TASKS 0x05 + +// Queue functions +// Define event recording level bitmask for events generated from Queue functions. +// Default: 0x05 +// <0x00=>Off <0x01=>Errors <0x05=>Errors + Operation <0x0F=>All +#define configEVR_LEVEL_QUEUE 0x05 + +// Timer functions +// Define event recording level bitmask for events generated from Timer functions. +// Default: 0x05 +// <0x00=>Off <0x01=>Errors <0x05=>Errors + Operation <0x0F=>All +#define configEVR_LEVEL_TIMERS 0x05 + +// Event Groups functions +// Define event recording level bitmask for events generated from Event Groups functions. +// Default: 0x05 +// <0x00=>Off <0x01=>Errors <0x05=>Errors + Operation <0x0F=>All +#define configEVR_LEVEL_EVENTGROUPS 0x05 + +// Heap functions +// Define event recording level bitmask for events generated from Heap functions. +// Default: 0x05 +// <0x00=>Off <0x01=>Errors <0x05=>Errors + Operation <0x0F=>All +#define configEVR_LEVEL_HEAP 0x05 + +// Stream Buffer functions +// Define event recording level bitmask for events generated from Stream Buffer functions. +// Default: 0x05 +// <0x00=>Off <0x01=>Errors <0x05=>Errors + Operation <0x0F=>All +#define configEVR_LEVEL_STREAMBUFFER 0x05 +// +// + +// Port Specific Features +// Enable and configure port specific features. +// Check FreeRTOS documentation for definitions that apply for the used port. + +// Use Floating Point Unit +// Using Floating Point Unit (FPU) affects context handling. +// Enable FPU when application uses floating point operations. +// Default: 1 +#define configENABLE_FPU 1 + +// Use Memory Protection Unit +// Using Memory Protection Unit (MPU) requires detailed memory map definition. +// This setting is only releavant for MPU enabled ports. +// Default: 0 +#define configENABLE_MPU 0 + +// Use TrustZone Secure Side Only +// This settings prevents FreeRTOS contex switch to Non-Secure side. +// Enable this setting when FreeRTOS runs on the Secure side only. +#define configRUN_FREERTOS_SECURE_ONLY 1 + +// Use TrustZone Security Extension +// Using TrustZone affects context handling. +// Enable TrustZone when FreeRTOS runs on the Non-Secure side and calls functions from the Secure side. +// Default: 1 +#define configENABLE_TRUSTZONE 0 + +// Minimal secure stack size [words] <0-65535> +// Stack for idle task Secure side context in words. +// This setting is only relevant when TrustZone extension is enabled. +// Default: 128 +#define configMINIMAL_SECURE_STACK_SIZE ((uint32_t) 128) +// + +#ifdef __NVIC_PRIO_BITS +#define configPRIO_BITS __NVIC_PRIO_BITS +#else +#define configPRIO_BITS 4 +#endif + +//------------- <<< end of configuration section >>> --------------------------- + +/* Defines needed by FreeRTOS to implement CMSIS RTOS2 API. Do not change! */ +#define configCPU_CLOCK_HZ (SystemCoreClock) +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configUSE_PREEMPTION 1 +#define configUSE_TIMERS 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configMAX_PRIORITIES 56 +#define configKERNEL_INTERRUPT_PRIORITY (0x07 << (8 - configPRIO_BITS)) + +/* Defines that include FreeRTOS functions which implement CMSIS RTOS2 API. Do not change! */ +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskDelayUntil 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xTimerPendFunctionCall 1 + +/* Map the FreeRTOS port interrupt handlers to their CMSIS standard names. */ +#define xPortPendSVHandler PendSV_Handler +#define vPortSVCHandler SVC_Handler + +/* Ensure Cortex-M port compatibility. */ +#define SysTick_Handler xPortSysTickHandler + +#include "RTE_Components.h" +#include CMSIS_device_header + +#endif /* FREERTOS_CONFIG_H */ diff --git a/src/test_driver/openiotsdk/unit-tests/lwip-config/user_lwipopts.h b/src/test_driver/openiotsdk/unit-tests/lwip-config/user_lwipopts.h new file mode 100644 index 00000000000000..59ed1720c7e36c --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/lwip-config/user_lwipopts.h @@ -0,0 +1,25 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USER_LWIPOPTS_H +#define USER_LWIPOPTS_H + +#define LWIP_STATS (0) +#define PBUF_POOL_SIZE (1001) + +#endif /* USER_LWIPOPTS_H */ diff --git a/src/test_driver/openiotsdk/unit-tests/main/include/CHIPProjectConfig.h b/src/test_driver/openiotsdk/unit-tests/main/include/CHIPProjectConfig.h new file mode 100644 index 00000000000000..bb2c4755245f95 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/main/include/CHIPProjectConfig.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Example project configuration file for CHIP. + * + * This is a place to put application or project-specific overrides + * to the default configuration values for general CHIP features. + * + */ + +#pragma once + +// Enable support functions for parsing command-line arguments +#define CHIP_CONFIG_ENABLE_ARG_PARSER 1 +#define CHIP_CONFIG_NON_POSIX_LONG_OPT 1 + +#define CHIP_SYSTEM_CONFIG_NUM_TIMERS 32 +#define CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE 1 + +#define CONFIG_BUILD_FOR_HOST_UNIT_TEST 1 + +#define CONFIG_IM_BUILD_FOR_UNIT_TEST 1 +#define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT 64 +#define CHIP_CONFIG_MAX_FABRICS 16 +#define CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE 500 + +#define CHIP_SYSTEM_CONFIG_POOL_USE_HEAP 1 diff --git a/src/test_driver/openiotsdk/unit-tests/main/include/NlTestLogger.h b/src/test_driver/openiotsdk/unit-tests/main/include/NlTestLogger.h new file mode 100644 index 00000000000000..f43e3e19081fc2 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/main/include/NlTestLogger.h @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Custom NL test logger implementation + * + */ + +#include +#include + +class NlTestLogger +{ + static void def_log_name(struct _nlTestSuite * inSuite) { printf("[ %s ]\r\n", inSuite->name); } + + static void def_log_initialize(struct _nlTestSuite * inSuite, int inResult, int inWidth) + { + printf("[ %s : %-*s ] : %s\r\n", inSuite->name, inWidth, "Initialize", inResult == FAILURE ? "FAILED" : "PASSED"); + } + static void def_log_terminate(struct _nlTestSuite * inSuite, int inResult, int inWidth) + { + printf("[ %s : %-*s ] : %s\r\n", inSuite->name, inWidth, "Terminate", inResult == FAILURE ? "FAILED" : "PASSED"); + } + + static void def_log_setup(struct _nlTestSuite * inSuite, int inResult, int inWidth) + { + printf("[ %s : %-*s ] : %s\r\n", inSuite->name, inWidth, "Setup", inResult == FAILURE ? "FAILED" : "PASSED"); + } + + static void def_log_test(struct _nlTestSuite * inSuite, int inWidth, int inIndex) + { + printf("[ %s : %-*s ] : %s\r\n", inSuite->name, inWidth, inSuite->tests[inIndex].name, + inSuite->flagError ? "FAILED" : "PASSED"); + } + + static void def_log_teardown(struct _nlTestSuite * inSuite, int inResult, int inWidth) + { + printf("[ %s : %-*s ] : %s\r\n", inSuite->name, inWidth, "TearDown", inResult == FAILURE ? "FAILED" : "PASSED"); + } + + static void def_log_statTest(struct _nlTestSuite * inSuite) + { + printf("Failed Tests: %d / %d\r\n", inSuite->failedTests, inSuite->runTests); + } + + static void def_log_statAssert(struct _nlTestSuite * inSuite) + { + printf("Failed Asserts: %d / %d\r\n", inSuite->failedAssertions, inSuite->performedAssertions); + } + +public: + static constexpr nl_test_output_logger_t nl_test_logger = { + def_log_name, def_log_initialize, def_log_terminate, def_log_setup, + def_log_test, def_log_teardown, def_log_statTest, def_log_statAssert, + }; +}; diff --git a/src/test_driver/openiotsdk/unit-tests/main/main.cpp b/src/test_driver/openiotsdk/unit-tests/main/main.cpp new file mode 100644 index 00000000000000..8c41fd04d68593 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/main/main.cpp @@ -0,0 +1,90 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include + +#include "cmsis_os2.h" +#include "openiotsdk_platform.h" + +constexpr nl_test_output_logger_t NlTestLogger::nl_test_logger; + +using namespace ::chip; + +static void test_thread(void * argument) +{ + int status; + CHIP_ERROR err; + + if (openiotsdk_network_init(true)) + { + ChipLogAutomation("ERROR: Network initialization failed"); + goto exit; + } + + err = DeviceLayer::PlatformMgr().InitChipStack(); + if (err != CHIP_NO_ERROR) + { + ChipLogAutomation("Chip stack initialization failed: %s", err.AsString()); + goto exit; + } + + ChipLogAutomation("Open IoT SDK unit-tests run..."); + status = RunRegisteredUnitTests(); + ChipLogAutomation("Test status: %d", status); + ChipLogAutomation("Open IoT SDK unit-tests completed"); +exit: + osThreadTerminate(osThreadGetId()); +} + +int main() +{ + ChipLogAutomation("Open IoT SDK unit-tests start"); + + if (openiotsdk_platform_init()) + { + ChipLogAutomation("ERROR: Open IoT SDK platform initialization failed"); + return EXIT_FAILURE; + } + + nlTestSetLogger(&NlTestLogger::nl_test_logger); + + static const osThreadAttr_t thread_attr = { + .stack_size = 20 * 1024 // Allocate enough stack for app thread + }; + + osThreadId_t testThread = osThreadNew(test_thread, NULL, &thread_attr); + if (testThread == NULL) + { + ChipLogAutomation("ERROR: Failed to create app thread"); + return EXIT_FAILURE; + } + + if (openiotsdk_platform_run()) + { + ChipLogAutomation("ERROR: Open IoT SDK platform run failed"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/test_driver/openiotsdk/unit-tests/testnames.txt b/src/test_driver/openiotsdk/unit-tests/testnames.txt new file mode 100644 index 00000000000000..03fa4aee9b70f4 --- /dev/null +++ b/src/test_driver/openiotsdk/unit-tests/testnames.txt @@ -0,0 +1,24 @@ +accesstest +AppTests +ASN1Tests +BDXTests +ChipCryptoTests +CoreTests +CredentialsTest +DataModelTests +InetLayerTests +MdnsTests +MessagingLayerTests +MinimalMdnsCoreTests +MinimalMdnsRecordsTests +MinimalMdnsRespondersTests +PlatformTests +RawTransportTests +RetransmitTests +SecureChannelTests +SetupPayloadTests +SupportTests +SystemLayerTests +TestShell +TransportLayerTests +UserDirectedCommissioningTests