timerTest: redo to avoid time related false positives
This commit is contained in:
@@ -15,9 +15,11 @@
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
#include <epicsGuard.h>
|
||||
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/event.h>
|
||||
@@ -27,175 +29,214 @@
|
||||
using namespace epics::pvData;
|
||||
using std::string;
|
||||
|
||||
static TimeStamp currentTimeStamp;
|
||||
static double oneDelay = 4.0;
|
||||
static double twoDelay = 2.0;
|
||||
static double threeDelay = 1.0;
|
||||
static int ntimes = 3;
|
||||
static const double delays[3] = {1.0, 2.0, 4.0};
|
||||
static const unsigned ntimes = 3;
|
||||
|
||||
class MyCallback;
|
||||
typedef std::tr1::shared_ptr<MyCallback> MyCallbackPtr;
|
||||
namespace {
|
||||
|
||||
class MyCallback : public TimerCallback {
|
||||
public:
|
||||
POINTER_DEFINITIONS(MyCallback);
|
||||
MyCallback(string name,EventPtr const & wait)
|
||||
: name(name),
|
||||
wait(wait)
|
||||
{
|
||||
}
|
||||
~MyCallback()
|
||||
{
|
||||
}
|
||||
struct Marker : public TimerCallback
|
||||
{
|
||||
POINTER_DEFINITIONS(Marker);
|
||||
|
||||
Event wait, hold;
|
||||
virtual ~Marker() {}
|
||||
virtual void callback()
|
||||
{
|
||||
timeStamp.getCurrent();
|
||||
wait->signal();
|
||||
wait.signal();
|
||||
hold.wait();
|
||||
}
|
||||
virtual void timerStopped() {}
|
||||
};
|
||||
|
||||
struct MyCallback : public TimerCallback {
|
||||
POINTER_DEFINITIONS(MyCallback);
|
||||
|
||||
MyCallback(const string& name)
|
||||
:name(name)
|
||||
,counter(0)
|
||||
,first_gbl(0)
|
||||
{}
|
||||
virtual ~MyCallback() {}
|
||||
virtual void callback()
|
||||
{
|
||||
testDiag("expire %s",name.c_str());
|
||||
{
|
||||
epicsGuard<Mutex> G(gbl_mutex);
|
||||
counter++;
|
||||
if(first_gbl==0) {
|
||||
first_gbl = ++gbl_counter;
|
||||
}
|
||||
}
|
||||
wait.signal();
|
||||
}
|
||||
virtual void timerStopped()
|
||||
{
|
||||
printf("timerStopped %s\n",name.c_str());
|
||||
testDiag("timerStopped %s",name.c_str());
|
||||
}
|
||||
TimeStamp &getTimeStamp() { return timeStamp;}
|
||||
private:
|
||||
string name;
|
||||
EventPtr wait;
|
||||
TimeStamp timeStamp;
|
||||
void clear() {
|
||||
epicsGuard<Mutex> G(gbl_mutex);
|
||||
counter = gbl_counter = 0;
|
||||
}
|
||||
|
||||
const string name;
|
||||
unsigned counter, first_gbl;
|
||||
Event wait;
|
||||
|
||||
static unsigned gbl_counter;
|
||||
static Mutex gbl_mutex;
|
||||
};
|
||||
|
||||
static void testBasic()
|
||||
unsigned MyCallback::gbl_counter;
|
||||
Mutex MyCallback::gbl_mutex;
|
||||
|
||||
typedef std::tr1::shared_ptr<MyCallback> MyCallbackPtr;
|
||||
|
||||
}// namespace
|
||||
|
||||
static void testBasic(unsigned oneOrd, unsigned twoOrd, unsigned threeOrd)
|
||||
{
|
||||
testDiag("\n\ntestBasic oneDelay %lf twoDelay %lf threeDaley %lf\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testDiag("testBasic oneOrd %u twoOrd %u threeOrd %u",
|
||||
oneOrd,twoOrd,threeOrd);
|
||||
|
||||
string one("one");
|
||||
string two("two");
|
||||
string three("three");
|
||||
EventPtr eventOne(new Event());
|
||||
EventPtr eventTwo(new Event());
|
||||
EventPtr eventThree(new Event());
|
||||
TimerPtr timer(new Timer(string("timer"),middlePriority));
|
||||
MyCallbackPtr callbackOne(new MyCallback(one,eventOne));
|
||||
MyCallbackPtr callbackTwo(new MyCallback(two,eventTwo));
|
||||
MyCallbackPtr callbackThree(new MyCallback(three,eventThree));
|
||||
for(int n=0; n<ntimes; n++) {
|
||||
currentTimeStamp.getCurrent();
|
||||
testOk1(!timer->isScheduled(callbackOne));
|
||||
testOk1(!timer->isScheduled(callbackTwo));
|
||||
testOk1(!timer->isScheduled(callbackThree));
|
||||
timer->scheduleAfterDelay(callbackOne,oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo,twoDelay);
|
||||
timer->scheduleAfterDelay(callbackThree,threeDelay);
|
||||
if(oneDelay>.1) testOk1(timer->isScheduled(callbackOne));
|
||||
if(twoDelay>.1) testOk1(timer->isScheduled(callbackTwo));
|
||||
if(threeDelay>.1) testOk1(timer->isScheduled(callbackThree));
|
||||
Timer timer("timer" ,middlePriority);
|
||||
|
||||
eventOne->wait();
|
||||
eventTwo->wait();
|
||||
eventThree->wait();
|
||||
double diff;
|
||||
double delta;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - oneDelay;
|
||||
Marker::shared_pointer marker(new Marker);
|
||||
MyCallbackPtr callbackOne(new MyCallback("one"));
|
||||
MyCallbackPtr callbackTwo(new MyCallback("two"));
|
||||
MyCallbackPtr callbackThree(new MyCallback("three"));
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackTwo->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - twoDelay;
|
||||
for(unsigned n=0; n<ntimes; n++) {
|
||||
testDiag("iteration %u", n);
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackThree->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - threeDelay;
|
||||
testOk1(!timer.isScheduled(marker));
|
||||
timer.scheduleAfterDelay(marker, 0.01);
|
||||
marker->wait.wait();
|
||||
// timer worker is blocked
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
callbackOne->clear();
|
||||
callbackTwo->clear();
|
||||
callbackThree->clear();
|
||||
|
||||
timer.scheduleAfterDelay(callbackOne,delays[oneOrd]);
|
||||
timer.scheduleAfterDelay(callbackTwo,delays[twoOrd]);
|
||||
timer.scheduleAfterDelay(callbackThree,delays[threeOrd]);
|
||||
|
||||
testOk1(timer.isScheduled(callbackOne));
|
||||
testOk1(timer.isScheduled(callbackTwo));
|
||||
testOk1(timer.isScheduled(callbackThree));
|
||||
|
||||
marker->hold.signal(); // let the worker loose
|
||||
|
||||
callbackOne->wait.wait();
|
||||
callbackTwo->wait.wait();
|
||||
callbackThree->wait.wait();
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
{
|
||||
epicsGuard<Mutex> G(MyCallback::gbl_mutex);
|
||||
testOk(callbackOne->counter==1, "%s counter %u = 1", callbackOne->name.c_str(), callbackOne->counter);
|
||||
testOk(callbackTwo->counter==1, "%s counter %u = 1", callbackTwo->name.c_str(), callbackTwo->counter);
|
||||
testOk(callbackThree->counter==1, "%s counter %u = 1", callbackThree->name.c_str(), callbackThree->counter);
|
||||
|
||||
testOk(callbackOne->first_gbl==oneOrd+1, "%s first_gbl %u = %u", callbackOne->name.c_str(), callbackOne->first_gbl, oneOrd+1);
|
||||
testOk(callbackTwo->first_gbl==twoOrd+1, "%s first_gbl %u = %u", callbackTwo->name.c_str(), callbackTwo->first_gbl, twoOrd+1);
|
||||
testOk(callbackThree->first_gbl==threeOrd+1, "%s first_gbl %u = %u", callbackThree->name.c_str(), callbackThree->first_gbl, threeOrd+1);
|
||||
}
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
}
|
||||
printf("testBasic PASSED\n");
|
||||
}
|
||||
|
||||
static void testCancel()
|
||||
static void testCancel(unsigned oneOrd, unsigned twoOrd, unsigned threeOrd,
|
||||
unsigned oneReal, unsigned threeReal)
|
||||
{
|
||||
testDiag("\n\ntestCancel oneDelay %lf twoDelay %lf threeDaley %lf\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testDiag("testCancel oneOrd %u twoOrd %u threeOrd %u",
|
||||
oneOrd,twoOrd,threeOrd);
|
||||
|
||||
string one("one");
|
||||
string two("two");
|
||||
string three("three");
|
||||
EventPtr eventOne(new Event());
|
||||
EventPtr eventTwo(new Event());
|
||||
EventPtr eventThree(new Event());
|
||||
TimerPtr timer(new Timer(string("timer"),middlePriority));
|
||||
MyCallbackPtr callbackOne(new MyCallback(one,eventOne));
|
||||
MyCallbackPtr callbackTwo(new MyCallback(two,eventTwo));
|
||||
MyCallbackPtr callbackThree(new MyCallback(three,eventThree));
|
||||
for(int n=0; n<ntimes; n++) {
|
||||
currentTimeStamp.getCurrent();
|
||||
testOk1(!timer->isScheduled(callbackOne));
|
||||
testOk1(!timer->isScheduled(callbackTwo));
|
||||
testOk1(!timer->isScheduled(callbackThree));
|
||||
timer->scheduleAfterDelay(callbackOne,oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo,twoDelay);
|
||||
timer->scheduleAfterDelay(callbackThree,threeDelay);
|
||||
timer->cancel(callbackTwo);
|
||||
if(oneDelay>.1) testOk1(timer->isScheduled(callbackOne));
|
||||
testOk1(!timer->isScheduled(callbackTwo));
|
||||
if(threeDelay>.1) testOk1(timer->isScheduled(callbackThree));
|
||||
Timer timer("timer" ,middlePriority);
|
||||
|
||||
eventOne->wait();
|
||||
eventThree->wait();
|
||||
double diff;
|
||||
double delta;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - oneDelay;
|
||||
Marker::shared_pointer marker(new Marker);
|
||||
MyCallbackPtr callbackOne(new MyCallback("one"));
|
||||
MyCallbackPtr callbackTwo(new MyCallback("two"));
|
||||
MyCallbackPtr callbackThree(new MyCallback("three"));
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackThree->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - threeDelay;
|
||||
for(unsigned n=0; n<ntimes; n++) {
|
||||
testDiag("iteration %u", n);
|
||||
|
||||
testOk1(!timer.isScheduled(marker));
|
||||
timer.scheduleAfterDelay(marker, 0.01);
|
||||
marker->wait.wait();
|
||||
// timer worker is blocked
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
callbackOne->clear();
|
||||
callbackTwo->clear();
|
||||
callbackThree->clear();
|
||||
|
||||
timer.scheduleAfterDelay(callbackOne,delays[oneOrd]);
|
||||
timer.scheduleAfterDelay(callbackTwo,delays[twoOrd]);
|
||||
timer.scheduleAfterDelay(callbackThree,delays[threeOrd]);
|
||||
|
||||
testOk1(timer.isScheduled(callbackOne));
|
||||
testOk1(timer.isScheduled(callbackTwo));
|
||||
testOk1(timer.isScheduled(callbackThree));
|
||||
|
||||
timer.cancel(callbackTwo);
|
||||
|
||||
testOk1(timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(timer.isScheduled(callbackThree));
|
||||
|
||||
marker->hold.signal(); // let the worker loose
|
||||
|
||||
callbackOne->wait.wait();
|
||||
callbackThree->wait.wait();
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
{
|
||||
epicsGuard<Mutex> G(MyCallback::gbl_mutex);
|
||||
testOk(callbackOne->counter==1, "%s counter %u = 1", callbackOne->name.c_str(), callbackOne->counter);
|
||||
testOk(callbackTwo->counter==0, "%s counter %u = 0", callbackTwo->name.c_str(), callbackTwo->counter);
|
||||
testOk(callbackThree->counter==1, "%s counter %u = 1", callbackThree->name.c_str(), callbackThree->counter);
|
||||
|
||||
testOk(callbackOne->first_gbl==oneReal+1, "%s first_gbl %u = %u", callbackOne->name.c_str(), callbackOne->first_gbl, oneOrd+1);
|
||||
testOk(callbackTwo->first_gbl==0, "%s first_gbl %u = %u", callbackTwo->name.c_str(), callbackTwo->first_gbl, 0);
|
||||
testOk(callbackThree->first_gbl==threeReal+1, "%s first_gbl %u = %u", callbackThree->name.c_str(), callbackThree->first_gbl, threeOrd+1);
|
||||
}
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
}
|
||||
printf("testCancel PASSED\n");
|
||||
}
|
||||
|
||||
MAIN(testTimer)
|
||||
{
|
||||
testPlan(171);
|
||||
testDiag("Tests timer");
|
||||
oneDelay = .4;
|
||||
twoDelay = .2;
|
||||
threeDelay = .1;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
oneDelay = .1;
|
||||
twoDelay = .2;
|
||||
threeDelay = .4;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
oneDelay = .1;
|
||||
twoDelay = .4;
|
||||
threeDelay = .2;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
oneDelay = .0;
|
||||
twoDelay = .0;
|
||||
threeDelay = .0;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
testPlan(315);
|
||||
try {
|
||||
testDiag("Tests timer");
|
||||
|
||||
testBasic(2, 1, 0);
|
||||
testCancel(2, 1, 0, 1, 0);
|
||||
|
||||
testBasic(0, 1, 2);
|
||||
testCancel(0, 1, 2, 0, 1);
|
||||
|
||||
testBasic(0, 2, 1);
|
||||
testCancel(0, 2, 1, 0, 1);
|
||||
|
||||
}catch(std::exception& e) {
|
||||
testFail("Unhandled exception: %s", e.what());
|
||||
}
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user