From 012520d2d7e8d2bbc914bb5735bf1563abd0e4ea Mon Sep 17 00:00:00 2001 From: Arkadiusz Cholewinski Date: Wed, 21 Feb 2024 09:28:36 +0100 Subject: [PATCH] Kernel: Integration test Propose scenarios of integration test for kernel testing. Signed-off-by: Arkadiusz Cholewinski --- tests/integration/kernel/CMakeLists.txt | 8 + tests/integration/kernel/prj.conf | 2 + tests/integration/kernel/src/main.c | 307 ++++++++++++++++++++++++ tests/integration/kernel/testcase.yaml | 4 + 4 files changed, 321 insertions(+) create mode 100644 tests/integration/kernel/CMakeLists.txt create mode 100644 tests/integration/kernel/prj.conf create mode 100644 tests/integration/kernel/src/main.c create mode 100644 tests/integration/kernel/testcase.yaml diff --git a/tests/integration/kernel/CMakeLists.txt b/tests/integration/kernel/CMakeLists.txt new file mode 100644 index 00000000000..8cc120f9b85 --- /dev/null +++ b/tests/integration/kernel/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(kernel) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/integration/kernel/prj.conf b/tests/integration/kernel/prj.conf new file mode 100644 index 00000000000..f8d48f84037 --- /dev/null +++ b/tests/integration/kernel/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_MP_MAX_NUM_CPUS=1 diff --git a/tests/integration/kernel/src/main.c b/tests/integration/kernel/src/main.c new file mode 100644 index 00000000000..faf23b96e53 --- /dev/null +++ b/tests/integration/kernel/src/main.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + + +/* COMMON DEFFINITIONS */ +#define STACK_SIZE 500 +#define LIST_LEN 8 + +static struct k_sem sema; +static struct k_thread tdata; + +static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE); + + +/* FIFO SCENARIO */ +/* Thread A enters items into a fifo, starts Thread B and waits for a semaphore. */ +/* Thread B extracts all items from the fifo and enters some items back into the fifo. */ +/* Thread B gives the semaphore for Thread A to continue. */ +/* Once the control is returned back to Thread A, it extracts all items from the fifo. */ +/* Verify the data's correctness. */ + +static K_FIFO_DEFINE(fifo); +struct fifo_item_t { + void *fifo_reserved; /* 1st word reserved for use by FIFO */ + uint8_t value; +}; +static struct fifo_item_t fifo_data[LIST_LEN]; + +static void thread_entry_fn_fifo(void *p1, void *p2, void *p3) +{ + struct fifo_item_t *rx_data; + uint32_t i; + + /* Get items from fifo */ + for (i = 0U; i < LIST_LEN; i++) { + rx_data = k_fifo_get((struct k_fifo *)p1, K_NO_WAIT); + zassert_equal(rx_data->value, fifo_data[i].value); + } + + /* Put items into fifo */ + for (i = 0U; i < LIST_LEN; i++) { + fifo_data[i].value *= i; + k_fifo_put((struct k_fifo *)p1, &fifo_data[i]); + } + + /* Give control back to Thread A */ + k_sem_give(&sema); +} + + +ZTEST(kernel, test_fifo_usage) +{ + struct fifo_item_t *rx_data; + uint32_t i; + + /* Init binary semaphore */ + k_sem_init(&sema, 0, 1); + + /* Set and Put items into fifo */ + for (i = 0U; i < LIST_LEN; i++) { + fifo_data[i].value = i; + k_fifo_put(&fifo, &fifo_data[i]); + } + + /* Create the Thread B */ + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, + thread_entry_fn_fifo, &fifo, NULL, NULL, + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT); + + /* Let the thread B run */ + k_sem_take(&sema, K_FOREVER); + + /* Get items from fifo */ + for (i = 0U; i < LIST_LEN; i++) { + rx_data = k_fifo_get(&fifo, K_NO_WAIT); + zassert_equal(rx_data->value, fifo_data[i].value); + } + + /* Clear the spawn thread */ + k_thread_abort(tid); +} + +/* LIFO SCENARIO */ +/* Thread A enters items into a lifo, starts Thread B and waits for a semaphore. */ +/* Thread B extracts all items from the lifo and enters some items back into the lifo. */ +/* Thread B gives the semaphore for Thread A to continue. */ +/* Once the control is returned back to Thread A, it extracts all items from the lifo. */ +/* Verify the data's correctness. */ + +struct lifo_item_t { + void *LIFO_reserved; /* 1st word reserved for use by LIFO */ + uint8_t value; +}; +static struct lifo_item_t lifo_data[LIST_LEN]; +K_LIFO_DEFINE(lifo); + + +static void thread_entry_fn_lifo(void *p1, void *p2, void *p3) +{ + struct lifo_item_t *rx_data; + uint32_t i; + + /* Get items from lifo */ + for (i = 0U; i < LIST_LEN; i++) { + rx_data = k_lifo_get((struct k_lifo *)p1, K_NO_WAIT); + zassert_equal(rx_data->value, lifo_data[LIST_LEN-1-i].value); + } + + /* Put items into lifo */ + for (i = 0U; i < LIST_LEN; i++) { + lifo_data[i].value *= i; + k_lifo_put((struct k_lifo *)p1, &lifo_data[i]); + } + + /* Give control back to Thread A */ + k_sem_give(&sema); +} + +ZTEST(kernel, test_lifo_usage) +{ + struct lifo_item_t *rx_data; + uint32_t i; + + /* Init binary semaphore */ + k_sem_init(&sema, 0, 1); + + /* Set and Put items into lifo */ + for (i = 0U; i < LIST_LEN; i++) { + lifo_data[i].value = i; + k_lifo_put(&lifo, &lifo_data[i]); + } + + /* Create the Thread B */ + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, + thread_entry_fn_lifo, &lifo, NULL, NULL, + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT); + + /* Let the thread B run */ + k_sem_take(&sema, K_FOREVER); + + /* Get items from lifo */ + for (i = 0U; i < LIST_LEN; i++) { + rx_data = k_lifo_get(&lifo, K_NO_WAIT); + zassert_equal(rx_data->value, lifo_data[LIST_LEN-1-i].value); + } + + /* Clear the spawn thread */ + k_thread_abort(tid); + +} + +/* STACK SCENARIO */ +/* Thread A enters items into a stack, starts thread B and waits for a semaphore. */ +/* Thread B extracts all items from the stack and enters some items back into the stack. */ +/* Thread B gives the semaphore for Thread A to continue. */ +/* Once the control is returned back to Thread A, it extracts all items from the stack. */ +/* Verify the data's correctness. */ + + +#define STACK_LEN 8 +#define MAX_ITEMS 8 + +K_STACK_DEFINE(stack, STACK_LEN); +stack_data_t stack_data[MAX_ITEMS]; + + +static void thread_entry_fn_stack(void *p1, void *p2, void *p3) +{ + stack_data_t *rx_data; + stack_data_t data[MAX_ITEMS]; + + /* fill data to compare */ + for (int i = 0; i < STACK_LEN; i++) { + data[i] = i; + } + + /* read data from a stack */ + for (int i = 0; i < STACK_LEN; i++) { + k_stack_pop((struct k_stack *)p1, (stack_data_t *)&rx_data, K_NO_WAIT); + } + + zassert_false(memcmp(rx_data, data, STACK_LEN), + "Push & Pop items does not match"); + + /* Push data into a stack */ + for (int i = 0; i < STACK_LEN; i++) { + stack_data[i] *= i; + k_stack_push((struct k_stack *)p1, (stack_data_t)&stack_data[i]); + } + + /* Give control back to Thread A */ + k_sem_give(&sema); +} + + +ZTEST(kernel, test_stack_usage) +{ + stack_data_t *rx_data; + + /* Init binary semaphore */ + k_sem_init(&sema, 0, 1); + + /* Push data into a stack */ + for (int i = 0; i < STACK_LEN; i++) { + stack_data[i] = i; + k_stack_push(&stack, (stack_data_t)&stack_data[i]); + } + + /* Create the Thread B */ + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, + thread_entry_fn_stack, &stack, NULL, NULL, + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_NO_WAIT); + + /* Let the thread B run */ + k_sem_take(&sema, K_FOREVER); + + /* read data from a stack */ + for (int i = 0; i < STACK_LEN; i++) { + k_stack_pop(&stack, (stack_data_t *)&rx_data, K_NO_WAIT); + } + + + /* Verify the correctness */ + zassert_false(memcmp(rx_data, stack_data, STACK_LEN), + "Push & Pop items does not match"); + + /* Clear the spawn thread */ + k_thread_abort(tid); +} + +/* MUTEX SCENARIO */ +/* Initialize the mutex. */ +/* Start the two Threads with the entry points. */ +/* The entry points change variable and use lock and unlock mutex functions to */ +/* synchronize the access to that variable. */ +/* Join all threads. */ +/* Verify the variable. */ + +#define NUMBER_OF_ITERATIONS 10000 + +static uint32_t mutex_data; +static struct k_thread tdata_2; +static K_THREAD_STACK_DEFINE(tstack_2, STACK_SIZE); + +K_MUTEX_DEFINE(mutex); + +static void thread_entry_fn_mutex(void *p1, void *p2, void *p3) +{ + uint32_t i; + + for (i = 0; i < NUMBER_OF_ITERATIONS; i++) { + k_mutex_lock((struct k_mutex *)p1, K_FOREVER); + mutex_data += 1; + k_mutex_unlock((struct k_mutex *)p1); + } +} + +static void thread_entry_fn_mutex_2(void *p1, void *p2, void *p3) +{ + uint32_t i; + + for (i = 0; i < NUMBER_OF_ITERATIONS*2; i++) { + k_mutex_lock((struct k_mutex *)p1, K_FOREVER); + mutex_data -= 1; + k_mutex_unlock((struct k_mutex *)p1); + } +} + +ZTEST(kernel, test_mutex_usage) +{ + + /* Create the Thread A */ + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, + thread_entry_fn_mutex, &mutex, &mutex_data, NULL, + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_FOREVER); + + /* Create the Thread B */ + k_tid_t tid2 = k_thread_create(&tdata_2, tstack_2, STACK_SIZE, + thread_entry_fn_mutex_2, &mutex, &mutex_data, NULL, + K_PRIO_PREEMPT(0), K_INHERIT_PERMS, K_FOREVER); + + /* Start the Thread A */ + k_thread_start(tid); + /* Start the Thread B */ + k_thread_start(tid2); + /* Wait for end of Thread A */ + k_thread_join(&tdata, K_FOREVER); + /* Wait for end of Thread B */ + k_thread_join(&tdata_2, K_FOREVER); + /* Verify data after the end of the threads */ + zassert_equal(mutex_data, -10000); + + /* Clear the spawn threads */ + k_thread_abort(tid); + k_thread_abort(tid2); +} + + +ZTEST_SUITE(kernel, NULL, NULL, + ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL); diff --git a/tests/integration/kernel/testcase.yaml b/tests/integration/kernel/testcase.yaml new file mode 100644 index 00000000000..c33a25c72c2 --- /dev/null +++ b/tests/integration/kernel/testcase.yaml @@ -0,0 +1,4 @@ +tests: + integration.kernel: + tags: + - kernel