ember/tests/TestTasks.cpp

323 lines
7.8 KiB
C++
Raw Permalink Normal View History

2010-11-29 20:06:39 +01:00
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/TestResult.h>
#include "framework/tasks/TaskQueue.h"
#include "framework/tasks/ITask.h"
2010-11-29 20:58:00 +01:00
#include "framework/tasks/ITaskExecutionListener.h"
2010-12-12 18:33:06 +01:00
#include "framework/tasks/TaskExecutionContext.h"
2010-11-29 20:58:00 +01:00
#include "framework/Exception.h"
2014-02-19 21:25:35 +01:00
#include <Eris/EventService.h>
2010-12-12 15:46:08 +01:00
#include <wfmath/timestamp.h>
2014-02-19 21:25:35 +01:00
#include <boost/asio.hpp>
#define _GLIBCXX_USE_NANOSLEEP 1
#include <thread>
#include <chrono>
#include <condition_variable>
2010-11-29 20:06:39 +01:00
namespace Ember
{
class CounterTask: public Tasks::ITask
{
public:
int& mCounter;
2010-11-29 20:58:00 +01:00
int mSleep;
CounterTask(int& counter, int sleep = 0) :
mCounter(counter), mSleep(sleep)
2010-11-29 20:06:39 +01:00
{
mCounter += 2;
}
virtual void executeTaskInBackgroundThread(Tasks::TaskExecutionContext& context)
{
2010-11-29 20:58:00 +01:00
if (mSleep) {
std::this_thread::sleep_for(std::chrono::milliseconds(mSleep));
2010-11-29 20:58:00 +01:00
}
2010-11-29 20:06:39 +01:00
mCounter--;
}
/**
* @brief Executes the task in the main thread, after executeTaskInBackgroundThread() has been called.
* Since this will happen in the main thread you shouldn't do any time consuming things here, since it will lock up the rendering.
*/
virtual void executeTaskInMainThread()
{
mCounter--;
}
virtual std::string getName() const {
return "CounterTask";
}
2010-11-29 20:58:00 +01:00
};
2010-12-12 15:46:08 +01:00
struct TimeHolder {
public:
WFMath::TimeStamp time;
};
class TimeTask: public Tasks::ITask
{
public:
TimeHolder& timeHolder;
2010-12-12 18:33:06 +01:00
ITask* subtask;
Tasks::ITaskExecutionListener* listener;
2010-12-12 15:46:08 +01:00
2010-12-12 18:33:06 +01:00
TimeTask(TimeHolder& timeHolder, ITask* subtask = 0, Tasks::ITaskExecutionListener* listener = 0)
: timeHolder(timeHolder), subtask(subtask), listener(listener)
2010-12-12 15:46:08 +01:00
{
}
virtual void executeTaskInBackgroundThread(Tasks::TaskExecutionContext& context)
{
2010-12-12 18:33:06 +01:00
if (subtask) {
//sleep a little so that we get different times on the tasks
std::this_thread::sleep_for(std::chrono::milliseconds(5));
2010-12-12 18:33:06 +01:00
context.executeTask(subtask,listener);
}
//sleep a little so that we get different times on the tasks
std::this_thread::sleep_for(std::chrono::milliseconds(5));
2010-12-12 15:46:08 +01:00
}
virtual void executeTaskInMainThread()
{
2010-12-12 18:33:06 +01:00
//sleep a little so that we get different times on the tasks
std::this_thread::sleep_for(std::chrono::milliseconds(5));
2010-12-12 15:46:08 +01:00
timeHolder.time = WFMath::TimeStamp::now();
}
virtual std::string getName() const {
return "TimeTask";
}
};
2010-11-29 20:58:00 +01:00
class CounterTaskBackgroundException: public CounterTask {
public:
CounterTaskBackgroundException(int& counter) : CounterTask(counter) {
}
2010-11-29 20:06:39 +01:00
2010-11-29 20:58:00 +01:00
virtual void executeTaskInBackgroundThread(Tasks::TaskExecutionContext& context)
{
throw Ember::Exception();
}
};
class SimpleListener : public Tasks::ITaskExecutionListener {
public:
bool started;
bool ended;
bool error;
2010-12-12 15:46:08 +01:00
WFMath::TimeStamp startedTime;
WFMath::TimeStamp endedTime;
WFMath::TimeStamp errorTime;
2010-11-29 20:58:00 +01:00
SimpleListener() : started(false), ended(false), error(false) {
}
virtual void executionStarted()
{
2010-12-12 15:46:08 +01:00
startedTime = WFMath::TimeStamp::now();
2010-11-29 20:58:00 +01:00
started = true;
}
virtual void executionEnded()
{
2010-12-12 15:46:08 +01:00
endedTime = WFMath::TimeStamp::now();
2010-11-29 20:58:00 +01:00
ended = true;
}
virtual void executionError(const Ember::Exception& exception)
{
2010-12-12 15:46:08 +01:00
errorTime = WFMath::TimeStamp::now();
2010-11-29 20:58:00 +01:00
error = true;
}
2010-11-29 20:06:39 +01:00
};
class TaskTestCase: public CppUnit::TestFixture
{
2010-11-29 20:58:00 +01:00
CPPUNIT_TEST_SUITE(TaskTestCase);
CPPUNIT_TEST(testSimpleTaskRun);
CPPUNIT_TEST(testSimpleTaskRunAndPoll);
CPPUNIT_TEST(testSimpleTaskRunTwoExecs);
CPPUNIT_TEST(testSimpleTaskRunTwoTasks);
CPPUNIT_TEST(testSimpleTaskRunTwoTasksTwoExecs);
CPPUNIT_TEST(testListener);
CPPUNIT_TEST(testBackgroundException);
2010-12-12 15:46:08 +01:00
CPPUNIT_TEST(testTaskOrder);
2010-12-12 18:33:06 +01:00
CPPUNIT_TEST(testSubTaskOrder);
2010-11-29 20:58:00 +01:00
2010-11-29 20:06:39 +01:00
CPPUNIT_TEST_SUITE_END();
2014-02-19 21:25:35 +01:00
boost::asio::io_service io_service;
2010-11-29 20:06:39 +01:00
public:
void testSimpleTaskRun()
{
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-11-29 20:06:39 +01:00
taskQueue.enqueueTask(new CounterTask(counter));
}
CPPUNIT_ASSERT(counter == 0);
}
2010-11-29 20:58:00 +01:00
void testSimpleTaskRunAndPoll()
{
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-11-29 20:58:00 +01:00
taskQueue.enqueueTask(new CounterTask(counter));
//200 ms should be enough... This isn't deterministic though.
std::this_thread::sleep_for(std::chrono::milliseconds(200));
2014-02-19 21:25:35 +01:00
es.processAllHandlers();
2010-11-29 20:58:00 +01:00
CPPUNIT_ASSERT(counter == 0);
}
}
2010-11-29 20:06:39 +01:00
void testSimpleTaskRunTwoExecs()
{
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(2, es);
2010-11-29 20:06:39 +01:00
taskQueue.enqueueTask(new CounterTask(counter));
}
CPPUNIT_ASSERT(counter == 0);
}
void testSimpleTaskRunTwoTasks()
{
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-11-29 20:58:00 +01:00
taskQueue.enqueueTask(new CounterTask(counter, 200));
2010-11-29 20:06:39 +01:00
taskQueue.enqueueTask(new CounterTask(counter));
}
CPPUNIT_ASSERT(counter == 0);
}
void testSimpleTaskRunTwoTasksTwoExecs()
{
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(2, es);
2010-11-29 20:58:00 +01:00
taskQueue.enqueueTask(new CounterTask(counter, 200));
2010-11-29 20:06:39 +01:00
taskQueue.enqueueTask(new CounterTask(counter));
}
CPPUNIT_ASSERT(counter == 0);
}
2010-11-29 20:58:00 +01:00
void testListener()
{
SimpleListener listener;
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-11-29 20:58:00 +01:00
taskQueue.enqueueTask(new CounterTask(counter), &listener);
}
CPPUNIT_ASSERT(counter == 0);
CPPUNIT_ASSERT(listener.started);
CPPUNIT_ASSERT(listener.ended);
}
void testBackgroundException()
{
SimpleListener listener;
int counter = 0;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-11-29 20:58:00 +01:00
taskQueue.enqueueTask(new CounterTaskBackgroundException(counter), &listener);
}
CPPUNIT_ASSERT(counter == 1);
CPPUNIT_ASSERT(listener.error);
}
2010-12-12 15:46:08 +01:00
void testTaskOrder()
{
SimpleListener listener1;
SimpleListener listener2;
SimpleListener listener3;
TimeHolder time1;
TimeHolder time2;
TimeHolder time3;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-12-12 15:46:08 +01:00
taskQueue.enqueueTask(new TimeTask(time1), &listener1);
taskQueue.enqueueTask(new TimeTask(time2), &listener2);
taskQueue.enqueueTask(new TimeTask(time3), &listener3);
}
CPPUNIT_ASSERT(listener1.startedTime < listener2.startedTime);
CPPUNIT_ASSERT(listener2.startedTime < listener3.startedTime);
CPPUNIT_ASSERT(listener1.endedTime < listener2.endedTime);
CPPUNIT_ASSERT(listener2.endedTime < listener3.endedTime);
CPPUNIT_ASSERT(time1.time < time2.time);
CPPUNIT_ASSERT(time2.time < time3.time);
}
2010-12-12 18:33:06 +01:00
void testSubTaskOrder()
{
SimpleListener listener1;
SimpleListener listener2;
SimpleListener listener3;
TimeHolder time1;
TimeHolder time2;
TimeHolder time3;
{
2014-02-19 21:25:35 +01:00
Eris::EventService es(io_service);
Tasks::TaskQueue taskQueue(1, es);
2010-12-12 18:33:06 +01:00
taskQueue.enqueueTask(new TimeTask(time1, new TimeTask(time2), &listener2), &listener1);
taskQueue.enqueueTask(new TimeTask(time3), &listener3);
}
//task 1 should start before task 2
CPPUNIT_ASSERT(listener1.startedTime < listener2.startedTime);
CPPUNIT_ASSERT(listener2.startedTime < listener3.startedTime);
//However, task 2 should end before task 1
CPPUNIT_ASSERT(listener2.endedTime < listener1.endedTime);
CPPUNIT_ASSERT(listener1.endedTime < listener3.endedTime);
//And task 2 should be run in the main thread before task 1
CPPUNIT_ASSERT(time2.time < time1.time);
CPPUNIT_ASSERT(time1.time < time3.time);
}
2010-11-29 20:06:39 +01:00
};
}
CPPUNIT_TEST_SUITE_REGISTRATION( Ember::TaskTestCase);
int main(int argc, char **argv)
{
CppUnit::TextUi::TestRunner runner;
CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
// Shows a message as each test starts
CppUnit::BriefTestProgressListener listener;
runner.eventManager().addListener(&listener);
bool wasSuccessful = runner.run("", false);
return !wasSuccessful;
}