From ea61c2791c10c1eb40382cc813e1c5468b02afe6 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 29 Mar 2016 12:39:20 +0000 Subject: New style test sequences for RT (not complete). git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9179 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- test/rt/source/test/test_root.c | 116 ++++++++ test/rt/source/test/test_root.h | 106 +++++++ test/rt/source/test/test_sequence_001.c | 276 ++++++++++++++++++ test/rt/source/test/test_sequence_001.h | 17 ++ test/rt/source/test/test_sequence_002.c | 341 ++++++++++++++++++++++ test/rt/source/test/test_sequence_002.h | 17 ++ test/rt/source/test/test_sequence_003.c | 124 ++++++++ test/rt/source/test/test_sequence_003.h | 17 ++ test/rt/source/test/test_sequence_004.c | 497 ++++++++++++++++++++++++++++++++ test/rt/source/test/test_sequence_004.h | 17 ++ test/rt/source/test/test_sequence_005.c | 67 +++++ test/rt/source/test/test_sequence_005.h | 17 ++ test/rt/source/test/test_sequence_006.c | 387 +++++++++++++++++++++++++ test/rt/source/test/test_sequence_006.h | 17 ++ test/rt/source/test/test_sequence_007.c | 290 +++++++++++++++++++ test/rt/source/test/test_sequence_007.h | 17 ++ test/rt/source/test/test_sequence_008.c | 270 +++++++++++++++++ test/rt/source/test/test_sequence_008.h | 17 ++ 18 files changed, 2610 insertions(+) create mode 100644 test/rt/source/test/test_root.c create mode 100644 test/rt/source/test/test_root.h create mode 100644 test/rt/source/test/test_sequence_001.c create mode 100644 test/rt/source/test/test_sequence_001.h create mode 100644 test/rt/source/test/test_sequence_002.c create mode 100644 test/rt/source/test/test_sequence_002.h create mode 100644 test/rt/source/test/test_sequence_003.c create mode 100644 test/rt/source/test/test_sequence_003.h create mode 100644 test/rt/source/test/test_sequence_004.c create mode 100644 test/rt/source/test/test_sequence_004.h create mode 100644 test/rt/source/test/test_sequence_005.c create mode 100644 test/rt/source/test/test_sequence_005.h create mode 100644 test/rt/source/test/test_sequence_006.c create mode 100644 test/rt/source/test/test_sequence_006.h create mode 100644 test/rt/source/test/test_sequence_007.c create mode 100644 test/rt/source/test/test_sequence_007.h create mode 100644 test/rt/source/test/test_sequence_008.c create mode 100644 test/rt/source/test/test_sequence_008.h (limited to 'test/rt/source') diff --git a/test/rt/source/test/test_root.c b/test/rt/source/test/test_root.c new file mode 100644 index 000000000..d9aa0a8f2 --- /dev/null +++ b/test/rt/source/test/test_root.c @@ -0,0 +1,116 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +/** + * @mainpage Test Suite Specification + * Test suite for ChibiOS/RT. The purpose of this suite is to perform + * unit tests on the RT modules and to converge to 100% code coverage + * through successive improvements. + * + *

Test Sequences

+ * - @subpage test_sequence_001 + * - @subpage test_sequence_002 + * - @subpage test_sequence_003 + * - @subpage test_sequence_004 + * - @subpage test_sequence_005 + * - @subpage test_sequence_006 + * - @subpage test_sequence_007 + * - @subpage test_sequence_008 + * . + */ + +/** + * @file test_root.c + * @brief Test Suite root structures code. + */ + +#include "hal.h" +#include "ch_test.h" +#include "test_root.h" + +#if !defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/** + * @brief Array of all the test sequences. + */ +const testcase_t * const *test_suite[] = { + test_sequence_001, + test_sequence_002, + test_sequence_003, + test_sequence_004, + test_sequence_005, + test_sequence_006, + test_sequence_007, + test_sequence_008, + NULL +}; + +/*===========================================================================*/ +/* Shared code. */ +/*===========================================================================*/ + +/* + * Static working areas, the following areas can be used for threads or + * used as temporary buffers. + */ +union test_buffers test; + +/* + * Pointers to the spawned threads. + */ +thread_t *threads[MAX_THREADS]; + +/* + * Pointers to the working areas. + */ +void * ROMCONST wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2, + test.wa.T3, test.wa.T4}; + +/* + * Sets a termination request in all the test-spawned threads. + */ +void test_terminate_threads(void) { + int i; + + for (i = 0; i < MAX_THREADS; i++) + if (threads[i]) + chThdTerminate(threads[i]); +} + +/* + * Waits for the completion of all the test-spawned threads. + */ +void test_wait_threads(void) { + int i; + + for (i = 0; i < MAX_THREADS; i++) + if (threads[i] != NULL) { + chThdWait(threads[i]); + threads[i] = NULL; + } +} + +systime_t test_wait_tick(void) { + + chThdSleep(1); + return chVTGetSystemTime(); +} + +#endif /* !defined(__DOXYGEN__) */ diff --git a/test/rt/source/test/test_root.h b/test/rt/source/test/test_root.h new file mode 100644 index 000000000..e167ecc7b --- /dev/null +++ b/test/rt/source/test/test_root.h @@ -0,0 +1,106 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 test_root.h + * @brief Test Suite root structures header. + */ + +#ifndef _SPC5_TEST_ROOT_H_ +#define _SPC5_TEST_ROOT_H_ + +#include "test_sequence_001.h" +#include "test_sequence_002.h" +#include "test_sequence_003.h" +#include "test_sequence_004.h" +#include "test_sequence_005.h" +#include "test_sequence_006.h" +#include "test_sequence_007.h" +#include "test_sequence_008.h" + +#if !defined(__DOXYGEN__) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern const testcase_t * const *test_suite[]; + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Shared definitions. */ +/*===========================================================================*/ + +#define TEST_SUITE_NAME "ChibiOS/RT Test Suite" + +/* + * Allowed delay in timeout checks. + */ +#define ALLOWED_DELAY MS2ST(2) + +/* + * Maximum number of test threads. + */ +#define MAX_THREADS 5 + +/* + * Stack size of test threads. + */ +#if defined(CH_ARCHITECTURE_AVR) || defined(CH_ARCHITECTURE_MSP430) +#define THREADS_STACK_SIZE 48 +#elif defined(CH_ARCHITECTURE_STM8) +#define THREADS_STACK_SIZE 64 +#elif defined(CH_ARCHITECTURE_SIMIA32) +#define THREADS_STACK_SIZE 512 +#else +#define THREADS_STACK_SIZE 128 +#endif + +/* + * Working Area size of test threads. + */ +#define WA_SIZE THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE) + +/* + * Union of all Working Areas, usable as a single large buffer if required. + */ +union test_buffers { + struct { + THD_WORKING_AREA(T0, THREADS_STACK_SIZE); + THD_WORKING_AREA(T1, THREADS_STACK_SIZE); + THD_WORKING_AREA(T2, THREADS_STACK_SIZE); + THD_WORKING_AREA(T3, THREADS_STACK_SIZE); + THD_WORKING_AREA(T4, THREADS_STACK_SIZE); + } wa; + uint8_t buffer[WA_SIZE * 5]; +}; + +extern thread_t *threads[MAX_THREADS]; +extern void * ROMCONST wa[5]; + +void test_terminate_threads(void); +void test_wait_threads(void); +systime_t test_wait_tick(void); + +#endif /* !defined(__DOXYGEN__) */ + +#endif /* _SPC5_TEST_ROOT_H_ */ diff --git a/test/rt/source/test/test_sequence_001.c b/test/rt/source/test/test_sequence_001.c new file mode 100644 index 000000000..c4b944b84 --- /dev/null +++ b/test/rt/source/test/test_sequence_001.c @@ -0,0 +1,276 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_001 [1] System layer and port interface + * + * File: @ref test_sequence_001.c + * + *

Description

+ * The functionality of the system layer and port interface is tested. + * Basic RT functionality is taken for granted or this test suite could + * not even be executed. Errors in implementation are detected by + * executing this sequence with the state checker enabled + * (CH_DBG_STATE_CHECKER=TRUE). + * + *

Test Cases

+ * - @subpage test_001_001 + * - @subpage test_001_002 + * - @subpage test_001_003 + * - @subpage test_001_004 + * . + */ + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +/* Timer callback for testing system functions in ISR context.*/ +static void vtcb(void *p) { + syssts_t sts; + + (void)p; + + /* Testing normal case.*/ + chSysLockFromISR(); + chSysUnlockFromISR(); + + /* Reentrant case.*/ + chSysLockFromISR(); + sts = chSysGetStatusAndLockX(); + chSysRestoreStatusX(sts); + chSysUnlockFromISR(); +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_001_001 [1.1] System integrity functionality + * + *

Description

+ * The system self-test functionality is invoked in order to make an + * initial system state assessment and for coverage. + * + *

Test Steps

+ * - [1.1.1] Testing Ready List integrity. + * - [1.1.2] Testing Virtual Timers List integrity. + * - [1.1.3] Testing Registry List integrity. + * - [1.1.4] Testing Port-defined integrity. + * . + */ + +static void test_001_001_execute(void) { + bool result; + + /* [1.1.1] Testing Ready List integrity.*/ + test_set_step(1); + { + chSysLock(); + result = chSysIntegrityCheckI(CH_INTEGRITY_RLIST); + chSysUnlock(); + test_assert(result == false, "ready list check failed"); + } + + /* [1.1.2] Testing Virtual Timers List integrity.*/ + test_set_step(2); + { + chSysLock(); + result = chSysIntegrityCheckI(CH_INTEGRITY_VTLIST); + chSysUnlock(); + test_assert(result == false, "virtual timers list check failed"); + } + + /* [1.1.3] Testing Registry List integrity.*/ + test_set_step(3); + { + chSysLock(); + result = chSysIntegrityCheckI(CH_INTEGRITY_REGISTRY); + chSysUnlock(); + test_assert(result == false, "registry list check failed"); + } + + /* [1.1.4] Testing Port-defined integrity.*/ + test_set_step(4); + { + chSysLock(); + result = chSysIntegrityCheckI(CH_INTEGRITY_PORT); + chSysUnlock(); + test_assert(result == false, "port layer check failed"); + } +} + +static const testcase_t test_001_001 = { + "System integrity functionality", + NULL, + NULL, + test_001_001_execute +}; + +/** + * @page test_001_002 [1.2] Critical zones functionality + * + *

Description

+ * The critical zones API is invoked for coverage. + * + *

Test Steps

+ * - [1.2.1] Testing chSysGetStatusAndLockX() and + * chSysRestoreStatusX(), non reentrant case. + * - [1.2.2] Testing chSysGetStatusAndLockX() and + * chSysRestoreStatusX(), reentrant case. + * - [1.2.3] Testing chSysUnconditionalLock(). + * - [1.2.4] Testing chSysUnconditionalUnlock(). + * - [1.2.5] Testing from ISR context using a virtual timer. + * . + */ + +static void test_001_002_execute(void) { + syssts_t sts; + virtual_timer_t vt; + + /* [1.2.1] Testing chSysGetStatusAndLockX() and + chSysRestoreStatusX(), non reentrant case.*/ + test_set_step(1); + { + sts = chSysGetStatusAndLockX(); + chSysRestoreStatusX(sts); + } + + /* [1.2.2] Testing chSysGetStatusAndLockX() and + chSysRestoreStatusX(), reentrant case.*/ + test_set_step(2); + { + chSysLock(); + sts = chSysGetStatusAndLockX(); + chSysRestoreStatusX(sts); + chSysUnlock(); + } + + /* [1.2.3] Testing chSysUnconditionalLock().*/ + test_set_step(3); + { + chSysUnconditionalLock(); + chSysUnconditionalLock(); + chSysUnlock(); + } + + /* [1.2.4] Testing chSysUnconditionalUnlock().*/ + test_set_step(4); + { + chSysLock(); + chSysUnconditionalUnlock(); + chSysUnconditionalUnlock(); + } + + /* [1.2.5] Testing from ISR context using a virtual timer.*/ + test_set_step(5); + { + chVTObjectInit(&vt); + chVTSet(&vt, 1, vtcb, NULL); + chThdSleep(10); + + test_assert(chVTIsArmed(&vt) == false, "timer still armed"); + } +} + +static const testcase_t test_001_002 = { + "Critical zones functionality", + NULL, + NULL, + test_001_002_execute +}; + +/** + * @page test_001_003 [1.3] Interrupts handling functionality + * + *

Description

+ * The interrupts handling API is invoked for coverage. + * + *

Test Steps

+ * - [1.3.1] Testing chSysSuspend(), chSysDisable() and chSysEnable(). + * . + */ + +static void test_001_003_execute(void) { + + /* [1.3.1] Testing chSysSuspend(), chSysDisable() and + chSysEnable().*/ + test_set_step(1); + { + chSysSuspend(); + chSysDisable(); + chSysSuspend(); + chSysEnable(); + } +} + +static const testcase_t test_001_003 = { + "Interrupts handling functionality", + NULL, + NULL, + test_001_003_execute +}; + +/** + * @page test_001_004 [1.4] System Tick Counter functionality + * + *

Description

+ * The functionality of the API @p chVTGetSystemTimeX() is tested. + * + *

Test Steps

+ * - [1.4.1] A System Tick Counter increment is expected, the test + * simply hangs if it does not happen. + * . + */ + +static void test_001_004_execute(void) { + + /* [1.4.1] A System Tick Counter increment is expected, the test + simply hangs if it does not happen.*/ + test_set_step(1); + { + systime_t time = chVTGetSystemTimeX(); + while (time == chVTGetSystemTimeX()) { + } + } +} + +static const testcase_t test_001_004 = { + "System Tick Counter functionality", + NULL, + NULL, + test_001_004_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief System layer and port interface. + */ +const testcase_t * const test_sequence_001[] = { + &test_001_001, + &test_001_002, + &test_001_003, + &test_001_004, + NULL +}; diff --git a/test/rt/source/test/test_sequence_001.h b/test/rt/source/test/test_sequence_001.h new file mode 100644 index 000000000..7a71cfc00 --- /dev/null +++ b/test/rt/source/test/test_sequence_001.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_001[]; diff --git a/test/rt/source/test/test_sequence_002.c b/test/rt/source/test/test_sequence_002.c new file mode 100644 index 000000000..a67abf568 --- /dev/null +++ b/test/rt/source/test/test_sequence_002.c @@ -0,0 +1,341 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_002 [2] Threads Functionality + * + * File: @ref test_sequence_002.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to + * threading. + * + *

Test Cases

+ * - @subpage test_002_001 + * - @subpage test_002_002 + * - @subpage test_002_003 + * - @subpage test_002_004 + * . + */ + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +static THD_FUNCTION(thread, p) { + + test_emit_token(*(char *)p); +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_002_001 [2.1] Thread Sleep functionality + * + *

Description

+ * The functionality of @p chThdSleep() and derivatives is tested. + * + *

Test Steps

+ * - [2.1.1] The current system time is read then a sleep is performed + * for 100 system ticks and on exit the system time is verified + * again. + * - [2.1.2] The current system time is read then a sleep is performed + * for 100000 microseconds and on exit the system time is verified + * again. + * - [2.1.3] The current system time is read then a sleep is performed + * for 100 milliseconds and on exit the system time is verified + * again. + * - [2.1.4] The current system time is read then a sleep is performed + * for 1 second and on exit the system time is verified again. + * - [2.1.5] Function chThdSleepUntil() is tested with a timeline of + * "now" + 100 ticks. + * . + */ + +static void test_002_001_execute(void) { + systime_t time; + + /* [2.1.1] The current system time is read then a sleep is performed + for 100 system ticks and on exit the system time is verified + again.*/ + test_set_step(1); + { + time = chVTGetSystemTimeX(); + chThdSleep(100); + test_assert_time_window(time + 100, + time + 100 + CH_CFG_ST_TIMEDELTA + 1, + "out of time window"); + } + + /* [2.1.2] The current system time is read then a sleep is performed + for 100000 microseconds and on exit the system time is verified + again.*/ + test_set_step(2); + { + time = chVTGetSystemTimeX(); + chThdSleepMicroseconds(100000); + test_assert_time_window(time + US2ST(100000), + time + US2ST(100000) + CH_CFG_ST_TIMEDELTA + 1, + "out of time window"); + } + + /* [2.1.3] The current system time is read then a sleep is performed + for 100 milliseconds and on exit the system time is verified + again.*/ + test_set_step(3); + { + time = chVTGetSystemTimeX(); + chThdSleepMilliseconds(100); + test_assert_time_window(time + MS2ST(100), + time + MS2ST(100) + CH_CFG_ST_TIMEDELTA + 1, + "out of time window"); + } + + /* [2.1.4] The current system time is read then a sleep is performed + for 1 second and on exit the system time is verified again.*/ + test_set_step(4); + { + time = chVTGetSystemTimeX(); + chThdSleepSeconds(1); + test_assert_time_window(time + S2ST(1), + time + S2ST(1) + CH_CFG_ST_TIMEDELTA + 1, + "out of time window"); + } + + /* [2.1.5] Function chThdSleepUntil() is tested with a timeline of + "now" + 100 ticks.*/ + test_set_step(5); + { + time = chVTGetSystemTimeX(); + chThdSleepUntil(time + 100); + test_assert_time_window(time + 100, + time + 100 + CH_CFG_ST_TIMEDELTA + 1, + "out of time window"); + } +} + +static const testcase_t test_002_001 = { + "Thread Sleep functionality", + NULL, + NULL, + test_002_001_execute +}; + +/** + * @page test_002_002 [2.2] Ready List functionality, threads priority order + * + *

Description

+ * Five threads, are enqueued in the ready list and atomically + * executed. The test expects the threads to perform their operations + * in correct priority order regardless of the initial order. + * + *

Test Steps

+ * - [2.2.1] Creating 5 threads with increasing priority, execution + * sequence is tested. + * - [2.2.2] Creating 5 threads with decreasing priority, execution + * sequence is tested. + * - [2.2.3] Creating 5 threads with pseudo-random priority, execution + * sequence is tested. + * . + */ + +static void test_002_002_execute(void) { + + /* [2.2.1] Creating 5 threads with increasing priority, execution + sequence is tested.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A"); + test_wait_threads(); + test_assert_sequence("ABCDE", "invalid sequence"); + } + + /* [2.2.2] Creating 5 threads with decreasing priority, execution + sequence is tested.*/ + test_set_step(2); + { + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D"); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E"); + test_wait_threads(); + test_assert_sequence("ABCDE", "invalid sequence"); + } + + /* [2.2.3] Creating 5 threads with pseudo-random priority, execution + sequence is tested.*/ + test_set_step(3); + { + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-4, thread, "D"); + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-5, thread, "E"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread, "A"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-2, thread, "B"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-3, thread, "C"); + test_wait_threads(); + test_assert_sequence("ABCDE", "invalid sequence"); + } +} + +static const testcase_t test_002_002 = { + "Ready List functionality, threads priority order", + NULL, + NULL, + test_002_002_execute +}; + +/** + * @page test_002_003 [2.3] Priority change test + * + *

Description

+ * A series of priority changes are performed on the current thread in + * order to verify that the priority change happens as expected. + * + *

Test Steps

+ * - [2.3.1] Thread priority is increased by one then a check is + * performed. + * - [2.3.2] Thread priority is returned to the previous value then a + * check is performed. + * . + */ + +static void test_002_003_execute(void) { + tprio_t prio, p1; + + /* [2.3.1] Thread priority is increased by one then a check is + performed.*/ + test_set_step(1); + { + prio = chThdGetPriorityX(); + p1 = chThdSetPriority(prio + 1); + test_assert(p1 == prio, "unexpected returned priority level"); + test_assert(chThdGetPriorityX() == prio + 1, "unexpected priority level"); + } + + /* [2.3.2] Thread priority is returned to the previous value then a + check is performed.*/ + test_set_step(2); + { + p1 = chThdSetPriority(p1); + test_assert(p1 == prio + 1, "unexpected returned priority level"); + test_assert(chThdGetPriorityX() == prio, "unexpected priority level"); + } +} + +static const testcase_t test_002_003 = { + "Priority change test", + NULL, + NULL, + test_002_003_execute +}; + +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) +/** + * @page test_002_004 [2.4] Priority change test with Priority Inheritance + * + *

Description

+ * A series of priority changes are performed on the current thread in + * order to verify that the priority change happens as expected. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MUTEXES + * . + * + *

Test Steps

+ * - [2.4.1] Simulating a priority boost situation (prio > realprio). + * - [2.4.2] Raising thread priority above original priority but below + * the boosted level. + * - [2.4.3] Raising thread priority above the boosted level. + * - [2.4.4] Restoring original conditions. + * . + */ + +static void test_002_004_execute(void) { + tprio_t prio, p1; + + /* [2.4.1] Simulating a priority boost situation (prio > realprio).*/ + test_set_step(1); + { + prio = chThdGetPriorityX(); + chThdGetSelfX()->prio += 2; + test_assert(chThdGetPriorityX() == prio + 2, "unexpected priority level"); + } + + /* [2.4.2] Raising thread priority above original priority but below + the boosted level.*/ + test_set_step(2); + { + p1 = chThdSetPriority(prio + 1); + test_assert(p1 == prio, "unexpected returned priority level"); + test_assert(chThdGetSelfX()->prio == prio + 2, "unexpected priority level"); + test_assert(chThdGetSelfX()->realprio == prio + 1, "unexpected returned real priority level"); + } + + /* [2.4.3] Raising thread priority above the boosted level.*/ + test_set_step(3); + { + p1 = chThdSetPriority(prio + 3); + test_assert(p1 == prio + 1, "unexpected returned priority level"); + test_assert(chThdGetSelfX()->prio == prio + 3, "unexpected priority level"); + test_assert(chThdGetSelfX()->realprio == prio + 3, "unexpected real priority level"); + } + + /* [2.4.4] Restoring original conditions.*/ + test_set_step(4); + { + chSysLock(); + chThdGetSelfX()->prio = prio; + chThdGetSelfX()->realprio = prio; + chSysUnlock(); + } +} + +static const testcase_t test_002_004 = { + "Priority change test with Priority Inheritance", + NULL, + NULL, + test_002_004_execute +}; +#endif /* CH_CFG_USE_MUTEXES */ + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Threads Functionality. + */ +const testcase_t * const test_sequence_002[] = { + &test_002_001, + &test_002_002, + &test_002_003, +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) + &test_002_004, +#endif + NULL +}; diff --git a/test/rt/source/test/test_sequence_002.h b/test/rt/source/test/test_sequence_002.h new file mode 100644 index 000000000..fdf3a8148 --- /dev/null +++ b/test/rt/source/test/test_sequence_002.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_002[]; diff --git a/test/rt/source/test/test_sequence_003.c b/test/rt/source/test/test_sequence_003.c new file mode 100644 index 000000000..0e4b1fb7f --- /dev/null +++ b/test/rt/source/test/test_sequence_003.c @@ -0,0 +1,124 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_003 [3] Suspend/Resume + * + * File: @ref test_sequence_003.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to + * threads suspend/resume. + * + *

Test Cases

+ * - @subpage test_003_001 + * . + */ + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +static thread_reference_t tr1; + +static THD_FUNCTION(thread1, p) { + + chThdResumeI(&tr1, MSG_OK); + test_emit_token(*(char *)p); +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_003_001 [3.1] Suspend and Resume functionality + * + *

Description

+ * The functionality of chThdSuspendTimeoutS() and chThdResumeI() is + * tested. + * + *

Test Steps

+ * - [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread + * is remotely resumed with message @p MSG_OK. On return the message + * and the state of the reference are tested. + * - [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread + * is not resumed so a timeout must occur. On return the message and + * the state of the reference are tested. + * . + */ + +static void test_003_001_setup(void) { + tr1 = NULL; +} + +static void test_003_001_execute(void) { + systime_t time; + msg_t msg; + + /* [3.1.1] The function chThdSuspendTimeoutS() is invoked, the thread + is remotely resumed with message @p MSG_OK. On return the message + and the state of the reference are tested.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread1, "A"); + chSysLock(); + msg = chThdSuspendTimeoutS(&tr1, TIME_INFINITE); + chSysUnlock(); + test_assert(NULL == tr1, "not NULL"); + test_assert(MSG_OK == msg,"wrong returned message"); + test_wait_threads(); + } + + /* [3.1.2] The function chThdSuspendTimeoutS() is invoked, the thread + is not resumed so a timeout must occur. On return the message and + the state of the reference are tested.*/ + test_set_step(2); + { + chSysLock(); + time = chVTGetSystemTimeX(); + msg = chThdSuspendTimeoutS(&tr1, MS2ST(1000)); + chSysUnlock(); + test_assert_time_window(time + MS2ST(1000), + time + MS2ST(1000) + 1, + "out of time window"); + test_assert(NULL == tr1, "not NULL"); + test_assert(MSG_TIMEOUT == msg, "wrong returned message"); + } +} + +static const testcase_t test_003_001 = { + "Suspend and Resume functionality", + test_003_001_setup, + NULL, + test_003_001_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Suspend/Resume. + */ +const testcase_t * const test_sequence_003[] = { + &test_003_001, + NULL +}; diff --git a/test/rt/source/test/test_sequence_003.h b/test/rt/source/test/test_sequence_003.h new file mode 100644 index 000000000..71ce5cd65 --- /dev/null +++ b/test/rt/source/test/test_sequence_003.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_003[]; diff --git a/test/rt/source/test/test_sequence_004.c b/test/rt/source/test/test_sequence_004.c new file mode 100644 index 000000000..0be4f03fb --- /dev/null +++ b/test/rt/source/test/test_sequence_004.c @@ -0,0 +1,497 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_004 [4] Counter and Binary Semaphores + * + * File: @ref test_sequence_004.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to + * counter semaphores. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Cases

+ * - @subpage test_004_001 + * - @subpage test_004_002 + * - @subpage test_004_003 + * - @subpage test_004_004 + * - @subpage test_004_005 + * - @subpage test_004_006 + * . + */ + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#include "ch.h" + +static semaphore_t sem1; + +static THD_FUNCTION(thread1, p) { + + chSemWait(&sem1); + test_emit_token(*(char *)p); +} + +static THD_FUNCTION(thread2, p) { + + (void)p; + chThdSleepMilliseconds(50); + chSysLock(); + chSemSignalI(&sem1); /* For coverage reasons */ + chSchRescheduleS(); + chSysUnlock(); +} + +static THD_FUNCTION(thread3, p) { + + (void)p; + chSemWait(&sem1); + chSemSignal(&sem1); +} + +static THD_FUNCTION(thread4, p) { + + chBSemSignal((binary_semaphore_t *)p); +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_004_001 [4.1] Semaphore primitives, no state change + * + *

Description

+ * Wait, Signal and Reset primitives are tested. The testing thread + * does not trigger a state change. + * + *

Test Steps

+ * - [4.1.1] The function chSemWait() is invoked, after return the + * counter and the returned message are tested. + * - [4.1.2] The function chSemSignal() is invoked, after return the + * counter is tested. + * - [4.1.3] The function chSemReset() is invoked, after return the + * counter is tested. + * . + */ + +static void test_004_001_setup(void) { + chSemObjectInit(&sem1, 1); +} + +static void test_004_001_teardown(void) { + chSemReset(&sem1, 0); +} + +static void test_004_001_execute(void) { + + /* [4.1.1] The function chSemWait() is invoked, after return the + counter and the returned message are tested.*/ + test_set_step(1); + { + msg_t msg; + + msg = chSemWait(&sem1); + test_assert_lock(chSemGetCounterI(&sem1) == 0, "wrong counter value"); + test_assert(MSG_OK == msg, "wrong returned message"); + } + + /* [4.1.2] The function chSemSignal() is invoked, after return the + counter is tested.*/ + test_set_step(2); + { + chSemSignal(&sem1); + test_assert_lock(chSemGetCounterI(&sem1) == 1, "wrong counter value"); + } + + /* [4.1.3] The function chSemReset() is invoked, after return the + counter is tested.*/ + test_set_step(3); + { + chSemReset(&sem1, 2); + test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value"); + } +} + +static const testcase_t test_004_001 = { + "Semaphore primitives, no state change", + test_004_001_setup, + test_004_001_teardown, + test_004_001_execute +}; + +/** + * @page test_004_002 [4.2] Semaphore enqueuing test + * + *

Description

+ * Five threads with randomized priorities are enqueued to a semaphore + * then awakened one at time. The test expects that the threads reach + * their goal in FIFO order or priority order depending on the @p + * CH_CFG_USE_SEMAPHORES_PRIORITY configuration setting. + * + *

Test Steps

+ * - [4.2.1] Five threads are created with mixed priority levels (not + * increasing nor decreasing). Threads enqueue on a semaphore + * initialized to zero. + * - [4.2.2] The semaphore is signaled 5 times. The thread activation + * sequence is tested. + * . + */ + +static void test_004_002_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void test_004_002_execute(void) { + + /* [4.2.1] Five threads are created with mixed priority levels (not + increasing nor decreasing). Threads enqueue on a semaphore + initialized to zero.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread1, "A"); + threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+1, thread1, "B"); + threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread1, "C"); + threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+4, thread1, "D"); + threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+2, thread1, "E"); + } + + /* [4.2.2] The semaphore is signaled 5 times. The thread activation + sequence is tested.*/ + test_set_step(2); + { + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + chSemSignal(&sem1); + test_wait_threads(); + #if CH_CFG_USE_SEMAPHORES_PRIORITY + test_assert_sequence("ADCEB", "invalid sequence"); + #else + test_assert_sequence("ABCDE", "invalid sequence"); + #endif + } +} + +static const testcase_t test_004_002 = { + "Semaphore enqueuing test", + test_004_002_setup, + NULL, + test_004_002_execute +}; + +/** + * @page test_004_003 [4.3] Semaphore timeout test + * + *

Description

+ * The three possible semaphore waiting modes (do not wait, wait with + * timeout, wait without timeout) are explored. The test expects that + * the semaphore wait function returns the correct value in each of the + * above scenario and that the semaphore structure status is correct + * after each operation. + * + *

Test Steps

+ * - [4.3.1] Testing special case TIME_IMMEDIATE. + * - [4.3.2] Testing non-timeout condition. + * - [4.3.3] Testing timeout condition. + * . + */ + +static void test_004_003_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void test_004_003_execute(void) { + unsigned i; + systime_t target_time; + msg_t msg; + + /* [4.3.1] Testing special case TIME_IMMEDIATE.*/ + test_set_step(1); + { + msg = chSemWaitTimeout(&sem1, TIME_IMMEDIATE); + test_assert(msg == MSG_TIMEOUT, "wrong wake-up message"); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + + /* [4.3.2] Testing non-timeout condition.*/ + test_set_step(2); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX() - 1, + thread2, 0); + msg = chSemWaitTimeout(&sem1, MS2ST(500)); + test_wait_threads(); + test_assert(msg == MSG_OK, "wrong wake-up message"); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + + /* [4.3.3] Testing timeout condition.*/ + test_set_step(3); + { + target_time = test_wait_tick() + MS2ST(5 * 50); + for (i = 0; i < 5; i++) { + test_emit_token('A' + i); + msg = chSemWaitTimeout(&sem1, MS2ST(50)); + test_assert(msg == MSG_TIMEOUT, "wrong wake-up message"); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + test_assert_sequence("ABCDE", "invalid sequence"); + test_assert_time_window(target_time, target_time + ALLOWED_DELAY, + "out of time window"); + } +} + +static const testcase_t test_004_003 = { + "Semaphore timeout test", + test_004_003_setup, + NULL, + test_004_003_execute +}; + +/** + * @page test_004_004 [4.4] Testing chSemAddCounterI() functionality + * + *

Description

+ * The functon is tested by waking up a thread then the semaphore + * counter value is tested. + * + *

Test Steps

+ * - [4.4.1] A thread is created, it goes to wait on the semaphore. + * - [4.4.2] The semaphore counter is increased by two, it is then + * tested to be one, the thread must have completed. + * . + */ + +static void test_004_004_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void test_004_004_execute(void) { + + /* [4.4.1] A thread is created, it goes to wait on the semaphore.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread1, "A"); + } + + /* [4.4.2] The semaphore counter is increased by two, it is then + tested to be one, the thread must have completed.*/ + test_set_step(2); + { + chSysLock(); + chSemAddCounterI(&sem1, 2); + chSchRescheduleS(); + chSysUnlock(); + test_wait_threads(); + test_assert_lock(chSemGetCounterI(&sem1) == 1, "invalid counter"); + test_assert_sequence("A", "invalid sequence"); + } +} + +static const testcase_t test_004_004 = { + "Testing chSemAddCounterI() functionality", + test_004_004_setup, + NULL, + test_004_004_execute +}; + +/** + * @page test_004_005 [4.5] Testing chSemWaitSignal() functionality + * + *

Description

+ * This test case explicitly addresses the @p chSemWaitSignal() + * function. A thread is created that performs a wait and a signal + * operations. The tester thread is awakened from an atomic wait/signal + * operation. The test expects that the semaphore wait function returns + * the correct value in each of the above scenario and that the + * semaphore structure status is correct after each operation. + * + *

Test Steps

+ * - [4.5.1] An higher priority thread is created that performs + * non-atomical wait and signal operations on a semaphore. + * - [4.5.2] The function chSemSignalWait() is invoked by specifying + * the same semaphore for the wait and signal phases. The counter + * value must be one on exit. + * - [4.5.3] The function chSemSignalWait() is invoked again by + * specifying the same semaphore for the wait and signal phases. The + * counter value must be one on exit. + * . + */ + +static void test_004_005_setup(void) { + chSemObjectInit(&sem1, 0); +} + +static void test_004_005_execute(void) { + + /* [4.5.1] An higher priority thread is created that performs + non-atomical wait and signal operations on a semaphore.*/ + test_set_step(1); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+1, thread3, 0); + } + + /* [4.5.2] The function chSemSignalWait() is invoked by specifying + the same semaphore for the wait and signal phases. The counter + value must be one on exit.*/ + test_set_step(2); + { + chSemSignalWait(&sem1, &sem1); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } + + /* [4.5.3] The function chSemSignalWait() is invoked again by + specifying the same semaphore for the wait and signal phases. The + counter value must be one on exit.*/ + test_set_step(3); + { + chSemSignalWait(&sem1, &sem1); + test_assert(queue_isempty(&sem1.queue), "queue not empty"); + test_assert(sem1.cnt == 0, "counter not zero"); + } +} + +static const testcase_t test_004_005 = { + "Testing chSemWaitSignal() functionality", + test_004_005_setup, + NULL, + test_004_005_execute +}; + +/** + * @page test_004_006 [4.6] Testing Binary Semaphores special case + * + *

Description

+ * This test case tests the binary semaphores functionality. The test + * both checks the binary semaphore status and the expected status of + * the underlying counting semaphore. + * + *

Test Steps

+ * - [4.6.1] Creating a binary semaphore in "taken" state, the state is + * checked. + * - [4.6.2] Resetting the binary semaphore in "taken" state, the state + * must not change. + * - [4.6.3] Starting a signaler thread at a lower priority. + * - [4.6.4] Waiting for the binary semaphore to be signaled, the + * semaphore is expected to be taken. + * - [4.6.5] Signaling the binary semaphore, checking the binary + * semaphore state to be "not taken" and the underlying counter + * semaphore counter to be one. + * - [4.6.6] Signaling the binary semaphore again, the internal state + * must not change from "not taken". + * . + */ + +static void test_004_006_execute(void) { + binary_semaphore_t bsem; + msg_t msg; + + /* [4.6.1] Creating a binary semaphore in "taken" state, the state is + checked.*/ + test_set_step(1); + { + chBSemObjectInit(&bsem, true); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + } + + /* [4.6.2] Resetting the binary semaphore in "taken" state, the state + must not change.*/ + test_set_step(2); + { + chBSemReset(&bsem, true); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + } + + /* [4.6.3] Starting a signaler thread at a lower priority.*/ + test_set_step(3); + { + threads[0] = chThdCreateStatic(wa[0], WA_SIZE, + chThdGetPriorityX()-1, thread4, &bsem); + } + + /* [4.6.4] Waiting for the binary semaphore to be signaled, the + semaphore is expected to be taken.*/ + test_set_step(4); + { + msg = chBSemWait(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) == true, "not taken"); + test_assert(msg == MSG_OK, "unexpected message"); + } + + /* [4.6.5] Signaling the binary semaphore, checking the binary + semaphore state to be "not taken" and the underlying counter + semaphore counter to be one.*/ + test_set_step(5); + { + chBSemSignal(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) ==false, "still taken"); + test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter"); + } + + /* [4.6.6] Signaling the binary semaphore again, the internal state + must not change from "not taken".*/ + test_set_step(6); + { + chBSemSignal(&bsem); + test_assert_lock(chBSemGetStateI(&bsem) == false, "taken"); + test_assert_lock(chSemGetCounterI(&bsem.sem) == 1, "unexpected counter"); + } +} + +static const testcase_t test_004_006 = { + "Testing Binary Semaphores special case", + NULL, + NULL, + test_004_006_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Counter and Binary Semaphores. + */ +const testcase_t * const test_sequence_004[] = { + &test_004_001, + &test_004_002, + &test_004_003, + &test_004_004, + &test_004_005, + &test_004_006, + NULL +}; + +#endif /* CH_CFG_USE_SEMAPHORES */ diff --git a/test/rt/source/test/test_sequence_004.h b/test/rt/source/test/test_sequence_004.h new file mode 100644 index 000000000..caa3a601c --- /dev/null +++ b/test/rt/source/test/test_sequence_004.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_004[]; diff --git a/test/rt/source/test/test_sequence_005.c b/test/rt/source/test/test_sequence_005.c new file mode 100644 index 000000000..da845e148 --- /dev/null +++ b/test/rt/source/test/test_sequence_005.c @@ -0,0 +1,67 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_005 [5] Mutexes, Condition Variables and Priority Inheritance + * + * File: @ref test_sequence_005.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to + * mutexes, condition variables and priority inheritance algorithm. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MUTEXES + * . + * + *

Test Cases

+ * No test cases defined in the test sequence. + */ + +#if (CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +static MUTEX_DECL(m1); +static MUTEX_DECL(m2); +#if CH_CFG_USE_CONDVARS || defined(__DOXYGEN__) +static CONDVAR_DECL(c1); +#endif + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Mutexes, Condition Variables and Priority Inheritance. + */ +const testcase_t * const test_sequence_005[] = { + NULL +}; + +#endif /* CH_CFG_USE_MUTEXES */ diff --git a/test/rt/source/test/test_sequence_005.h b/test/rt/source/test/test_sequence_005.h new file mode 100644 index 000000000..b65d62ace --- /dev/null +++ b/test/rt/source/test/test_sequence_005.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_005[]; diff --git a/test/rt/source/test/test_sequence_006.c b/test/rt/source/test/test_sequence_006.c new file mode 100644 index 000000000..cba9cbf9c --- /dev/null +++ b/test/rt/source/test/test_sequence_006.c @@ -0,0 +1,387 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_006 [6] Mailboxes + * + * File: @ref test_sequence_006.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to + * mailboxes. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MAILBOXES + * . + * + *

Test Cases

+ * - @subpage test_006_001 + * - @subpage test_006_002 + * - @subpage test_006_003 + * . + */ + +#if (CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define MB_SIZE 4 + +static msg_t mb_buffer[MB_SIZE]; +static MAILBOX_DECL(mb1, mb_buffer, MB_SIZE); + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_006_001 [6.1] Mailbox normal API, non-blocking tests + * + *

Description

+ * The mailbox normal API is tested without triggering blocking + * conditions. + * + *

Test Steps

+ * - [6.1.1] Testing the mailbox size. + * - [6.1.2] Resetting the mailbox, conditions are checked, no errors + * expected. + * - [6.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() + * once, no errors expected. + * - [6.1.4] Testing intermediate conditions. Data pointers must be + * aligned, semaphore counters are checked. + * - [6.1.5] Emptying the mailbox using chMBFetch(), no errors + * expected. + * - [6.1.6] Posting and then fetching one more message, no errors + * expected. + * - [6.1.7] Testing final conditions. Data pointers must be aligned to + * buffer start, semaphore counters are checked. + * . + */ + +static void test_006_001_setup(void) { + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_006_001_teardown(void) { + chMBReset(&mb1); +} + +static void test_006_001_execute(void) { + msg_t msg1, msg2; + unsigned i; + + /* [6.1.1] Testing the mailbox size.*/ + test_set_step(1); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + } + + /* [6.1.2] Resetting the mailbox, conditions are checked, no errors + expected.*/ + test_set_step(2); + { + chMBReset(&mb1); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } + + /* [6.1.3] Filling the mailbox using chMBPost() and chMBPostAhead() + once, no errors expected.*/ + test_set_step(3); + { + for (i = 0; i < MB_SIZE - 1; i++) { + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + msg1 = chMBPostAhead(&mb1, 'A', TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [6.1.4] Testing intermediate conditions. Data pointers must be + aligned, semaphore counters are checked.*/ + test_set_step(4); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); + test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); + } + + /* [6.1.5] Emptying the mailbox using chMBFetch(), no errors + expected.*/ + test_set_step(5); + { + for (i = 0; i < MB_SIZE; i++) { + msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + test_emit_token(msg2); + } + test_assert_sequence("ABCD", "wrong get sequence"); + } + + /* [6.1.6] Posting and then fetching one more message, no errors + expected.*/ + test_set_step(6); + { + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [6.1.7] Testing final conditions. Data pointers must be aligned to + buffer start, semaphore counters are checked.*/ + test_set_step(7); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } +} + +static const testcase_t test_006_001 = { + "Mailbox normal API, non-blocking tests", + test_006_001_setup, + test_006_001_teardown, + test_006_001_execute +}; + +/** + * @page test_006_002 [6.2] Mailbox I-Class API, non-blocking tests + * + *

Description

+ * The mailbox I-Class API is tested without triggering blocking + * conditions. + * + *

Test Steps

+ * - [6.2.1] Testing the mailbox size. + * - [6.2.2] Resetting the mailbox, conditions are checked, no errors + * expected. + * - [6.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() + * once, no errors expected. + * - [6.2.4] Testing intermediate conditions. Data pointers must be + * aligned, semaphore counters are checked. + * - [6.2.5] Emptying the mailbox using chMBFetchI(), no errors + * expected. + * - [6.2.6] Posting and then fetching one more message, no errors + * expected. + * - [6.2.7] Testing final conditions. Data pointers must be aligned to + * buffer start, semaphore counters are checked. + * . + */ + +static void test_006_002_setup(void) { + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_006_002_teardown(void) { + chMBReset(&mb1); +} + +static void test_006_002_execute(void) { + msg_t msg1, msg2; + unsigned i; + + /* [6.2.1] Testing the mailbox size.*/ + test_set_step(1); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "wrong size"); + } + + /* [6.2.2] Resetting the mailbox, conditions are checked, no errors + expected.*/ + test_set_step(2); + { + chSysLock(); + chMBResetI(&mb1); + chSysUnlock(); + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert_lock(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert_lock(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } + + /* [6.2.3] Filling the mailbox using chMBPostI() and chMBPostAheadI() + once, no errors expected.*/ + test_set_step(3); + { + for (i = 0; i < MB_SIZE - 1; i++) { + chSysLock(); + msg1 = chMBPostI(&mb1, 'B' + i); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + chSysLock(); + msg1 = chMBPostAheadI(&mb1, 'A'); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [6.2.4] Testing intermediate conditions. Data pointers must be + aligned, semaphore counters are checked.*/ + test_set_step(4); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == 0, "still empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == MB_SIZE, "not full"); + test_assert_lock(mb1.rdptr == mb1.wrptr, "pointers not aligned"); + } + + /* [6.2.5] Emptying the mailbox using chMBFetchI(), no errors + expected.*/ + test_set_step(5); + { + for (i = 0; i < MB_SIZE; i++) { + chSysLock(); + msg1 = chMBFetchI(&mb1, &msg2); + chSysUnlock(); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + test_emit_token(msg2); + } + test_assert_sequence("ABCD", "wrong get sequence"); + } + + /* [6.2.6] Posting and then fetching one more message, no errors + expected.*/ + test_set_step(6); + { + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + msg1 = chMBFetch(&mb1, &msg2, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + + /* [6.2.7] Testing final conditions. Data pointers must be aligned to + buffer start, semaphore counters are checked.*/ + test_set_step(7); + { + test_assert_lock(chMBGetFreeCountI(&mb1) == MB_SIZE, "not empty"); + test_assert_lock(chMBGetUsedCountI(&mb1) == 0, "still full"); + test_assert(mb1.buffer == mb1.wrptr, "write pointer not aligned to base"); + test_assert(mb1.buffer == mb1.rdptr, "read pointer not aligned to base"); + } +} + +static const testcase_t test_006_002 = { + "Mailbox I-Class API, non-blocking tests", + test_006_002_setup, + test_006_002_teardown, + test_006_002_execute +}; + +/** + * @page test_006_003 [6.3] Mailbox timeouts + * + *

Description

+ * The mailbox API is tested for timeouts. + * + *

Test Steps

+ * - [6.3.1] Filling the mailbox. + * - [6.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and + * chMBPostAheadI() timeout. + * - [6.3.3] Resetting the mailbox. + * - [6.3.4] Testing chMBFetch() and chMBFetchI() timeout. + * . + */ + +static void test_006_003_setup(void) { + chMBObjectInit(&mb1, mb_buffer, MB_SIZE); +} + +static void test_006_003_teardown(void) { + chMBReset(&mb1); +} + +static void test_006_003_execute(void) { + msg_t msg1, msg2; + unsigned i; + + /* [6.3.1] Filling the mailbox.*/ + test_set_step(1); + { + for (i = 0; i < MB_SIZE; i++) { + msg1 = chMBPost(&mb1, 'B' + i, TIME_INFINITE); + test_assert(msg1 == MSG_OK, "wrong wake-up message"); + } + } + + /* [6.3.2] Testing chMBPost(), chMBPostI(), chMBPostAhead() and + chMBPostAheadI() timeout.*/ + test_set_step(2); + { + msg1 = chMBPost(&mb1, 'X', 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBPostI(&mb1, 'X'); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + msg1 = chMBPostAhead(&mb1, 'X', 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBPostAheadI(&mb1, 'X'); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + } + + /* [6.3.3] Resetting the mailbox.*/ + test_set_step(3); + { + chMBReset(&mb1); + } + + /* [6.3.4] Testing chMBFetch() and chMBFetchI() timeout.*/ + test_set_step(4); + { + msg1 = chMBFetch(&mb1, &msg2, 1); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + chSysLock(); + msg1 = chMBFetchI(&mb1, &msg2); + chSysUnlock(); + test_assert(msg1 == MSG_TIMEOUT, "wrong wake-up message"); + } +} + +static const testcase_t test_006_003 = { + "Mailbox timeouts", + test_006_003_setup, + test_006_003_teardown, + test_006_003_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Mailboxes. + */ +const testcase_t * const test_sequence_006[] = { + &test_006_001, + &test_006_002, + &test_006_003, + NULL +}; + +#endif /* CH_CFG_USE_MAILBOXES */ diff --git a/test/rt/source/test/test_sequence_006.h b/test/rt/source/test/test_sequence_006.h new file mode 100644 index 000000000..026d07577 --- /dev/null +++ b/test/rt/source/test/test_sequence_006.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_006[]; diff --git a/test/rt/source/test/test_sequence_007.c b/test/rt/source/test/test_sequence_007.c new file mode 100644 index 000000000..a1cd8039d --- /dev/null +++ b/test/rt/source/test/test_sequence_007.c @@ -0,0 +1,290 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_007 [7] Memory Pools + * + * File: @ref test_sequence_007.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to memory + * pools. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_MEMPOOLS + * . + * + *

Test Cases

+ * - @subpage test_007_001 + * - @subpage test_007_002 + * - @subpage test_007_003 + * . + */ + +#if (CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define MEMORY_POOL_SIZE 4 + +static uint32_t objects[MEMORY_POOL_SIZE]; +static MEMORYPOOL_DECL(mp1, sizeof (uint32_t), NULL); +static GUARDEDMEMORYPOOL_DECL(gmp1, sizeof (uint32_t)); + +static void *null_provider(size_t size, unsigned align) { + + (void)size; + (void)align; + + return NULL; +} + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_007_001 [7.1] Loading and emptying a memory pool + * + *

Description

+ * The memory pool functionality is tested by loading and emptying it, + * all conditions are tested. + * + *

Test Steps

+ * - [7.1.1] Adding the objects to the pool using chPoolLoadArray(). + * - [7.1.2] Emptying the pool using chPoolAlloc(). + * - [7.1.3] Now must be empty. + * - [7.1.4] Adding the objects to the pool using chPoolFree(). + * - [7.1.5] Emptying the pool using chPoolAlloc() again. + * - [7.1.6] Now must be empty again. + * - [7.1.7] Covering the case where a provider is unable to return + * more memory. + * . + */ + +static void test_007_001_setup(void) { + chPoolObjectInit(&mp1, sizeof (uint32_t), NULL); +} + +static void test_007_001_execute(void) { + unsigned i; + + /* [7.1.1] Adding the objects to the pool using chPoolLoadArray().*/ + test_set_step(1); + { + chPoolLoadArray(&mp1, objects, MEMORY_POOL_SIZE); + } + + /* [7.1.2] Emptying the pool using chPoolAlloc().*/ + test_set_step(2); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); + } + + /* [7.1.3] Now must be empty.*/ + test_set_step(3); + { + test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); + } + + /* [7.1.4] Adding the objects to the pool using chPoolFree().*/ + test_set_step(4); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + chPoolFree(&mp1, &objects[i]); + } + + /* [7.1.5] Emptying the pool using chPoolAlloc() again.*/ + test_set_step(5); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chPoolAlloc(&mp1) != NULL, "list empty"); + } + + /* [7.1.6] Now must be empty again.*/ + test_set_step(6); + { + test_assert(chPoolAlloc(&mp1) == NULL, "list not empty"); + } + + /* [7.1.7] Covering the case where a provider is unable to return + more memory.*/ + test_set_step(7); + { + chPoolObjectInit(&mp1, sizeof (uint32_t), null_provider); + test_assert(chPoolAlloc(&mp1) == NULL, "provider returned memory"); + } +} + +static const testcase_t test_007_001 = { + "Loading and emptying a memory pool", + test_007_001_setup, + NULL, + test_007_001_execute +}; + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page test_007_002 [7.2] Loading and emptying a guarded memory pool without waiting + * + *

Description

+ * The memory pool functionality is tested by loading and emptying it, + * all conditions are tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [7.2.1] Adding the objects to the pool using + * chGuardedPoolLoadArray(). + * - [7.2.2] Emptying the pool using chGuardedPoolAllocTimeout(). + * - [7.2.3] Now must be empty. + * - [7.2.4] Adding the objects to the pool using chGuardedPoolFree(). + * - [7.2.5] Emptying the pool using chGuardedPoolAllocTimeout() again. + * - [7.2.6] Now must be empty again. + * . + */ + +static void test_007_002_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + +static void test_007_002_execute(void) { + unsigned i; + + /* [7.2.1] Adding the objects to the pool using + chGuardedPoolLoadArray().*/ + test_set_step(1); + { + chGuardedPoolLoadArray(&gmp1, objects, MEMORY_POOL_SIZE); + } + + /* [7.2.2] Emptying the pool using chGuardedPoolAllocTimeout().*/ + test_set_step(2); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + } + + /* [7.2.3] Now must be empty.*/ + test_set_step(3); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + } + + /* [7.2.4] Adding the objects to the pool using + chGuardedPoolFree().*/ + test_set_step(4); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + chGuardedPoolFree(&gmp1, &objects[i]); + } + + /* [7.2.5] Emptying the pool using chGuardedPoolAllocTimeout() + again.*/ + test_set_step(5); + { + for (i = 0; i < MEMORY_POOL_SIZE; i++) + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) != NULL, "list empty"); + } + + /* [7.2.6] Now must be empty again.*/ + test_set_step(6); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, TIME_IMMEDIATE) == NULL, "list not empty"); + } +} + +static const testcase_t test_007_002 = { + "Loading and emptying a guarded memory pool without waiting", + test_007_002_setup, + NULL, + test_007_002_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ + +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) +/** + * @page test_007_003 [7.3] Guarded Memory Pools timeout + * + *

Description

+ * The timeout features for the Guarded Memory Pools is tested. + * + *

Conditions

+ * This test is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_SEMAPHORES + * . + * + *

Test Steps

+ * - [7.3.1] Trying to allocate with 100mS timeout, must fail because + * the pool is empty. + * . + */ + +static void test_007_003_setup(void) { + chGuardedPoolObjectInit(&gmp1, sizeof (uint32_t)); +} + +static void test_007_003_execute(void) { + + /* [7.3.1] Trying to allocate with 100mS timeout, must fail because + the pool is empty.*/ + test_set_step(1); + { + test_assert(chGuardedPoolAllocTimeout(&gmp1, MS2ST(100)) == NULL, "list not empty"); + } +} + +static const testcase_t test_007_003 = { + "Guarded Memory Pools timeout", + test_007_003_setup, + NULL, + test_007_003_execute +}; +#endif /* CH_CFG_USE_SEMAPHORES */ + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Memory Pools. + */ +const testcase_t * const test_sequence_007[] = { + &test_007_001, +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &test_007_002, +#endif +#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__) + &test_007_003, +#endif + NULL +}; + +#endif /* CH_CFG_USE_MEMPOOLS */ diff --git a/test/rt/source/test/test_sequence_007.h b/test/rt/source/test/test_sequence_007.h new file mode 100644 index 000000000..e439f1b22 --- /dev/null +++ b/test/rt/source/test/test_sequence_007.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_007[]; diff --git a/test/rt/source/test/test_sequence_008.c b/test/rt/source/test/test_sequence_008.c new file mode 100644 index 000000000..8f9f5ff0f --- /dev/null +++ b/test/rt/source/test/test_sequence_008.c @@ -0,0 +1,270 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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 "hal.h" +#include "ch_test.h" +#include "test_root.h" + +/** + * @page test_sequence_008 [8] Memory Heaps + * + * File: @ref test_sequence_008.c + * + *

Description

+ * This sequence tests the ChibiOS/RT functionalities related to memory + * heaps. + * + *

Conditions

+ * This sequence is only executed if the following preprocessor condition + * evaluates to true: + * - CH_CFG_USE_HEAP + * . + * + *

Test Cases

+ * - @subpage test_008_001 + * - @subpage test_008_002 + * . + */ + +#if (CH_CFG_USE_HEAP) || defined(__DOXYGEN__) + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#define ALLOC_SIZE 16 +#define HEAP_SIZE (ALLOC_SIZE * 8) + +static memory_heap_t test_heap; +static CH_HEAP_AREA(myheap, HEAP_SIZE); + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page test_008_001 [8.1] Allocation and fragmentation + * + *

Description

+ * Series of allocations/deallocations are performed in carefully + * designed sequences in order to stimulate all the possible code paths + * inside the allocator. The test expects to find the heap back to the + * initial status after each sequence. + * + *

Test Steps

+ * - [8.1.1] Testing initial conditions, the heap must not be + * fragmented and one free block present. + * - [8.1.2] Trying to allocate an block bigger than available space, + * an error is expected. + * - [8.1.3] Single block allocation using chHeapAlloc() then the block + * is freed using chHeapFree(), must not fail. + * - [8.1.4] Using chHeapStatus() to assess the heap state. There must + * be at least one free block of sufficient size. + * - [8.1.5] Allocating then freeing in the same order. + * - [8.1.6] Allocating then freeing in reverse order. + * - [8.1.7] Small fragments handling. Checking the behavior when + * allocating blocks with size not multiple of alignment unit. + * - [8.1.8] Skipping a fragment, the first fragment in the list is too + * small so the allocator must pick the second one. + * - [8.1.9] Allocating the whole available space. + * - [8.1.10] Testing final conditions. The heap geometry must be the + * same than the one registered at beginning. + * . + */ + +static void test_008_001_setup(void) { + chHeapObjectInit(&test_heap, myheap, sizeof(myheap)); +} + +static void test_008_001_execute(void) { + void *p1, *p2, *p3; + size_t n, sz; + + /* [8.1.1] Testing initial conditions, the heap must not be + fragmented and one free block present.*/ + test_set_step(1); + { + test_assert(chHeapStatus(&test_heap, &sz, NULL) == 1, "heap fragmented"); + } + + /* [8.1.2] Trying to allocate an block bigger than available space, + an error is expected.*/ + test_set_step(2); + { + p1 = chHeapAlloc(&test_heap, HEAP_SIZE * 2); + test_assert(p1 == NULL, "allocation not failed"); + } + + /* [8.1.3] Single block allocation using chHeapAlloc() then the block + is freed using chHeapFree(), must not fail.*/ + test_set_step(3); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* [8.1.4] Using chHeapStatus() to assess the heap state. There must + be at least one free block of sufficient size.*/ + test_set_step(4); + { + size_t total_size, largest_size; + + n = chHeapStatus(&test_heap, &total_size, &largest_size); + test_assert(n == 1, "missing free block"); + test_assert(total_size >= ALLOC_SIZE, "unexpected heap state"); + test_assert(total_size == largest_size, "unexpected heap state"); + } + + /* [8.1.5] Allocating then freeing in the same order.*/ + test_set_step(5); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); /* Does not merge.*/ + chHeapFree(p2); /* Merges backward.*/ + chHeapFree(p3); /* Merges both sides.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [8.1.6] Allocating then freeing in reverse order.*/ + test_set_step(6); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p3 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p3); /* Merges forward.*/ + chHeapFree(p2); /* Merges forward.*/ + chHeapFree(p1); /* Merges forward.*/ + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [8.1.7] Small fragments handling. Checking the behavior when + allocating blocks with size not multiple of alignment unit.*/ + test_set_step(7); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE + 1); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + /* Note, the first situation happens when the alignment size is smaller + than the header size, the second in the other cases.*/ + test_assert((chHeapStatus(&test_heap, &n, NULL) == 1) || + (chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented"); + chHeapFree(p2); + chHeapFree(p1); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [8.1.8] Skipping a fragment, the first fragment in the list is too + small so the allocator must pick the second one.*/ + test_set_step(8); + { + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + p2 = chHeapAlloc(&test_heap, ALLOC_SIZE); + chHeapFree(p1); + test_assert( chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state"); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE * 2); /* Skips first fragment.*/ + chHeapFree(p1); + chHeapFree(p2); + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + } + + /* [8.1.9] Allocating the whole available space.*/ + test_set_step(9); + { + (void)chHeapStatus(&test_heap, &n, NULL); + p1 = chHeapAlloc(&test_heap, n); + test_assert(p1 != NULL, "allocation failed"); + test_assert(chHeapStatus(&test_heap, NULL, NULL) == 0, "not empty"); + chHeapFree(p1); + } + + /* [8.1.10] Testing final conditions. The heap geometry must be the + same than the one registered at beginning.*/ + test_set_step(10); + { + test_assert(chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented"); + test_assert(n == sz, "size changed"); + } +} + +static const testcase_t test_008_001 = { + "Allocation and fragmentation", + test_008_001_setup, + NULL, + test_008_001_execute +}; + +/** + * @page test_008_002 [8.2] Default Heap + * + *

Description

+ * The default heap is pre-allocated in the system. We test base + * functionality. + * + *

Test Steps

+ * - [8.2.1] Single block allocation using chHeapAlloc() then the block + * is freed using chHeapFree(), must not fail. + * - [8.2.2] Testing allocation failure. + * . + */ + +static void test_008_002_execute(void) { + void *p1; + size_t total_size, largest_size; + + /* [8.2.1] Single block allocation using chHeapAlloc() then the block + is freed using chHeapFree(), must not fail.*/ + test_set_step(1); + { + (void)chHeapStatus(NULL, &total_size, &largest_size); + p1 = chHeapAlloc(&test_heap, ALLOC_SIZE); + test_assert(p1 != NULL, "allocation failed"); + chHeapFree(p1); + } + + /* [8.2.2] Testing allocation failure.*/ + test_set_step(2); + { + p1 = chHeapAlloc(NULL, (size_t)-256); + test_assert(p1 == NULL, "allocation not failed"); + } +} + +static const testcase_t test_008_002 = { + "Default Heap", + NULL, + NULL, + test_008_002_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Memory Heaps. + */ +const testcase_t * const test_sequence_008[] = { + &test_008_001, + &test_008_002, + NULL +}; + +#endif /* CH_CFG_USE_HEAP */ diff --git a/test/rt/source/test/test_sequence_008.h b/test/rt/source/test/test_sequence_008.h new file mode 100644 index 000000000..4f0a07ce4 --- /dev/null +++ b/test/rt/source/test/test_sequence_008.h @@ -0,0 +1,17 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + 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. +*/ + +extern const testcase_t * const test_sequence_008[]; -- cgit v1.2.3