Merge pull request #4682 from bulislaw/sem_tests

Test: RTOS: Semaphore: Rework tests
pull/4792/head
Jimmy Brisson 2017-07-17 11:06:48 -05:00 committed by GitHub
commit 160940b30e
2 changed files with 180 additions and 9 deletions

View File

@ -1,14 +1,19 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "rtos.h"
using namespace utest::v1;
#if defined(MBED_RTOS_SINGLE_THREAD)
#error [NOT_SUPPORTED] test not supported
#endif
#define THREAD_DELAY 75
#define THREAD_DELAY 30
#define SEMAPHORE_SLOTS 2
#define SEM_CHANGES 100
#define SHORT_WAIT 5
#define THREAD_STACK_SIZE 512
@ -18,7 +23,8 @@ volatile int change_counter = 0;
volatile int sem_counter = 0;
volatile bool sem_defect = false;
void test_thread(int const *delay) {
void test_thread(int const *delay)
{
const int thread_delay = *delay;
while (true) {
two_slots.wait();
@ -34,9 +40,14 @@ void test_thread(int const *delay) {
}
}
int main (void) {
GREENTEA_SETUP(20, "default_auto");
/* Test multiple threads
Given 3 threads started with different delays and a semaphore with 2 tokens
when each thread runs it tries to acquire a token
then no more than two threads should be able to access protected region
*/
void test_multi()
{
const int t1_delay = THREAD_DELAY * 1;
const int t2_delay = THREAD_DELAY * 2;
const int t3_delay = THREAD_DELAY * 3;
@ -57,7 +68,164 @@ int main (void) {
break;
}
}
GREENTEA_TESTSUITE_RESULT(!sem_defect);
return 0;
}
struct thread_data {
Semaphore *sem;
uint32_t data;
};
void single_thread(struct thread_data *data)
{
int32_t cnt = data->sem->wait();
TEST_ASSERT_EQUAL(1, cnt);
data->data++;
}
/** Test single thread
Given a two threads A & B and a semaphore (with count of 0) and a counter (equals to 0)
when thread B calls @a wait
then thread B waits for a token to become available
then the counter is equal to 0
when thread A calls @a release on the semaphore
then thread B acquires a token and increments the counter
then the counter equals to 1
*/
void test_single_thread()
{
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
Semaphore sem(0);
struct thread_data data;
osStatus res;
data.sem = &sem;
data.data = 0;
res = t.start(callback(single_thread, &data));
TEST_ASSERT_EQUAL(osOK, res);
Thread::wait(SHORT_WAIT);
TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
TEST_ASSERT_EQUAL(0, data.data);
res = sem.release();
TEST_ASSERT_EQUAL(osOK, res);
Thread::wait(SHORT_WAIT);
TEST_ASSERT_EQUAL(1, data.data);
t.join();
}
void timeout_thread(Semaphore *sem)
{
int32_t cnt = sem->wait(30);
TEST_ASSERT_EQUAL(0, cnt);
}
/** Test timeout
Given thread and a semaphore with no tokens available
when thread calls @a wait on the semaphore with timeout of 10ms
then the thread waits for 10ms and timeouts after
*/
void test_timeout()
{
Thread t(osPriorityNormal, THREAD_STACK_SIZE);
Semaphore sem(0);
osStatus res;
uint32_t start = us_ticker_read();
res = t.start(callback(timeout_thread, &sem));
TEST_ASSERT_EQUAL(osOK, res);
Thread::wait(SHORT_WAIT);
TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
t.join();
TEST_ASSERT_UINT32_WITHIN(5000, 30000, us_ticker_read() - start);
}
/** Test no timeouts
Test 1 token no timeout
Given thread and a semaphore with one token available
when thread calls @a wait on the semaphore with timeout of 0ms
then the thread acquires the token immediately
Test 0 tokens no timeout
Given thread and a semaphore with no tokens available
when thread calls @a wait on the semaphore with timeout of 0ms
then the thread returns immediately without acquiring a token
*/
template<int T>
void test_no_timeout()
{
Semaphore sem(T);
uint32_t start = us_ticker_read();
int32_t cnt = sem.wait(0);
TEST_ASSERT_EQUAL(T, cnt);
TEST_ASSERT_UINT32_WITHIN(5000, 0, us_ticker_read() - start);
}
/** Test multiple tokens wait
Given a thread and a semaphore initialized with 5 tokens
when thread calls @a wait 6 times on the semaphore
then the token counts goes to zero
*/
void test_multiple_tokens_wait()
{
Semaphore sem(5);
for(int i = 5; i >= 0; i--) {
int32_t cnt = sem.wait(0);
TEST_ASSERT_EQUAL(i, cnt);
}
}
/** Test multiple tokens release
Given a thread and a semaphore initialized with zero tokens and max of 5
when thread calls @a release 6 times on the semaphore
then the token count should be equal to 5 and last release call should fail
*/
void test_multiple_tokens_release()
{
Semaphore sem(0, 5);
for(int i = 5; i > 0; i--) {
osStatus stat = sem.release();
TEST_ASSERT_EQUAL(osOK, stat);
}
osStatus stat = sem.release();
TEST_ASSERT_EQUAL(osErrorResource, stat);
}
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Test single thread", test_single_thread),
Case("Test timeout", test_timeout),
Case("Test 1 token no timeout", test_no_timeout<1>),
Case("Test 0 tokens no timeout", test_no_timeout<0>),
Case("Test multiple tokens wait", test_multiple_tokens_wait),
Case("Test multiple tokens release", test_multiple_tokens_release),
Case("Test multiple threads", test_multi)
};
Specification specification(test_setup, cases);
int main()
{
return !Harness::run(specification);
}

View File

@ -53,12 +53,15 @@ public:
/** Wait until a Semaphore resource becomes available.
@param millisec timeout value or 0 in case of no time-out. (default: osWaitForever).
@return number of available tokens, or -1 in case of incorrect parameters
@return number of available tokens, before taking one; or -1 in case of incorrect parameters
*/
int32_t wait(uint32_t millisec=osWaitForever);
/** Release a Semaphore resource that was obtain with Semaphore::wait.
@return status code that indicates the execution status of the function.
@return status code that indicates the execution status of the function:
@a osOK the token has been correctly released.
@a osErrorResource the maximum token count has been reached.
@a osErrorParameter internal error.
*/
osStatus release(void);