blob: 2ad23a2091ef047740005cc957632f86d1e43f0b [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
/**
* @brief Define and initialize test_pipe at compile time
*/
K_PIPE_DEFINE(test_pipe, 256, 4);
#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
#define PIPE_SIZE (256)
K_PIPE_DEFINE(small_pipe, 10, 4);
K_THREAD_STACK_DEFINE(stack_1, STACK_SIZE);
K_SEM_DEFINE(get_sem, 0, 1);
K_SEM_DEFINE(put_sem, 1, 1);
K_SEM_DEFINE(sync_sem, 0, 1);
K_SEM_DEFINE(multiple_send_sem, 0, 1);
ZTEST_BMEM uint8_t tx_buffer[PIPE_SIZE + 1];
ZTEST_BMEM uint8_t rx_buffer[PIPE_SIZE + 1];
#define TOTAL_ELEMENTS (sizeof(single_elements) / sizeof(struct pipe_sequence))
#define TOTAL_WAIT_ELEMENTS (sizeof(wait_elements) / \
sizeof(struct pipe_sequence))
#define TOTAL_TIMEOUT_ELEMENTS (sizeof(timeout_elements) / \
sizeof(struct pipe_sequence))
/* Minimum tx/rx size*/
/* the pipe will always pass */
#define NO_CONSTRAINT (0U)
/* Pipe will at least put one byte */
#define ATLEAST_1 (1U)
/* Pipe must put all data on the buffer */
#define ALL_BYTES (sizeof(tx_buffer))
#define RETURN_SUCCESS (0)
#define TIMEOUT_VAL (K_MSEC(10))
#define TIMEOUT_200MSEC (K_MSEC(200))
/* encompassing structs */
struct pipe_sequence {
uint32_t size;
uint32_t min_size;
uint32_t sent_bytes;
int return_value;
};
static const struct pipe_sequence single_elements[] = {
{ 0, ALL_BYTES, 0, 0 },
{ 1, ALL_BYTES, 1, RETURN_SUCCESS },
{ PIPE_SIZE - 1, ALL_BYTES, PIPE_SIZE - 1, RETURN_SUCCESS },
{ PIPE_SIZE, ALL_BYTES, PIPE_SIZE, RETURN_SUCCESS },
{ PIPE_SIZE + 1, ALL_BYTES, 0, -EIO },
/* minimum 1 byte */
/* {0, ATLEAST_1, 0, -EIO}, */
{ 1, ATLEAST_1, 1, RETURN_SUCCESS },
{ PIPE_SIZE - 1, ATLEAST_1, PIPE_SIZE - 1, RETURN_SUCCESS },
{ PIPE_SIZE, ATLEAST_1, PIPE_SIZE, RETURN_SUCCESS },
{ PIPE_SIZE + 1, ATLEAST_1, PIPE_SIZE, RETURN_SUCCESS },
/* /\* any number of bytes *\/ */
{ 0, NO_CONSTRAINT, 0, 0 },
{ 1, NO_CONSTRAINT, 1, RETURN_SUCCESS },
{ PIPE_SIZE - 1, NO_CONSTRAINT, PIPE_SIZE - 1, RETURN_SUCCESS },
{ PIPE_SIZE, NO_CONSTRAINT, PIPE_SIZE, RETURN_SUCCESS },
{ PIPE_SIZE + 1, NO_CONSTRAINT, PIPE_SIZE, RETURN_SUCCESS }
};
static const struct pipe_sequence multiple_elements[] = {
{ PIPE_SIZE / 3, ALL_BYTES, PIPE_SIZE / 3, RETURN_SUCCESS, },
{ PIPE_SIZE / 3, ALL_BYTES, PIPE_SIZE / 3, RETURN_SUCCESS, },
{ PIPE_SIZE / 3, ALL_BYTES, PIPE_SIZE / 3, RETURN_SUCCESS, },
{ PIPE_SIZE / 3, ALL_BYTES, 0, -EIO },
{ PIPE_SIZE / 3, ATLEAST_1, PIPE_SIZE / 3, RETURN_SUCCESS },
{ PIPE_SIZE / 3, ATLEAST_1, PIPE_SIZE / 3, RETURN_SUCCESS },
{ PIPE_SIZE / 3, ATLEAST_1, PIPE_SIZE / 3, RETURN_SUCCESS },
{ PIPE_SIZE / 3, ATLEAST_1, 1, RETURN_SUCCESS },
{ PIPE_SIZE / 3, ATLEAST_1, 0, -EIO },
{ PIPE_SIZE / 3, NO_CONSTRAINT, PIPE_SIZE / 3, RETURN_SUCCESS },
{ PIPE_SIZE / 3, NO_CONSTRAINT, PIPE_SIZE / 3, RETURN_SUCCESS },
{ PIPE_SIZE / 3, NO_CONSTRAINT, PIPE_SIZE / 3, RETURN_SUCCESS },
{ PIPE_SIZE / 3, NO_CONSTRAINT, 1, RETURN_SUCCESS },
{ PIPE_SIZE / 3, NO_CONSTRAINT, 0, RETURN_SUCCESS }
};
static const struct pipe_sequence wait_elements[] = {
{ 1, ALL_BYTES, 1, RETURN_SUCCESS },
{ PIPE_SIZE - 1, ALL_BYTES, PIPE_SIZE - 1, RETURN_SUCCESS },
{ PIPE_SIZE, ALL_BYTES, PIPE_SIZE, RETURN_SUCCESS },
{ PIPE_SIZE + 1, ALL_BYTES, PIPE_SIZE + 1, RETURN_SUCCESS },
{ PIPE_SIZE - 1, ATLEAST_1, PIPE_SIZE - 1, RETURN_SUCCESS },
};
static const struct pipe_sequence timeout_elements[] = {
{ 0, ALL_BYTES, 0, 0 },
{ 1, ALL_BYTES, 0, -EAGAIN },
{ PIPE_SIZE - 1, ALL_BYTES, 0, -EAGAIN },
{ PIPE_SIZE, ALL_BYTES, 0, -EAGAIN },
{ PIPE_SIZE + 1, ALL_BYTES, 0, -EAGAIN },
{ 1, ATLEAST_1, 0, -EAGAIN },
{ PIPE_SIZE - 1, ATLEAST_1, 0, -EAGAIN },
{ PIPE_SIZE, ATLEAST_1, 0, -EAGAIN },
{ PIPE_SIZE + 1, ATLEAST_1, 0, -EAGAIN }
};
struct k_thread get_single_tid;
/* Helper functions */
uint32_t rx_buffer_check(char *buffer, uint32_t size)
{
uint32_t index;
for (index = 0U; index < size; index++) {
if (buffer[index] != (char) index) {
printk("buffer[index] = %d index = %d\n",
buffer[index], (char) index);
return index;
}
}
return size;
}
/******************************************************************************/
void pipe_put_single(void)
{
uint32_t index;
size_t written;
int return_value;
size_t min_xfer;
for (index = 0U; index < TOTAL_ELEMENTS; index++) {
k_sem_take(&put_sem, K_FOREVER);
min_xfer = (single_elements[index].min_size == ALL_BYTES ?
single_elements[index].size :
single_elements[index].min_size);
return_value = k_pipe_put(&test_pipe, &tx_buffer,
single_elements[index].size, &written,
min_xfer, K_NO_WAIT);
zassert_true((return_value ==
single_elements[index].return_value),
" Return value of k_pipe_put mismatch at index = %d expected =%d received = %d\n",
index,
single_elements[index].return_value, return_value);
zassert_true((written == single_elements[index].sent_bytes),
"Bytes written mismatch written is %d but expected is %d index = %d\n",
written,
single_elements[index].sent_bytes, index);
k_sem_give(&get_sem);
}
}
void pipe_get_single(void *p1, void *p2, void *p3)
{
uint32_t index;
size_t read;
int return_value;
size_t min_xfer;
for (index = 0U; index < TOTAL_ELEMENTS; index++) {
k_sem_take(&get_sem, K_FOREVER);
/* reset the rx buffer for the next interation */
(void)memset(rx_buffer, 0, sizeof(rx_buffer));
min_xfer = (single_elements[index].min_size == ALL_BYTES ?
single_elements[index].size :
single_elements[index].min_size);
return_value = k_pipe_get(&test_pipe, &rx_buffer,
single_elements[index].size, &read,
min_xfer, K_NO_WAIT);
zassert_true((return_value ==
single_elements[index].return_value),
"Return value of k_pipe_get mismatch at index = %d expected =%d received = %d\n",
index, single_elements[index].return_value,
return_value);
zassert_true((read == single_elements[index].sent_bytes),
"Bytes read mismatch read is %d but expected is %d index = %d\n",
read, single_elements[index].sent_bytes, index);
zassert_true(rx_buffer_check(rx_buffer, read) == read,
"Bytes read are not matching at index= %d\n expected =%d but received= %d",
index, read, rx_buffer_check(rx_buffer, read));
k_sem_give(&put_sem);
}
k_sem_give(&sync_sem);
}
/******************************************************************************/
void pipe_put_multiple(void)
{
uint32_t index;
size_t written;
int return_value;
size_t min_xfer;
for (index = 0U; index < TOTAL_ELEMENTS; index++) {
min_xfer = (multiple_elements[index].min_size == ALL_BYTES ?
multiple_elements[index].size :
multiple_elements[index].min_size);
return_value = k_pipe_put(&test_pipe, &tx_buffer,
multiple_elements[index].size,
&written,
min_xfer, K_NO_WAIT);
zassert_true((return_value ==
multiple_elements[index].return_value),
"Return value of k_pipe_put mismatch at index = %d expected =%d received = %d\n",
index,
multiple_elements[index].return_value,
return_value);
zassert_true((written == multiple_elements[index].sent_bytes),
"Bytes written mismatch written is %d but expected is %d index = %d\n",
written,
multiple_elements[index].sent_bytes, index);
if (return_value != RETURN_SUCCESS) {
k_sem_take(&multiple_send_sem, K_FOREVER);
}
}
}
void pipe_get_multiple(void *p1, void *p2, void *p3)
{
uint32_t index;
size_t read;
int return_value;
size_t min_xfer;
for (index = 0U; index < TOTAL_ELEMENTS; index++) {
/* reset the rx buffer for the next interation */
(void)memset(rx_buffer, 0, sizeof(rx_buffer));
min_xfer = (multiple_elements[index].min_size == ALL_BYTES ?
multiple_elements[index].size :
multiple_elements[index].min_size);
return_value = k_pipe_get(&test_pipe, &rx_buffer,
multiple_elements[index].size, &read,
min_xfer, K_NO_WAIT);
zassert_true((return_value ==
multiple_elements[index].return_value),
"Return value of k_pipe_get mismatch at index = %d expected =%d received = %d\n",
index, multiple_elements[index].return_value,
return_value);
zassert_true((read == multiple_elements[index].sent_bytes),
"Bytes read mismatch read is %d but expected is %d index = %d\n",
read, multiple_elements[index].sent_bytes, index);
zassert_true(rx_buffer_check(rx_buffer, read) == read,
"Bytes read are not matching at index= %d\n expected =%d but received= %d",
index, read, rx_buffer_check(rx_buffer, read));
if (return_value != RETURN_SUCCESS) {
k_sem_give(&multiple_send_sem);
}
}
k_sem_give(&sync_sem);
}
/******************************************************************************/
void pipe_put_forever_wait(void)
{
size_t written;
int return_value;
/* 1. fill the pipe. */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, K_FOREVER);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_put failed expected = 0 received = %d\n",
return_value);
zassert_true(written == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
/* wake up the get task */
k_sem_give(&get_sem);
/* 2. k_pipe_put() will force a context switch to the other thread. */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, K_FOREVER);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_put failed expected = 0 received = %d\n",
return_value);
zassert_true(written == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
/* 3. k_pipe_put() will force a context switch to the other thread. */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
ATLEAST_1, K_FOREVER);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_put failed expected = 0 received = %d\n",
return_value);
zassert_true(written == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
}
void pipe_get_forever_wait(void *pi, void *p2, void *p3)
{
size_t read;
int return_value;
/* get blocked until put forces the execution to come here */
k_sem_take(&get_sem, K_FOREVER);
/* k_pipe_get will force a context switch to the put function. */
return_value = k_pipe_get(&test_pipe, &rx_buffer,
PIPE_SIZE, &read,
PIPE_SIZE, K_FOREVER);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
/* k_pipe_get will force a context switch to the other thread. */
return_value = k_pipe_get(&test_pipe, &rx_buffer,
PIPE_SIZE, &read,
ATLEAST_1, K_FOREVER);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
/*3. last read to clear the pipe */
return_value = k_pipe_get(&test_pipe, &rx_buffer,
PIPE_SIZE, &read,
ATLEAST_1, K_FOREVER);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
k_sem_give(&sync_sem);
}
/******************************************************************************/
void pipe_put_timeout(void)
{
size_t written;
int return_value;
/* 1. fill the pipe. */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, TIMEOUT_VAL);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_put failed expected = 0 received = %d\n",
return_value);
zassert_true(written == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
/* pipe put cant be satisfied and thus timeout */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, TIMEOUT_VAL);
zassert_true(return_value == -EAGAIN,
"k_pipe_put failed expected = -EAGAIN received = %d\n",
return_value);
zassert_true(written == 0,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
/* Try once more with 1 byte pipe put cant be satisfied and
* thus timeout.
*/
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
ATLEAST_1, TIMEOUT_VAL);
zassert_true(return_value == -EAGAIN,
"k_pipe_put failed expected = -EAGAIN received = %d\n",
return_value);
zassert_true(written == 0,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
k_sem_give(&get_sem);
/* 2. pipe_get thread will now accept this data */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, TIMEOUT_VAL);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_put failed expected = 0 received = %d\n",
return_value);
zassert_true(written == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
/* 3. pipe_get thread will now accept this data */
return_value = k_pipe_put(&test_pipe, &tx_buffer,
PIPE_SIZE, &written,
ATLEAST_1, TIMEOUT_VAL);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_put failed expected = 0 received = %d\n",
return_value);
zassert_true(written == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, written);
}
void pipe_get_timeout(void *pi, void *p2, void *p3)
{
size_t read;
int return_value;
/* get blocked until put forces the execution to come here */
k_sem_take(&get_sem, K_FOREVER);
/* k_pipe_get will do a context switch to the put function. */
return_value = k_pipe_get(&test_pipe, &rx_buffer,
PIPE_SIZE, &read,
PIPE_SIZE, TIMEOUT_VAL);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
/* k_pipe_get will do a context switch to the put function. */
return_value = k_pipe_get(&test_pipe, &rx_buffer,
PIPE_SIZE, &read,
ATLEAST_1, TIMEOUT_VAL);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
/* cleanup the pipe */
return_value = k_pipe_get(&test_pipe, &rx_buffer,
PIPE_SIZE, &read,
ATLEAST_1, TIMEOUT_VAL);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == PIPE_SIZE,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
k_sem_give(&sync_sem);
}
/******************************************************************************/
void pipe_get_on_empty_pipe(void)
{
size_t read;
int return_value;
uint32_t read_size;
uint32_t size_array[] = { 1, PIPE_SIZE - 1, PIPE_SIZE, PIPE_SIZE + 1 };
for (int i = 0; i < 4; i++) {
read_size = size_array[i];
return_value = k_pipe_get(&test_pipe, &rx_buffer,
read_size, &read,
read_size, K_NO_WAIT);
zassert_true(return_value == -EIO,
"k_pipe_get failed expected = -EIO received = %d\n",
return_value);
return_value = k_pipe_get(&test_pipe, &rx_buffer,
read_size, &read,
ATLEAST_1, K_NO_WAIT);
zassert_true(return_value == -EIO,
"k_pipe_get failed expected = -EIO received = %d\n",
return_value);
return_value = k_pipe_get(&test_pipe, &rx_buffer,
read_size, &read,
NO_CONSTRAINT, K_NO_WAIT);
zassert_true(return_value == RETURN_SUCCESS,
"k_pipe_get failed expected = 0 received = %d\n",
return_value);
zassert_true(read == 0,
"k_pipe_put written failed expected = %d received = %d\n",
PIPE_SIZE, read);
}
}
/******************************************************************************/
void pipe_put_forever_timeout(void)
{
uint32_t index;
size_t written;
int return_value;
size_t min_xfer;
/* using this to synchronize the 2 threads */
k_sem_take(&put_sem, K_FOREVER);
for (index = 0U; index < TOTAL_WAIT_ELEMENTS; index++) {
min_xfer = (wait_elements[index].min_size == ALL_BYTES ?
wait_elements[index].size :
wait_elements[index].min_size);
return_value = k_pipe_put(&test_pipe, &tx_buffer,
wait_elements[index].size, &written,
min_xfer, K_FOREVER);
zassert_true((return_value ==
wait_elements[index].return_value),
"Return value of k_pipe_put mismatch at index = %d expected =%d received = %d\n",
index, wait_elements[index].return_value,
return_value);
zassert_true((written == wait_elements[index].sent_bytes),
"Bytes written mismatch written is %d but expected is %d index = %d\n",
written, wait_elements[index].sent_bytes, index);
}
}
void pipe_get_forever_timeout(void *p1, void *p2, void *p3)
{
uint32_t index;
size_t read;
int return_value;
size_t min_xfer;
/* using this to synchronize the 2 threads */
k_sem_give(&put_sem);
for (index = 0U; index < TOTAL_WAIT_ELEMENTS; index++) {
min_xfer = (wait_elements[index].min_size == ALL_BYTES ?
wait_elements[index].size :
wait_elements[index].min_size);
return_value = k_pipe_get(&test_pipe, &rx_buffer,
wait_elements[index].size, &read,
min_xfer, K_FOREVER);
zassert_true((return_value ==
wait_elements[index].return_value),
"Return value of k_pipe_get mismatch at index = %d expected =%d received = %d\n",
index, wait_elements[index].return_value,
return_value);
zassert_true((read == wait_elements[index].sent_bytes),
"Bytes read mismatch read is %d but expected is %d index = %d\n",
read, wait_elements[index].sent_bytes, index);
}
k_sem_give(&sync_sem);
}
/******************************************************************************/
void pipe_put_get_timeout(void)
{
uint32_t index;
size_t read;
int return_value;
size_t min_xfer;
for (index = 0U; index < TOTAL_TIMEOUT_ELEMENTS; index++) {
min_xfer = (timeout_elements[index].min_size == ALL_BYTES ?
timeout_elements[index].size :
timeout_elements[index].min_size);
return_value = k_pipe_get(&test_pipe, &rx_buffer,
timeout_elements[index].size, &read,
min_xfer, TIMEOUT_200MSEC);
zassert_true((return_value ==
timeout_elements[index].return_value),
"Return value of k_pipe_get mismatch at index = %d expected =%d received = %d\n",
index, timeout_elements[index].return_value,
return_value);
zassert_true((read == timeout_elements[index].sent_bytes),
"Bytes read mismatch read is %d but expected is %d index = %d\n",
read, timeout_elements[index].sent_bytes, index);
}
}
/******************************************************************************/
ZTEST_BMEM bool valid_fault;
void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *pEsf)
{
printk("Caught system error -- reason %d\n", reason);
if (valid_fault) {
valid_fault = false; /* reset back to normal */
ztest_test_pass();
} else {
k_fatal_halt(reason);
}
}
/******************************************************************************/
/* Test case entry points */
/**
* @brief Verify pipe with 1 element insert.
*
* @ingroup kernel_pipe_tests
*
* @details
* Test Objective:
* - transfer sequences of bytes of data in whole.
*
* Testing techniques:
* - function and block box testing,Interface testing,
* Dynamic analysis and testing.
*
* Prerequisite Conditions:
* - CONFIG_TEST_USERSPACE.
*
* Input Specifications:
* - N/A
*
* Test Procedure:
* -# Define and initialize a pipe at compile time.
* -# Using a sub thread to get pipe data in whole,
* and check if the data is correct with expected.
* -# Using main thread to put data in whole,
* check if the return is correct with expected.
*
* Expected Test Result:
* - The pipe put/get whole data is correct.
*
* Pass/Fail Criteria:
* - Successful if check points in test procedure are all passed, otherwise failure.
*
* Assumptions and Constraints:
* - N/A
*
* @see k_pipe_put(), k_pipe_get()
*/
ZTEST_USER(pipe, test_pipe_on_single_elements)
{
/* initialize the tx buffer */
for (int i = 0; i < sizeof(tx_buffer); i++) {
tx_buffer[i] = i;
}
k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
pipe_get_single, NULL, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
pipe_put_single();
k_sem_take(&sync_sem, K_FOREVER);
k_thread_abort(&get_single_tid);
ztest_test_pass();
}
/**
* @brief Test when multiple items are present in the pipe
* @details transfer sequences of bytes of data in part.
* - Using a sub thread to get data part.
* - Using main thread to put data part by part
* @ingroup kernel_pipe_tests
* @see k_pipe_put()
*/
ZTEST_USER(pipe, test_pipe_on_multiple_elements)
{
k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
pipe_get_multiple, NULL, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
pipe_put_multiple();
k_sem_take(&sync_sem, K_FOREVER);
k_thread_abort(&get_single_tid);
ztest_test_pass();
}
/**
* @brief Test when multiple items are present with wait
* @ingroup kernel_pipe_tests
* @see k_pipe_put()
*/
ZTEST_USER(pipe, test_pipe_forever_wait)
{
k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
pipe_get_forever_wait, NULL, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
pipe_put_forever_wait();
k_sem_take(&sync_sem, K_FOREVER);
k_thread_abort(&get_single_tid);
ztest_test_pass();
}
/**
* @brief Test pipes with timeout
*
* @ingroup kernel_pipe_tests
*
* @details
* Test Objective:
* - Check if the kernel support supplying a timeout parameter
* indicating the maximum amount of time a process will wait.
*
* Testing techniques:
* - function and block box testing,Interface testing,
* Dynamic analysis and testing.
*
* Prerequisite Conditions:
* - CONFIG_TEST_USERSPACE.
*
* Input Specifications:
* - N/A
*
* Test Procedure:
* -# Create a sub thread to get data from a pipe.
* -# In the sub thread, Set K_MSEC(10) as timeout for k_pipe_get().
* and check the data which get from pipe if correct.
* -# In main thread, use k_pipe_put to put data.
* and check the return of k_pipe_put.
*
* Expected Test Result:
* - The pipe can set timeout and works well.
*
* Pass/Fail Criteria:
* - Successful if check points in test procedure are all passed, otherwise failure.
*
* Assumptions and Constraints:
* - N/A
*
* @see k_pipe_put()
*/
ZTEST_USER(pipe, test_pipe_timeout)
{
k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
pipe_get_timeout, NULL, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
pipe_put_timeout();
k_sem_take(&sync_sem, K_FOREVER);
k_thread_abort(&get_single_tid);
ztest_test_pass();
}
/**
* @brief Test pipe get from a empty pipe
* @ingroup kernel_pipe_tests
* @see k_pipe_get()
*/
ZTEST_USER(pipe, test_pipe_get_on_empty_pipe)
{
pipe_get_on_empty_pipe();
ztest_test_pass();
}
/**
* @brief Test the pipe_get with K_FOREVER as timeout.
* @details Testcase is similar to test_pipe_on_single_elements()
* but with K_FOREVER as timeout.
* @ingroup kernel_pipe_tests
* @see k_pipe_put()
*/
ZTEST_USER(pipe, test_pipe_forever_timeout)
{
k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(0));
k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
pipe_get_forever_timeout, NULL, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
pipe_put_forever_timeout();
k_sem_take(&sync_sem, K_FOREVER);
ztest_test_pass();
}
/**
* @brief k_pipe_get timeout test
* @ingroup kernel_pipe_tests
* @see k_pipe_get()
*/
ZTEST_USER(pipe, test_pipe_get_timeout)
{
pipe_put_get_timeout();
ztest_test_pass();
}
/**
* @brief Test pipe get of invalid size
* @ingroup kernel_pipe_tests
* @see k_pipe_get()
*/
ZTEST_USER(pipe, test_pipe_get_invalid_size)
{
size_t read;
int ret;
valid_fault = true;
ret = k_pipe_get(&test_pipe, &rx_buffer,
0, &read,
1, TIMEOUT_200MSEC);
zassert_equal(ret, -EINVAL,
"fault didn't occur for min_xfer <= bytes_to_read");
}
/**
* @brief Test pipe get returns immediately if >= min_xfer is available
* @ingroup kernel_pipe_tests
* @see k_pipe_get()
*/
ZTEST_USER(pipe, test_pipe_get_min_xfer)
{
int res;
size_t bytes_written = 0;
size_t bytes_read = 0;
char buf[8] = {};
res = k_pipe_put(&test_pipe, "Hi!", 3, &bytes_written,
3 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not write entire message");
zassert_equal(bytes_written, 3, "did not write entire message");
res = k_pipe_get(&test_pipe, buf, sizeof(buf), &bytes_read,
1 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not read at least one byte");
zassert_equal(bytes_read, 3, "did not read all bytes available");
}
/**
* @brief Test pipe put returns immediately if >= min_xfer is available
* @ingroup kernel_pipe_tests
* @see k_pipe_put()
*/
ZTEST_USER(pipe, test_pipe_put_min_xfer)
{
int res;
size_t bytes_written = 0;
/* write 6 bytes into the pipe, so that 2 bytes are still free */
for (size_t i = 0; i < 2; ++i) {
bytes_written = 0;
res = k_pipe_put(&test_pipe, "Hi!", 3, &bytes_written,
3 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not write entire message");
zassert_equal(bytes_written, 3, "did not write entire message");
}
/* attempt to write 3 bytes, but allow success if >= 1 byte */
bytes_written = 0;
res = k_pipe_put(&test_pipe, "Hi!", 3, &bytes_written,
1 /* min_xfer */, K_FOREVER);
zassert_equal(res, 0, "did not write min_xfer");
zassert_true(bytes_written >= 1, "did not write min_xfer");
/* flush the pipe so other test can write to this pipe */
k_pipe_flush(&test_pipe);
}
/**
* @brief Test defining and initializing pipes at run time
*
* @ingroup kernel_pipe_tests
*
* @details
* Test Objective:
* - Check if the kernel provided a mechanism for defining and
* initializing pipes at run time.
*
* Testing techniques:
* - function and block box testing,Interface testing,
* Dynamic analysis and testing.
*
* Prerequisite Conditions:
* - CONFIG_TEST_USERSPACE.
*
* Input Specifications:
* - N/A
*
* Test Procedure:
* -# Define and initialize a pipe at run time
* -# Using this pipe to transfer data.
* -# Check the pipe get/put operation.
*
* Expected Test Result:
* - Pipe can be defined and initialized at run time.
*
* Pass/Fail Criteria:
* - Successful if check points in test procedure are all passed, otherwise failure.
*
* Assumptions and Constraints:
* - N/A
*
* @see k_pipe_init()
*/
ZTEST(pipe, test_pipe_define_at_runtime)
{
unsigned char ring_buffer[PIPE_SIZE];
struct k_pipe pipe;
size_t written, read;
/*Define and initialize pipe at run time*/
k_pipe_init(&pipe, ring_buffer, sizeof(ring_buffer));
/* initialize the tx buffer */
for (int i = 0; i < sizeof(tx_buffer); i++) {
tx_buffer[i] = i;
}
/*Using test_pipe which define and initialize at run time*/
zassert_equal(k_pipe_put(&pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, K_NO_WAIT), RETURN_SUCCESS, NULL);
/* Returned without waiting; zero data bytes were written. */
zassert_equal(k_pipe_put(&pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, K_NO_WAIT), -EIO, NULL);
/* Waiting period timed out. */
zassert_equal(k_pipe_put(&pipe, &tx_buffer,
PIPE_SIZE, &written,
PIPE_SIZE, TIMEOUT_VAL), -EAGAIN, NULL);
zassert_equal(k_pipe_get(&pipe, &rx_buffer,
PIPE_SIZE, &read,
PIPE_SIZE, K_NO_WAIT), RETURN_SUCCESS, NULL);
zassert_true(rx_buffer_check(rx_buffer, read) == read,
"Bytes read are not match.");
/* Returned without waiting; zero data bytes were read. */
zassert_equal(k_pipe_get(&pipe, &rx_buffer,
PIPE_SIZE, &read,
PIPE_SIZE, K_NO_WAIT), -EIO, NULL);
/* Waiting period timed out. */
zassert_equal(k_pipe_get(&pipe, &rx_buffer,
PIPE_SIZE, &read,
PIPE_SIZE, TIMEOUT_VAL), -EAGAIN, NULL);
}
/**
* @brief Helper thread to test k_pipe_flush() and k_pipe_buffer_flush()
*
* This helper thread attempts to write 50 bytes to the pipe identified by
* [p1], which has an internal buffer size of 10. This helper thread is
* expected to fill the internal buffer, and then block until it can complete
* the write.
*/
void test_pipe_flush_helper(void *p1, void *p2, void *p3)
{
struct k_pipe *pipe = (struct k_pipe *)p1;
char buffer[50];
size_t i;
size_t bytes_written;
int rv;
for (i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
rv = k_pipe_put(pipe, buffer, sizeof(buffer), &bytes_written,
sizeof(buffer), K_FOREVER);
zassert_true(rv == 0, "k_pipe_put() failed with %d", rv);
zassert_true(bytes_written == sizeof(buffer),
"Expected %zu bytes written, not %zu",
sizeof(buffer), bytes_written);
}
/**
* @brief Test flushing a pipe
*
* @ingroup kernel_pipe_tests
*
* @details
* Test Objective:
* - Check if the kernel flushes a pipe properly at runtime.
*
* Testing techniques:
* - function and block box testing,Interface testing,
* Dynamic analysis and testing.
*
* Prerequisite Conditions:
* - CONFIG_TEST_USERSPACE.
*
* Input Specifications:
* - N/A
*
* Test Procedure:
* -# Define and initialize a pipe at run time
* -# Use this pipe to transfer data.
* -# Have a thread fill and block on writing to the pipe
* -# Flush the pipe and check that the pipe is completely empty
* -# Have a thread fill and block on writing to the pipe
* -# Flush only the pipe's buffer and check the results
*
* Expected Test Result:
* - Reading from the pipe after k_pipe_flush() results in no data to read.
* - Reading from the pipe after k_pipe_buffer_flush() results in read data,
* but missing the original data that was in the buffer prior to the flush.
*
* Pass/Fail Criteria:
* - Successful if check points in test procedure are all passed, otherwise
* failure.
*
* Assumptions and Constraints:
* - N/A
*/
ZTEST(pipe, test_pipe_flush)
{
unsigned char results_buffer[50];
size_t bytes_read;
size_t i;
int rv;
memset(results_buffer, 0, sizeof(results_buffer));
(void)k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
test_pipe_flush_helper, &small_pipe, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
k_sleep(K_MSEC(50)); /* give helper thread time to execute */
/* Completely flush the pipe */
k_pipe_flush(&small_pipe);
rv = k_pipe_get(&small_pipe, results_buffer, sizeof(results_buffer),
&bytes_read, 0, K_MSEC(100));
zassert_true(rv == 0, "k_pipe_get() failed with %d\n", rv);
zassert_true(bytes_read == 0,
"k_pipe_get() unexpectedly read %zu bytes\n", bytes_read);
rv = k_thread_join(&get_single_tid, K_MSEC(50));
zassert_true(rv == 0, "Wait for helper thread failed (%d)", rv);
(void)k_thread_create(&get_single_tid, stack_1, STACK_SIZE,
test_pipe_flush_helper, &small_pipe, NULL, NULL,
K_PRIO_PREEMPT(0), K_INHERIT_PERMS | K_USER,
K_NO_WAIT);
k_sleep(K_MSEC(50)); /* give helper thread time to execute */
/*
* Only flush the pipe's buffer. This is expected to leave 40 bytes
* left to receive.
*/
k_pipe_buffer_flush(&small_pipe);
rv = k_pipe_get(&small_pipe, results_buffer, sizeof(results_buffer),
&bytes_read, 0, K_MSEC(100));
zassert_true(rv == 0, "k_pipe_get() failed with %d\n", rv);
zassert_true(bytes_read == 40,
"k_pipe_get() unexpectedly read %zu bytes\n", bytes_read);
for (i = 0; i < 40; i++) {
zassert_true(results_buffer[i] == (unsigned char)(i + 10),
"At offset %zd, expected byte %02x, not %02x\n",
i, (i + 10), results_buffer[i]);
}
rv = k_thread_join(&get_single_tid, K_MSEC(50));
zassert_true(rv == 0, "Wait for helper thread failed (%d)", rv);
}