timerTest: redo to avoid time related false positives

This commit is contained in:
Michael Davidsaver
2018-03-28 15:40:48 -07:00
parent b4cd026fe5
commit fe413af177

View File

@@ -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();
}