mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/freertos_test_reorganization' into 'master'
FreeRTOS: Add test reorganization guidelines and initial batch of refactored tests Closes IDF-5997 See merge request espressif/esp-idf!20233
This commit is contained in:
commit
5f85f507fb
@ -4,11 +4,19 @@ menu "FreeRTOS"
|
||||
# Upstream FreeRTOS configurations go here
|
||||
|
||||
config FREERTOS_SMP
|
||||
bool "Run the SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)"
|
||||
bool "Run the Amazon SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)"
|
||||
default "n"
|
||||
help
|
||||
This will cause the FreeRTOS component to compile with the SMP FreeRTOS kernel instead.
|
||||
THIS FEATURE IS UNDER ACTIVE DEVELOPMENT, users use this at their own risk.
|
||||
Amazon has released an SMP version of the FreeRTOS Kernel which can be found via the following link:
|
||||
https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/smp
|
||||
|
||||
IDF has added an experimental port of this SMP kernel located in
|
||||
components/freertos/FreeRTOS-Kernel-SMP. Enabling this option will cause IDF to use the Amazon SMP
|
||||
kernel. Note that THIS FEATURE IS UNDER ACTIVE DEVELOPMENT, users use this at their own risk.
|
||||
|
||||
Leaving this option disabled will mean the IDF FreeRTOS kernel is used instead, which is located in:
|
||||
components/freertos/FreeRTOS-Kernel. Both kernel versions are SMP capable, but differ in
|
||||
their implementation and features.
|
||||
|
||||
config FREERTOS_UNICORE
|
||||
# Todo: Replace with CONFIG_NUM_CORES (IDF-4986)
|
||||
|
@ -1,3 +1,6 @@
|
||||
# For refactored FreeRTOS unit tests, we need to support #include "xxx.h" of FreeRTOS headers
|
||||
idf_component_get_property(FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH)
|
||||
|
||||
idf_component_register(SRC_DIRS integration/event_groups
|
||||
integration/queue
|
||||
integration/stream_buffer
|
||||
@ -6,6 +9,6 @@ idf_component_register(SRC_DIRS integration/event_groups
|
||||
miscellaneous
|
||||
performance
|
||||
port
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_INCLUDE_DIRS . ./integration "${FREERTOS_ORIG_INCLUDE_PATH}"
|
||||
PRIV_REQUIRES cmock test_utils esp_system driver esp_timer)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
73
components/freertos/test/integration/README.md
Normal file
73
components/freertos/test/integration/README.md
Normal file
@ -0,0 +1,73 @@
|
||||
# FreeRTOS Tests Guidelines
|
||||
|
||||
The FreeRTOS tests are currently being refactored/reorganized with the goal of being upstreamed. This document describes the set of guidelines to which the tests are refactored/reorganized according to.
|
||||
|
||||
## Unity Port
|
||||
|
||||
These test cases assume that the FreeRTOS port has also ported the [Unity Test Framework](https://github.com/ThrowTheSwitch/Unity). Because each FreeRTOS test case will require the scheduler to be started, the way that each test case is invoked will differ form regular Unity ports.
|
||||
|
||||
Regular Unity ports will assume that the `main()` function invokes each test using the `RUN_TEST()` macro. However, these test cases assume the following about the Unity port:
|
||||
|
||||
- Each test case is invoked from a `UnityTask` instead of `main()`. Thus each test case is run from the context of the `UnityTask`.
|
||||
- The `UnityTask` is created using `xTaskCreate...()` (and pinned to core 0 if SMP) from the port's startup (i.e., `main()`)
|
||||
- The port's startup (i.e., `main()`) should also start the scheduler using `vTaskStartScheduler()`
|
||||
- Note that this is similar to the startup of most FreeRTOS Demos.
|
||||
- Each test case is defined using the `TEST_CASE(name, ...)` macro. The `VA_ARGS` of the macro allows each port to specify a set of extra arguments (such as test case labels/tags) to be used into their CI pipelines.
|
||||
- A `portTestMacro.h` must be provided by each port. This header will contain
|
||||
- Some constants used by test cases such as default task stack sizes (e.g., `configTEST_DEFAULT_STACK_SIZE`)
|
||||
- Some port implementation specific functions/macros required by test cases such as getting current system time (e.g., `portTEST_GET_TIME()`).
|
||||
|
||||
## Test Organization
|
||||
|
||||
- Test cases are grouped into sub-directories roughly matching the header files of FreeRTOS (e.g., task, queue, semaphore, event groups etc).
|
||||
- Each source file should ideally test a particular behavior (e.g., priority scheduling, queue send, scheduler suspend). This should usually result in one test case per behavior, thus one test case per source file
|
||||
- Some test case behaviors may depend on configuration (e.g., priority scheduling in single core vs SMP). In such cases
|
||||
- If the affect is small, use an `#if (config... == 1)` to wrap the affected areas
|
||||
- If the affect is large, write a separate test case in a separate source file and wrap the entire test case with `#if (config... == 1)`.
|
||||
|
||||
## Test Case Template
|
||||
|
||||
Each test case should have the following:
|
||||
|
||||
- Test case description describing
|
||||
- Purpose of the test case
|
||||
- Test case procedure
|
||||
- Excepted outcome/behavior of the test case
|
||||
- The test case code wrapped in its required `config...` macros
|
||||
- The expected outcomes should be tested using the `TEST_ASSERT_...()` macros provided by unity
|
||||
|
||||
```c
|
||||
// In test_priority_scheduling.c
|
||||
|
||||
/*
|
||||
Test Priority Scheduling (Single Core)
|
||||
|
||||
Purpose:
|
||||
- Test that the single-core scheduler always schedules the highest priority ready task
|
||||
Procedure:
|
||||
- Raise the unityTask priority to (configMAX_PRIORITIES - 1)
|
||||
- unityTask creates the following lower priority tasks
|
||||
- task_A (configMAX_PRIORITIES - 2)
|
||||
- task_B (configMAX_PRIORITIES - 3)
|
||||
- UnityTask blocks for a short period of time to allow task_A to run
|
||||
- Clean up and restore unityTask's original priority
|
||||
Expected:
|
||||
- task_A should run after unityTask blocks
|
||||
- task_B should never have run
|
||||
*/
|
||||
#if ( configNUM_CORES == 1 )
|
||||
|
||||
static BaseType_t test_static_var = 0;
|
||||
|
||||
static void test_static_func(void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
TEST_CASE("Tasks: Priority scheduling single core", "[freertos]")
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
#endif /* configNUM_CORES == 1 */
|
||||
```
|
13
components/freertos/test/integration/portTestMacro.h
Normal file
13
components/freertos/test/integration/portTestMacro.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "test_utils.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
#define configTEST_DEFAULT_STACK_SIZE 4096
|
||||
#define configTEST_UNITY_TASK_PRIORITY UNITY_FREERTOS_PRIORITY
|
||||
|
||||
#define portTEST_GET_TIME() ((UBaseType_t) esp_cpu_get_cycle_count())
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "unity.h"
|
||||
#include "portTestMacro.h"
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
Test Priority Scheduling (Single Core)
|
||||
|
||||
Purpose:
|
||||
- Test that the single-core scheduler always schedules the highest priority ready task
|
||||
Procedure:
|
||||
- Raise the unityTask priority to (configMAX_PRIORITIES - 1)
|
||||
- unityTask creates the following lower priority tasks
|
||||
- task_A (configMAX_PRIORITIES - 2)
|
||||
- task_B (configMAX_PRIORITIES - 3)
|
||||
- UnityTask blocks for a short period of time to allow task_A to run
|
||||
- Clean up and restore unityTask's original priority
|
||||
Expected:
|
||||
- task_A should run after unityTask blocks
|
||||
- task_B should never have run
|
||||
*/
|
||||
|
||||
#if ( configNUM_CORES == 1 )
|
||||
|
||||
#define UNITY_TASK_DELAY_TICKS 10
|
||||
|
||||
static BaseType_t task_A_ran;
|
||||
static BaseType_t task_B_ran;
|
||||
|
||||
static void task_A(void *arg)
|
||||
{
|
||||
task_A_ran = pdTRUE;
|
||||
/* Keeping spinning to prevent the lower priority task_B from running */
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void task_B(void *arg)
|
||||
{
|
||||
/* The following should never run due to task_B having a lower priority */
|
||||
task_B_ran = pdTRUE;
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Tasks: Test priority scheduling", "[freertos]")
|
||||
{
|
||||
TaskHandle_t task_A_handle;
|
||||
TaskHandle_t task_B_handle;
|
||||
task_A_ran = pdFALSE;
|
||||
task_B_ran = pdFALSE;
|
||||
|
||||
/* Raise the priority of the unityTask */
|
||||
vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1);
|
||||
/* Create task_A and task_B */
|
||||
xTaskCreate(task_A, "task_A", configTEST_DEFAULT_STACK_SIZE, (void *)xTaskGetCurrentTaskHandle(), configMAX_PRIORITIES - 2, &task_A_handle);
|
||||
xTaskCreate(task_B, "task_B", configTEST_DEFAULT_STACK_SIZE, (void *)xTaskGetCurrentTaskHandle(), configMAX_PRIORITIES - 3, &task_B_handle);
|
||||
|
||||
/* Block to allow task_A to be scheduled */
|
||||
vTaskDelay(UNITY_TASK_DELAY_TICKS);
|
||||
|
||||
/* Test that only task_A has run */
|
||||
TEST_ASSERT_EQUAL(pdTRUE, task_A_ran);
|
||||
TEST_ASSERT_EQUAL(pdFALSE, task_B_ran);
|
||||
|
||||
vTaskDelete(task_A_handle);
|
||||
vTaskDelete(task_B_handle);
|
||||
/* Restore the priority of the unityTask */
|
||||
vTaskPrioritySet(NULL, configTEST_UNITY_TASK_PRIORITY);
|
||||
}
|
||||
|
||||
#endif /* configNUM_CORES == 1 */
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
#include "unity.h"
|
||||
#include "portTestMacro.h"
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
Test Priority Scheduling SMP
|
||||
|
||||
Purpose:
|
||||
- Test that the SMP scheduler always schedules the highest priority ready tasks for each core
|
||||
Procedure:
|
||||
- Raise the unityTask priority to (configMAX_PRIORITIES - 1)
|
||||
- unityTask creates the following lower priority tasks for each core
|
||||
- task_A (configMAX_PRIORITIES - 2) for each core
|
||||
- task_B (configMAX_PRIORITIES - 3) for each core
|
||||
- unityTask blocks for a short period of time to allow all of the task_As to run
|
||||
- Clean up and restore unityTask's original priority
|
||||
Expected:
|
||||
- All of the task_As should be run by the scheduler
|
||||
- None of the task_Bs should have run
|
||||
*/
|
||||
|
||||
#if ( defined( CONFIG_FREERTOS_SMP ) && ( configNUM_CORES > 1 ) && ( configRUN_MULTIPLE_PRIORITIES == 1 ) ) \
|
||||
|| ( !defined( CONFIG_FREERTOS_SMP ) && ( configNUM_CORES > 1 ) )
|
||||
|
||||
#define UNITY_TASK_DELAY_TICKS 10
|
||||
|
||||
static BaseType_t task_A_ran[configNUM_CORES];
|
||||
static BaseType_t task_B_ran[configNUM_CORES];
|
||||
|
||||
static void task_A(void *arg)
|
||||
{
|
||||
BaseType_t task_idx = (BaseType_t) arg;
|
||||
task_A_ran[task_idx] = pdTRUE;
|
||||
/* Keeping spinning to prevent the lower priority task_B from running */
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void task_B(void *arg)
|
||||
{
|
||||
/* The following should never be run due to task_B having a lower priority */
|
||||
BaseType_t task_idx = (BaseType_t) arg;
|
||||
task_B_ran[task_idx] = pdTRUE;
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Tasks: Test priority scheduling (SMP)", "[freertos]")
|
||||
{
|
||||
TaskHandle_t task_A_handles[configNUM_CORES];
|
||||
TaskHandle_t task_B_handles[configNUM_CORES];
|
||||
memset(task_A_ran, pdFALSE, sizeof(task_A_ran));
|
||||
memset(task_B_ran, pdFALSE, sizeof(task_B_ran));
|
||||
|
||||
/* Raise the priority of the unityTask */
|
||||
vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1);
|
||||
|
||||
/* Create task_A for each core */
|
||||
for (UBaseType_t x = 0; x < configNUM_CORES; x++) {
|
||||
xTaskCreate(task_A, "task_A", configTEST_DEFAULT_STACK_SIZE, (void *)x, configMAX_PRIORITIES - 2, &task_A_handles[x]);
|
||||
}
|
||||
|
||||
/* Create task_B for each core */
|
||||
for (UBaseType_t x = 0; x < configNUM_CORES; x++) {
|
||||
xTaskCreate(task_B, "task_B", configTEST_DEFAULT_STACK_SIZE, (void *)x, configMAX_PRIORITIES - 3, &task_B_handles[x]);
|
||||
}
|
||||
|
||||
/* Block to ensure all the task_As to be scheduled */
|
||||
vTaskDelay(UNITY_TASK_DELAY_TICKS);
|
||||
|
||||
/* Check that all the task_As have run, and none of the task_Bs have run */
|
||||
for (UBaseType_t x = 0; x < configNUM_CORES; x++) {
|
||||
TEST_ASSERT_EQUAL(pdTRUE, task_A_ran[x]);
|
||||
TEST_ASSERT_EQUAL(pdFALSE, task_B_ran[x]);
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
for (UBaseType_t x = 0; x < configNUM_CORES; x++) {
|
||||
vTaskDelete(task_A_handles[x]);
|
||||
vTaskDelete(task_B_handles[x]);
|
||||
}
|
||||
|
||||
/* Restore the priority of the unityTask */
|
||||
vTaskPrioritySet(NULL, configTEST_UNITY_TASK_PRIORITY);
|
||||
}
|
||||
|
||||
#endif /* ( defined( CONFIG_FREERTOS_SMP ) && ( configNUM_CORES > 1 ) && ( configRUN_MULTIPLE_PRIORITIES == 1 ) )
|
||||
|| ( !defined( CONFIG_FREERTOS_SMP ) && ( configNUM_CORES > 1 ) ) */
|
Loading…
Reference in New Issue
Block a user