Use scheduler interface in harness.

The default implementation uses MINAR as the underlying scheduler,
however, by declaring `config.utest.use_custom_scheduler = true`
MINAR is not included by default.
Niklas Hauser 2016-03-21 13:58:01 +00:00 committed by Martin Kojtal
parent 589dd7b509
commit 95462c1d7c
2 changed files with 65 additions and 20 deletions

View File

@ -17,9 +17,29 @@
*/
#include "utest/harness.h"
#include "minar/minar.h"
#include "core-util/CriticalSectionLock.h"
#include <stdlib.h>
#include "core-util/CriticalSectionLock.h"
#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER
#include "minar/minar.h"
static void *utest_minar_post(const utest_v1_harness_callback_t callback, const uint32_t delay_ms)
{
void *handle = minar::Scheduler::postCallback(callback).delay(minar::milliseconds(delay_ms)).getHandle();
return handle;
}
static int32_t utest_minar_cancel(void *handle)
{
int32_t ret = minar::Scheduler::cancelCallback(handle);
return ret;
}
static const utest_v1_scheduler_t utest_minar_scheduler =
{
utest_minar_post,
utest_minar_cancel
};
#endif
using namespace utest::v1;
@ -37,7 +57,7 @@ namespace
control_t case_control = control_t(REPEAT_SETUP_TEARDOWN);
size_t case_repeat_count = 1;
minar::callback_handle_t case_timeout_handle = NULL;
void *case_timeout_handle = NULL;
size_t case_validation_count = 0;
bool case_timeout_occurred = false;
@ -49,23 +69,41 @@ namespace
handlers_t handlers = defaults;
location_t location = LOCATION_UNKNOWN;
#ifndef YOTTA_CFG_UTEST_USE_CUSTOM_SCHEDULER
utest_v1_scheduler_t scheduler = utest_minar_scheduler;
#else
utest_v1_scheduler_t scheduler = {NULL, NULL};
#endif
}
static void die() {
while(1) ;
}
bool Harness::run(const Specification& specification)
bool Harness::set_scheduler(const utest_v1_scheduler_t scheduler)
{
return run(specification, 0);
if (!scheduler.post || !scheduler.cancel)
return false;
::scheduler = scheduler;
return true;
}
bool Harness::run(const Specification& specification, std::size_t)
{
return run(specification);
}
bool Harness::run(const Specification& specification)
{
// check if a specification is currently running
if (is_busy())
return false;
if (!scheduler.post || !scheduler.cancel)
return false;
test_cases = specification.cases;
test_length = specification.length;
defaults = specification.defaults;
@ -102,7 +140,7 @@ bool Harness::run(const Specification& specification, std::size_t)
case_current = &test_cases[setup_status];
minar::Scheduler::postCallback(run_next_case);
scheduler.post(run_next_case, 0);
return true;
}
@ -122,7 +160,7 @@ void Harness::raise_failure(const failure_reason_t reason)
if ((fail_status == STATUS_ABORT) && case_timeout_handle)
{
minar::Scheduler::cancelCallback(case_timeout_handle);
scheduler.cancel(case_timeout_handle);
case_timeout_handle = NULL;
}
}
@ -175,7 +213,7 @@ void Harness::schedule_next_case()
case_repeat_count = 1;
test_index_of_case++;
}
minar::Scheduler::postCallback(run_next_case);
scheduler.post(run_next_case, 0);
}
void Harness::handle_timeout()
@ -190,7 +228,7 @@ void Harness::handle_timeout()
}
if (case_timeout_occurred) {
raise_failure(failure_reason_t(REASON_TIMEOUT | ((case_control.repeat & REPEAT_ON_TIMEOUT) ? REASON_IGNORE : 0)));
minar::Scheduler::postCallback(schedule_next_case);
scheduler.post(schedule_next_case, 0);
}
}
@ -201,12 +239,12 @@ void Harness::validate_callback(const control_t control)
if (case_timeout_handle != NULL || case_control.timeout == TIMEOUT_FOREVER)
{
minar::Scheduler::cancelCallback(case_timeout_handle);
scheduler.cancel(case_timeout_handle);
case_timeout_handle = NULL;
control_t merged_control = case_control + control;
case_control.repeat = repeat_t(merged_control.repeat & ~REPEAT_ON_TIMEOUT);
case_control.timeout = TIMEOUT_NONE;
minar::Scheduler::postCallback(schedule_next_case);
scheduler.post(schedule_next_case, 0);
}
}
@ -272,13 +310,11 @@ void Harness::run_next_case()
if (case_control.timeout < TIMEOUT_UNDECLR && case_validation_count == 0) {
// if await validation _with_ timeout
if (case_control.timeout < TIMEOUT_FOREVER) {
case_timeout_handle = minar::Scheduler::postCallback(handle_timeout)
.delay(minar::milliseconds(case_control.timeout))
.getHandle();
case_timeout_handle = scheduler.post(handle_timeout, case_control.timeout);
}
}
else {
minar::Scheduler::postCallback(schedule_next_case);
scheduler.post(schedule_next_case, 0);
}
}
}

View File

@ -27,6 +27,7 @@
#include "case.h"
#include "default_handlers.h"
#include "specification.h"
#include "scheduler.h"
namespace utest {
@ -38,7 +39,12 @@ namespace v1 {
* The harness executes the test specification in an asynchronous fashion, therefore
* `run()` returns immediately.
*
* @note: In case of an test abort, the harness will busy-wait and never finish.
* By default, this harness uses the MINAR scheduler for asynchronous callbacks.
* If you wamt to provide your own custom scheduler, set `config.utest.use_custom_scheduler` to `true`
* inside your yotta config and set a custom scheduler implementation using the `set_scheduler()` function.
* You must set the scheduler before running a specification.
*
* @note In case of an test abort, the harness will busy-wait and never finish.
*/
class Harness
{
@ -48,15 +54,18 @@ namespace v1 {
/// @retval `false` if another specification is currently running
static bool run(const Specification& specification);
/// Runs a test specification starting at the specified case index
/// @warning if the start index is out of bounds, the call has no effect!
/// @retval `true` if the specification can be run
/// @retval `false` if another specification is currently running, or the start index was out of bounds
/// @cond
__deprecated_message("Start case selection is done by returning the index from the test setup handler!")
static bool run(const Specification& specification, size_t start_case);
/// @endcond
/// @returns `true` if a test specification is being executed, `false` otherwise
static bool is_busy();
/// Sets the scheduler to be used.
/// @return `true` if scheduler is properly specified (all functions non-null).
static bool set_scheduler(utest_v1_scheduler_t scheduler);
/** Call this function in the asynchronous callback that you have been waiting for.
*
* You can only validate a callback once, calling this function when no callback is expected