823 lines
25 KiB
C++
823 lines
25 KiB
C++
/* testCaProvider.cpp */
|
|
/*
|
|
* Copyright information and license terms for this software can be
|
|
* found in the file LICENSE that is included with the distribution
|
|
*/
|
|
/* Author: Marty Kraimer Date: 2018.05 */
|
|
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <cstdio>
|
|
|
|
#include <epicsUnitTest.h>
|
|
#include <testMain.h>
|
|
#include <epicsVersion.h>
|
|
#include <envDefs.h>
|
|
|
|
#ifdef EPICS_VERSION_INT
|
|
#if EPICS_VERSION_INT >= VERSION_INT(3,16,2,0)
|
|
#define USE_DBUNITTEST
|
|
// USE_TYPED_RSET prevents deprecation warnings
|
|
#define USE_TYPED_RSET
|
|
#define EXIT_TESTS 0
|
|
#include <dbAccess.h>
|
|
#include <errlog.h>
|
|
#include <dbUnitTest.h>
|
|
|
|
extern "C" int testIoc_registerRecordDeviceDriver(struct dbBase *pbase);
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef EXIT_TESTS
|
|
#define EXIT_TESTS 1
|
|
#endif
|
|
|
|
#include <pv/thread.h>
|
|
#include <pv/pvAccess.h>
|
|
#include <pv/convert.h>
|
|
#include <pv/caProvider.h>
|
|
#include <pv/requester.h>
|
|
#include <pv/status.h>
|
|
#include <pv/event.h>
|
|
#include <pv/lock.h>
|
|
#include <pv/pvIntrospect.h>
|
|
#include <pv/pvData.h>
|
|
|
|
// DEBUG must be 0 to run under the automated test harness
|
|
#define DEBUG 0
|
|
|
|
// These need to be longer than you might expect for Jenkins
|
|
#define CONNECTION_TIMEOUT 10.0
|
|
#define OPERATION_TIMEOUT 10.0
|
|
|
|
using namespace epics::pvData;
|
|
using namespace epics::pvAccess;
|
|
using namespace epics::pvAccess::ca;
|
|
using namespace std;
|
|
|
|
class TestChannel;
|
|
typedef std::tr1::shared_ptr<TestChannel> TestChannelPtr;
|
|
|
|
class TestChannel:
|
|
public ChannelRequester,
|
|
public std::tr1::enable_shared_from_this<TestChannel>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(TestChannel);
|
|
string getRequesterName();
|
|
void message(
|
|
string const & message,
|
|
MessageType messageType);
|
|
virtual void channelCreated(const Status& status, Channel::shared_pointer const & channel);
|
|
virtual void channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState);
|
|
string getChannelName();
|
|
Channel::shared_pointer getChannel();
|
|
static TestChannelPtr create(string const & channelName);
|
|
void connect();
|
|
void waitConnect(double timeout);
|
|
private:
|
|
TestChannel(string const & channelName);
|
|
string channelName;
|
|
Event waitForConnect;
|
|
Channel::shared_pointer channel;
|
|
};
|
|
|
|
string TestChannel::getChannelName() { return channelName;}
|
|
|
|
Channel::shared_pointer TestChannel::getChannel() { return channel;}
|
|
|
|
TestChannelPtr TestChannel::create(string const & channelName)
|
|
{
|
|
TestChannelPtr testChannel(new TestChannel(channelName));
|
|
testChannel->connect();
|
|
return testChannel;
|
|
}
|
|
|
|
TestChannel::TestChannel(string const & channelName)
|
|
: channelName(channelName)
|
|
{
|
|
}
|
|
|
|
string TestChannel::getRequesterName() { return "testChannel";}
|
|
void TestChannel::message(string const & message,MessageType messageType) {};
|
|
|
|
void TestChannel::channelCreated(const Status& status, Channel::shared_pointer const & channel)
|
|
{
|
|
if(channel->isConnected()) waitForConnect.signal();
|
|
}
|
|
|
|
void TestChannel::channelStateChange(Channel::shared_pointer const & channel, Channel::ConnectionState connectionState)
|
|
{
|
|
if(connectionState==Channel::CONNECTED) waitForConnect.signal();
|
|
}
|
|
|
|
void TestChannel::connect()
|
|
{
|
|
ChannelProviderRegistry::shared_pointer reg(ChannelProviderRegistry::clients());
|
|
ChannelProvider::shared_pointer channelProvider(reg->getProvider("ca"));
|
|
if(!channelProvider) throw std::runtime_error(channelName + " provider ca not registered");
|
|
channel = channelProvider->createChannel(channelName,shared_from_this(),ChannelProvider::PRIORITY_DEFAULT);
|
|
if(!channel) throw std::runtime_error(channelName + " channelCreate failed ");
|
|
waitConnect(CONNECTION_TIMEOUT);
|
|
}
|
|
|
|
void TestChannel::waitConnect(double timeout)
|
|
{
|
|
if(waitForConnect.wait(timeout)) return;
|
|
throw std::runtime_error(channelName + " TestChannel::waitConnect failed ");
|
|
}
|
|
|
|
class TestChannelGet;
|
|
typedef std::tr1::shared_ptr<TestChannelGet> TestChannelGetPtr;
|
|
|
|
class TestChannelGetRequester;
|
|
typedef std::tr1::shared_ptr<TestChannelGetRequester> TestChannelGetRequesterPtr;
|
|
typedef std::tr1::weak_ptr<TestChannelGetRequester> TestChannelGetRequesterWPtr;
|
|
|
|
class TestChannelGetRequester
|
|
{
|
|
public:
|
|
virtual void getDone(
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet) = 0;
|
|
};
|
|
|
|
class TestChannelGet:
|
|
public ChannelGetRequester,
|
|
public std::tr1::enable_shared_from_this<TestChannelGet>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(TestChannelGet);
|
|
virtual string getRequesterName();
|
|
virtual void message(string const & message, epics::pvData::MessageType messageType) {}
|
|
virtual void channelGetConnect(
|
|
const Status& status,
|
|
ChannelGet::shared_pointer const & channelGet,
|
|
Structure::const_shared_pointer const & structure);
|
|
virtual void getDone(
|
|
const Status& status,
|
|
ChannelGet::shared_pointer const & channelGet,
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet);
|
|
static TestChannelGetPtr create(
|
|
TestChannelGetRequesterPtr const &getRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest);
|
|
void connect();
|
|
void waitConnect(double timeout);
|
|
void get();
|
|
private:
|
|
TestChannelGet(
|
|
TestChannelGetRequesterPtr const &getRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest);
|
|
|
|
TestChannelGetRequesterWPtr getRequester;
|
|
TestChannelPtr testChannel;
|
|
PVStructurePtr pvRequest;
|
|
PVStructurePtr pvStructure;
|
|
Event waitForConnect;
|
|
ChannelGet::shared_pointer channelGet;
|
|
};
|
|
|
|
TestChannelGetPtr TestChannelGet::create(
|
|
TestChannelGetRequesterPtr const &getRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest)
|
|
{
|
|
TestChannelGetPtr testChannelGet(new TestChannelGet(getRequester,testChannel,pvRequest));
|
|
testChannelGet->connect();
|
|
testChannelGet->waitConnect(CONNECTION_TIMEOUT);
|
|
return testChannelGet;
|
|
}
|
|
|
|
TestChannelGet::TestChannelGet(
|
|
TestChannelGetRequesterPtr const &getRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest)
|
|
: getRequester(getRequester),
|
|
testChannel(testChannel),
|
|
pvRequest(pvRequest)
|
|
{
|
|
}
|
|
|
|
string TestChannelGet::getRequesterName() {return "TestChannelGet";}
|
|
|
|
void TestChannelGet::channelGetConnect(
|
|
const Status& status,
|
|
ChannelGet::shared_pointer const & channelGet,
|
|
Structure::const_shared_pointer const & structure)
|
|
{
|
|
waitForConnect.signal();
|
|
}
|
|
|
|
void TestChannelGet::getDone(
|
|
const Status& status,
|
|
ChannelGet::shared_pointer const & channelGet,
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet)
|
|
{
|
|
TestChannelGetRequesterPtr req(getRequester.lock());
|
|
if(!req) return;
|
|
if(status.isOK()) {
|
|
req->getDone(pvStructure,bitSet);
|
|
return;
|
|
}
|
|
string message = string("channel ")
|
|
+ testChannel->getChannelName()
|
|
+ " TestChannelGet::getDone "
|
|
+ status.getMessage();
|
|
throw std::runtime_error(message);
|
|
}
|
|
|
|
void TestChannelGet::connect()
|
|
{
|
|
channelGet = testChannel->getChannel()->createChannelGet(shared_from_this(),pvRequest);
|
|
if(!channelGet) throw std::runtime_error(testChannel->getChannelName() + " channelCreate failed ");
|
|
}
|
|
|
|
void TestChannelGet::waitConnect(double timeout)
|
|
{
|
|
if(waitForConnect.wait(timeout)) return;
|
|
throw std::runtime_error(testChannel->getChannelName() + " TestChannelGet::waitConnect failed ");
|
|
}
|
|
|
|
|
|
void TestChannelGet::get()
|
|
{
|
|
channelGet->get();
|
|
}
|
|
|
|
class TestChannelPut;
|
|
typedef std::tr1::shared_ptr<TestChannelPut> TestChannelPutPtr;
|
|
|
|
class TestChannelPutRequester;
|
|
typedef std::tr1::shared_ptr<TestChannelPutRequester> TestChannelPutRequesterPtr;
|
|
typedef std::tr1::weak_ptr<TestChannelPutRequester> TestChannelPutRequesterWPtr;
|
|
|
|
class TestChannelPutRequester
|
|
{
|
|
public:
|
|
virtual void putDone() = 0;
|
|
};
|
|
|
|
class TestChannelPut:
|
|
public ChannelPutRequester,
|
|
public std::tr1::enable_shared_from_this<TestChannelPut>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(TestChannelPut);
|
|
virtual string getRequesterName();
|
|
virtual void message(string const & message, MessageType messageType) {}
|
|
virtual void channelPutConnect(
|
|
const Status& status,
|
|
ChannelPut::shared_pointer const & channelPut,
|
|
Structure::const_shared_pointer const & structure);
|
|
virtual void putDone(
|
|
const Status& status,
|
|
ChannelPut::shared_pointer const & channelPut);
|
|
virtual void getDone(
|
|
const Status& status,
|
|
ChannelPut::shared_pointer const & channelPut,
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet);
|
|
static TestChannelPutPtr create(
|
|
TestChannelPutRequesterPtr const &putRequester,
|
|
TestChannelPtr const &testChannel);
|
|
void connect();
|
|
void waitConnect(double timeout);
|
|
void put(string const & value);
|
|
private:
|
|
TestChannelPut(
|
|
TestChannelPutRequesterPtr const &putRequester,
|
|
TestChannelPtr const &testChannel);
|
|
|
|
TestChannelPutRequesterWPtr putRequester;
|
|
TestChannelPtr testChannel;
|
|
PVStructurePtr pvStructure;
|
|
BitSetPtr bitSet;
|
|
Event waitForConnect;
|
|
ChannelPut::shared_pointer channelPut;
|
|
};
|
|
|
|
TestChannelPutPtr TestChannelPut::create(
|
|
TestChannelPutRequesterPtr const &putRequester,
|
|
TestChannelPtr const &testChannel)
|
|
{
|
|
TestChannelPutPtr testChannelPut(new TestChannelPut(putRequester,testChannel));
|
|
testChannelPut->connect();
|
|
testChannelPut->waitConnect(CONNECTION_TIMEOUT);
|
|
return testChannelPut;
|
|
}
|
|
|
|
TestChannelPut::TestChannelPut(
|
|
TestChannelPutRequesterPtr const &putRequester,
|
|
TestChannelPtr const &testChannel)
|
|
: putRequester(putRequester),
|
|
testChannel(testChannel)
|
|
{
|
|
}
|
|
|
|
string TestChannelPut::getRequesterName() {return "TestChannelPut";}
|
|
|
|
void TestChannelPut::channelPutConnect(
|
|
const Status& status,
|
|
ChannelPut::shared_pointer const & channelPut,
|
|
Structure::const_shared_pointer const & structure)
|
|
{
|
|
pvStructure = PVDataCreate::getPVDataCreate()->createPVStructure(structure);
|
|
bitSet = BitSetPtr(new BitSet(pvStructure->getNumberFields()));
|
|
waitForConnect.signal();
|
|
}
|
|
|
|
void TestChannelPut::getDone(
|
|
const Status& status,
|
|
ChannelPut::shared_pointer const & channelPut,
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet)
|
|
{
|
|
throw std::runtime_error("TestChannelPut::getDone should not be called");
|
|
}
|
|
|
|
void TestChannelPut::putDone(
|
|
const Status& status,
|
|
ChannelPut::shared_pointer const & channelPut)
|
|
{
|
|
TestChannelPutRequesterPtr req(putRequester.lock());
|
|
if(!req) return;
|
|
if(status.isOK()) {
|
|
req->putDone();
|
|
return;
|
|
}
|
|
string message = string("channel ")
|
|
+ testChannel->getChannelName()
|
|
+ " TestChannelPut::putDone "
|
|
+ status.getMessage();
|
|
throw std::runtime_error(message);
|
|
}
|
|
|
|
void TestChannelPut::connect()
|
|
{
|
|
string request("value");
|
|
PVStructurePtr pvRequest(createRequest(request));
|
|
|
|
channelPut = testChannel->getChannel()->createChannelPut(shared_from_this(),pvRequest);
|
|
if(!channelPut) throw std::runtime_error(testChannel->getChannelName() + " channelCreate failed ");
|
|
}
|
|
|
|
void TestChannelPut::waitConnect(double timeout)
|
|
{
|
|
if(waitForConnect.wait(timeout)) return;
|
|
throw std::runtime_error(testChannel->getChannelName()
|
|
+ " TestChannelPut::waitConnect failed ");
|
|
}
|
|
|
|
|
|
void TestChannelPut::put(string const & value)
|
|
{
|
|
PVFieldPtr pvField(pvStructure->getSubField("value"));
|
|
if(!pvField) throw std::runtime_error(testChannel->getChannelName()
|
|
+ " TestChannelPut::put no value ");
|
|
FieldConstPtr field(pvField->getField());
|
|
Type type(field->getType());
|
|
if(type==scalar) {
|
|
PVScalarPtr pvScalar(std::tr1::static_pointer_cast<PVScalar>(pvField));
|
|
getConvert()->fromString(pvScalar,value);
|
|
bitSet->set(pvField->getFieldOffset());
|
|
channelPut->put(pvStructure,bitSet);
|
|
return;
|
|
}
|
|
if(type==scalarArray) {
|
|
PVScalarArrayPtr pvScalarArray(std::tr1::static_pointer_cast<PVScalarArray>(pvField));
|
|
std::vector<string> values;
|
|
size_t pos = 0;
|
|
size_t n = 1;
|
|
while(true)
|
|
{
|
|
size_t offset = value.find(" ",pos);
|
|
if(offset==string::npos) {
|
|
values.push_back(value.substr(pos));
|
|
break;
|
|
}
|
|
values.push_back(value.substr(pos,offset-pos));
|
|
pos = offset+1;
|
|
n++;
|
|
}
|
|
pvScalarArray->setLength(n);
|
|
getConvert()->fromStringArray(pvScalarArray,0,n,values,0);
|
|
bitSet->set(pvField->getFieldOffset());
|
|
channelPut->put(pvStructure,bitSet);
|
|
return;
|
|
}
|
|
if(type==structure) {
|
|
PVScalarPtr pvScalar(pvStructure->getSubField<PVScalar>("value.index"));
|
|
if(pvScalar) {
|
|
getConvert()->fromString(pvScalar,value);
|
|
bitSet->set(pvScalar->getFieldOffset());
|
|
channelPut->put(pvStructure,bitSet);
|
|
return;
|
|
}
|
|
}
|
|
throw std::runtime_error(testChannel->getChannelName()
|
|
+ " TestChannelPut::put not supported type");
|
|
}
|
|
|
|
class TestChannelMonitor;
|
|
typedef std::tr1::shared_ptr<TestChannelMonitor> TestChannelMonitorPtr;
|
|
|
|
class TestChannelMonitorRequester;
|
|
typedef std::tr1::shared_ptr<TestChannelMonitorRequester> TestChannelMonitorRequesterPtr;
|
|
typedef std::tr1::weak_ptr<TestChannelMonitorRequester> TestChannelMonitorRequesterWPtr;
|
|
|
|
class TestChannelMonitorRequester
|
|
{
|
|
public:
|
|
virtual void monitorEvent(
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet) = 0;
|
|
};
|
|
|
|
class TestChannelMonitor:
|
|
public MonitorRequester,
|
|
public std::tr1::enable_shared_from_this<TestChannelMonitor>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(TestChannelMonitor);
|
|
virtual string getRequesterName();
|
|
virtual void message(string const & message, MessageType messageType) {}
|
|
virtual void monitorConnect(
|
|
Status const & status,
|
|
MonitorPtr const & monitor,
|
|
StructureConstPtr const & structure);
|
|
virtual void monitorEvent(MonitorPtr const & monitor);
|
|
virtual void unlisten(MonitorPtr const & monitor);
|
|
static TestChannelMonitorPtr create(
|
|
TestChannelMonitorRequesterPtr const &putRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest);
|
|
void connect();
|
|
void waitConnect(double timeout);
|
|
void stopEvents();
|
|
private:
|
|
TestChannelMonitor(
|
|
TestChannelMonitorRequesterPtr const &putRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest);
|
|
|
|
TestChannelMonitorRequesterWPtr monitorRequester;
|
|
TestChannelPtr testChannel;
|
|
PVStructurePtr pvRequest;
|
|
Event waitForConnect;
|
|
Monitor::shared_pointer channelMonitor;
|
|
};
|
|
|
|
TestChannelMonitorPtr TestChannelMonitor::create(
|
|
TestChannelMonitorRequesterPtr const &monitorRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest)
|
|
{
|
|
TestChannelMonitorPtr testChannelMonitor(new TestChannelMonitor(monitorRequester,testChannel,pvRequest));
|
|
testChannelMonitor->connect();
|
|
testChannelMonitor->waitConnect(CONNECTION_TIMEOUT);
|
|
return testChannelMonitor;
|
|
}
|
|
|
|
TestChannelMonitor::TestChannelMonitor(
|
|
TestChannelMonitorRequesterPtr const &monitorRequester,
|
|
TestChannelPtr const &testChannel,
|
|
PVStructurePtr const & pvRequest)
|
|
: monitorRequester(monitorRequester),
|
|
testChannel(testChannel),
|
|
pvRequest(pvRequest)
|
|
{
|
|
}
|
|
|
|
string TestChannelMonitor::getRequesterName() {return "TestChannelMonitor";}
|
|
|
|
void TestChannelMonitor::monitorConnect(
|
|
Status const & status,
|
|
MonitorPtr const & monitor,
|
|
StructureConstPtr const & structure)
|
|
{
|
|
waitForConnect.signal();
|
|
}
|
|
|
|
|
|
void TestChannelMonitor::monitorEvent(MonitorPtr const & monitor)
|
|
{
|
|
TestChannelMonitorRequesterPtr req(monitorRequester.lock());
|
|
if(!req) return;
|
|
while(true) {
|
|
MonitorElementPtr monitorElement = monitor->poll();
|
|
if(!monitorElement) return;
|
|
req->monitorEvent(monitorElement->pvStructurePtr,monitorElement->changedBitSet);
|
|
monitor->release(monitorElement);
|
|
}
|
|
}
|
|
|
|
|
|
void TestChannelMonitor::unlisten(MonitorPtr const & monitor)
|
|
{
|
|
}
|
|
|
|
void TestChannelMonitor::connect()
|
|
{
|
|
channelMonitor = testChannel->getChannel()->createMonitor(shared_from_this(),pvRequest);
|
|
if(!channelMonitor) throw std::runtime_error(testChannel->getChannelName()
|
|
+ " TestChannelMonitor::connect failed ");
|
|
}
|
|
|
|
void TestChannelMonitor::waitConnect(double timeout)
|
|
{
|
|
if(waitForConnect.wait(timeout)) {
|
|
channelMonitor->start();
|
|
return;
|
|
}
|
|
throw std::runtime_error(testChannel->getChannelName()
|
|
+ " TestChannelMonitor::waitConnect failed ");
|
|
}
|
|
|
|
void TestChannelMonitor::stopEvents()
|
|
{
|
|
channelMonitor->stop();
|
|
}
|
|
|
|
class TestClient;
|
|
typedef std::tr1::shared_ptr<TestClient> TestClientPtr;
|
|
|
|
class TestClient:
|
|
public TestChannelGetRequester,
|
|
public TestChannelPutRequester,
|
|
public TestChannelMonitorRequester,
|
|
public std::tr1::enable_shared_from_this<TestClient>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(TestClient);
|
|
virtual void getDone(
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet);
|
|
virtual void putDone();
|
|
virtual void monitorEvent(
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet);
|
|
static TestClientPtr create(string const &channelName,PVStructurePtr const & pvRequest);
|
|
void connect();
|
|
void get();
|
|
void put(string const & value);
|
|
void waitGet(double timeout);
|
|
void waitPut(double timeout);
|
|
void stopEvents();
|
|
virtual ~TestClient() {}
|
|
private:
|
|
TestClient(string const &channelName,PVStructurePtr const & pvRequest);
|
|
string channelName;
|
|
PVStructurePtr pvRequest;
|
|
string putValue;
|
|
TestChannelPtr testChannel;
|
|
TestChannelGetPtr testChannelGet;
|
|
TestChannelPutPtr testChannelPut;
|
|
TestChannelMonitorPtr testChannelMonitor;
|
|
Event waitForGet;
|
|
Event waitForPut;
|
|
};
|
|
|
|
TestClientPtr TestClient::create(string const &channelName,PVStructurePtr const & pvRequest)
|
|
{
|
|
TestClientPtr testClient(new TestClient(channelName,pvRequest));
|
|
testClient->connect();
|
|
return testClient;
|
|
}
|
|
|
|
TestClient::TestClient(string const &channelName,PVStructurePtr const & pvRequest)
|
|
: channelName(channelName),
|
|
pvRequest(pvRequest)
|
|
{
|
|
}
|
|
|
|
void TestClient::connect()
|
|
{
|
|
testChannel = TestChannel::create(channelName);
|
|
testChannelGet = TestChannelGet::create(shared_from_this(),testChannel,pvRequest);
|
|
testChannelPut = TestChannelPut::create(shared_from_this(),testChannel);
|
|
testChannelMonitor = TestChannelMonitor::create(shared_from_this(),testChannel,pvRequest);
|
|
}
|
|
|
|
void TestClient::getDone(
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet)
|
|
{
|
|
testOk(pvStructure.get() != 0,"pvStructure not null");
|
|
testOk(pvStructure->getSubField("value").get() != 0,"value not null");
|
|
testOk(pvStructure->getSubField("timeStamp").get() != 0,"timeStamp not null");
|
|
testOk(pvStructure->getSubField("alarm").get() != 0,"alarm not null");
|
|
if (DEBUG) std::cout << testChannel->getChannelName() + " TestClient::getDone"
|
|
<< " putValue " << putValue
|
|
<< " bitSet " << *bitSet
|
|
<< " pvStructure\n" << pvStructure << "\n";
|
|
PVScalarPtr pvScalar = pvStructure->getSubField<PVScalar>("value");
|
|
if(pvScalar) {
|
|
string getValue = getConvert()->toString(pvScalar);
|
|
testOk(getValue.compare(putValue)==0,"getValue==putValue");
|
|
}
|
|
waitForGet.signal();
|
|
}
|
|
|
|
void TestClient::putDone()
|
|
{
|
|
waitForPut.signal();
|
|
}
|
|
|
|
void TestClient::monitorEvent(
|
|
PVStructure::shared_pointer const & pvStructure,
|
|
BitSet::shared_pointer const & bitSet)
|
|
{
|
|
if (DEBUG) std::cout << testChannel->getChannelName() + " TestClient::monitorEvent"
|
|
<< " bitSet " << *bitSet
|
|
<< " pvStructure\n" << pvStructure << "\n";
|
|
}
|
|
|
|
void TestClient::get()
|
|
{
|
|
testDiag("TestClient::get %s",
|
|
testChannel->getChannelName().c_str());
|
|
testChannelGet->get();
|
|
if (DEBUG) cout << "TestClient::get() calling waitGet\n";
|
|
waitGet(OPERATION_TIMEOUT);
|
|
}
|
|
|
|
void TestClient::waitGet(double timeout)
|
|
{
|
|
testOk(waitForGet.wait(timeout),
|
|
"waitGet(%s) succeeded", testChannel->getChannelName().c_str());
|
|
}
|
|
|
|
void TestClient::put(string const & value)
|
|
{
|
|
testDiag("TestClient::put %s := %s",
|
|
testChannel->getChannelName().c_str(), value.c_str());
|
|
putValue = value;
|
|
testChannelPut->put(value);
|
|
waitPut(OPERATION_TIMEOUT);
|
|
}
|
|
|
|
void TestClient::waitPut(double timeout)
|
|
{
|
|
testOk(waitForPut.wait(timeout),
|
|
"waitPut(%s) succeeded", testChannel->getChannelName().c_str());
|
|
}
|
|
|
|
void TestClient::stopEvents()
|
|
{
|
|
testChannelMonitor->stopEvents();
|
|
}
|
|
|
|
class TestIoc;
|
|
typedef std::tr1::shared_ptr<TestIoc> TestIocPtr;
|
|
|
|
class TestIoc :
|
|
public epicsThreadRunable
|
|
{
|
|
public:
|
|
virtual void run();
|
|
static TestIocPtr create();
|
|
void start();
|
|
void shutdown();
|
|
private:
|
|
#ifndef USE_DBUNITTEST
|
|
std::auto_ptr<epicsThread> thread;
|
|
const char *base;
|
|
const char *arch;
|
|
#endif
|
|
};
|
|
|
|
TestIocPtr TestIoc::create()
|
|
{
|
|
return TestIocPtr(new TestIoc());
|
|
}
|
|
|
|
void TestIoc::start()
|
|
{
|
|
#ifdef USE_DBUNITTEST
|
|
testdbPrepare();
|
|
testdbReadDatabase("testIoc.dbd", NULL, NULL);
|
|
testIoc_registerRecordDeviceDriver(pdbbase);
|
|
testdbReadDatabase("testCaProvider.db", NULL, NULL);
|
|
eltc(0);
|
|
testIocInitOk();
|
|
eltc(1);
|
|
#else
|
|
base = getenv("EPICS_BASE");
|
|
if (!base)
|
|
testAbort("Environment variable $EPICS_BASE not defined");
|
|
arch = getenv("EPICS_HOST_ARCH");
|
|
if (!arch)
|
|
testAbort("Environment variable $EPICS_HOST_ARCH not defined");
|
|
epicsEnvSet("EPICS_CA_ADDR_LIST", "localhost");
|
|
epicsEnvSet("EPICS_CA_AUTO_ADDR_LIST", "NO");
|
|
|
|
thread = std::auto_ptr<epicsThread>(new epicsThread(
|
|
*this,
|
|
"testIoc",
|
|
epicsThreadGetStackSize(epicsThreadStackBig),
|
|
epicsThreadPriorityLow));
|
|
thread->start();
|
|
#endif
|
|
}
|
|
|
|
void TestIoc::run()
|
|
{
|
|
#ifndef USE_DBUNITTEST
|
|
// Base-3.14 doesn't provide the dbUnitTest APIs, and the CA
|
|
// tests with an embedded IOC fail with a Base before 3.16.2.
|
|
// This version only works on workstation targets, it runs the
|
|
// softIoc from Base as a separate process, using system().
|
|
if(system("$EPICS_BASE/bin/$EPICS_HOST_ARCH/softIoc -x test -d ../testCaProvider.db")!=0) {
|
|
string message(base);
|
|
message += "/bin/";
|
|
message += arch;
|
|
message += "/softIoc -d ../testCaProvider.db not started";
|
|
throw std::runtime_error(message);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void TestIoc::shutdown()
|
|
{
|
|
#ifdef USE_DBUNITTEST
|
|
testIocShutdownOk();
|
|
testdbCleanup();
|
|
#endif
|
|
}
|
|
|
|
void checkClient(const string &channelName, const string &putValue)
|
|
{
|
|
string request("value,alarm,timeStamp");
|
|
PVStructurePtr pvRequest(createRequest(request));
|
|
TestClientPtr client = TestClient::create(channelName,pvRequest);
|
|
if (!client)
|
|
testAbort("NULL client for %s", channelName.c_str());
|
|
client->put(putValue);
|
|
client->get();
|
|
client->stopEvents();
|
|
}
|
|
|
|
MAIN(testCaProvider)
|
|
{
|
|
testPlan(143 + EXIT_TESTS);
|
|
|
|
TestIocPtr testIoc(new TestIoc());
|
|
testIoc->start();
|
|
|
|
testDiag("===Test caProvider===");
|
|
CAClientFactory::start();
|
|
ChannelProviderRegistry::shared_pointer reg(ChannelProviderRegistry::clients());
|
|
try {
|
|
ChannelProvider::shared_pointer channelProvider(reg->getProvider("ca"));
|
|
if (!channelProvider) testAbort("Channel provider 'ca' not registered");
|
|
checkClient("DBRlongout", "0");
|
|
checkClient("DBRlongout", "1");
|
|
checkClient("DBRlongout", "-1");
|
|
checkClient("DBRlongout", "32767");
|
|
checkClient("DBRlongout", "32768");
|
|
checkClient("DBRlongout", "-32768");
|
|
checkClient("DBRlongout", "-32769");
|
|
checkClient("DBRlongout", "2147483647");
|
|
checkClient("DBRlongout", "-2147483648");
|
|
checkClient("DBRdoubleout", "1.5");
|
|
checkClient("DBRstringout", "test");
|
|
checkClient("DBRbyteArray", "1 2 3");
|
|
checkClient("DBRshortArray", "1 2 3");
|
|
checkClient("DBRintArray", "1 2 3");
|
|
checkClient("DBRubyteArray", "1 2 3");
|
|
checkClient("DBRushortArray", "1 2 3");
|
|
checkClient("DBRuintArray", "1 2 3");
|
|
checkClient("DBRfloatArray", "1 2 3");
|
|
checkClient("DBRdoubleArray", "1 2 3");
|
|
checkClient("DBRstringArray", "aa bb cc");
|
|
checkClient("DBRmbbout", "2");
|
|
checkClient("DBRbinaryout", "1");
|
|
|
|
#ifndef USE_DBUNITTEST
|
|
// put to record that makes IOC exit
|
|
string channelName = "test:exit";
|
|
string request("value");
|
|
PVStructurePtr pvRequest(createRequest(request));
|
|
TestClientPtr client = TestClient::create(channelName,pvRequest);
|
|
if (!client)
|
|
testAbort("NULL client for %s", channelName.c_str());
|
|
client->put("1");
|
|
client->stopEvents();
|
|
#endif
|
|
}
|
|
catch (std::exception& e) {
|
|
testAbort("caught un-expected exception: %s", e.what());
|
|
}
|
|
|
|
testIoc->shutdown();
|
|
|
|
return testDone();;
|
|
}
|
|
|