From 43e05ce0487b2888da6c67a5f715ef702c90c830 Mon Sep 17 00:00:00 2001 From: Gasper Jansa Date: Fri, 25 Feb 2011 17:12:00 +0100 Subject: [PATCH] server test --- testApp/remote/Makefile | 4 + testApp/remote/testRemoteClientImpl.cpp | 15 +- testApp/remote/testServer.cpp | 891 ++++++++++++++++++++++++ 3 files changed, 903 insertions(+), 7 deletions(-) create mode 100644 testApp/remote/testServer.cpp diff --git a/testApp/remote/Makefile b/testApp/remote/Makefile index 6304fc3..6bc794e 100644 --- a/testApp/remote/Makefile +++ b/testApp/remote/Makefile @@ -38,6 +38,10 @@ PROD_HOST += testServerContext testServerContext_SRCS += testServerContext.cpp testServerContext_LIBS += pvData pvAccess Com +PROD_HOST += testServer +testServer_SRCS += testServer.cpp +testServer_LIBS += pvData pvAccess Com + include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE diff --git a/testApp/remote/testRemoteClientImpl.cpp b/testApp/remote/testRemoteClientImpl.cpp index c4c7ae0..6c5c0f3 100644 --- a/testApp/remote/testRemoteClientImpl.cpp +++ b/testApp/remote/testRemoteClientImpl.cpp @@ -461,16 +461,17 @@ int main(int argc,char *argv[]) channelFind->destroy(); */ ChannelRequesterImpl channelRequester; - Channel* channel = provider->createChannel("structureArrayTest", &channelRequester); + Channel* channel = provider->createChannel("test", &channelRequester); epicsThreadSleep ( 1.0 ); channel->printInfo(); - - PVStructure* pvRequest; + + PVStructure* pvRequest; +/* GetFieldRequesterImpl getFieldRequesterImpl; - channel->getField(&getFieldRequesterImpl, ""); + channel->getField(&getFieldRequesterImpl, "alarm"); epicsThreadSleep ( 1.0 ); ChannelProcessRequesterImpl channelProcessRequester; @@ -490,7 +491,7 @@ int main(int argc,char *argv[]) channelGet->destroy(); delete pvRequest; - +*/ ChannelPutRequesterImpl channelPutRequesterImpl; pvRequest = getCreateRequest()->createRequest("field(value,timeStamp)",&channelPutRequesterImpl); ChannelPut* channelPut = channel->createChannelPut(&channelPutRequesterImpl, pvRequest); @@ -501,7 +502,7 @@ int main(int argc,char *argv[]) epicsThreadSleep ( 1.0 ); channelPut->destroy(); delete pvRequest; - +/* ChannelPutGetRequesterImpl channelPutGetRequesterImpl; pvRequest = getCreateRequest()->createRequest("putField(value,timeStamp)getField(timeStamp)",&channelPutGetRequesterImpl); ChannelPutGet* channelPutGet = channel->createChannelPutGet(&channelPutGetRequesterImpl, pvRequest); @@ -561,7 +562,7 @@ int main(int argc,char *argv[]) monitor->destroy(); delete pvRequest; - epicsThreadSleep ( 3.0 ); + epicsThreadSleep ( 3.0 );*/ printf("Destroying channel... \n"); channel->destroy(); printf("done.\n"); diff --git a/testApp/remote/testServer.cpp b/testApp/remote/testServer.cpp new file mode 100644 index 0000000..4d2df11 --- /dev/null +++ b/testApp/remote/testServer.cpp @@ -0,0 +1,891 @@ +/* + * testServer.cpp + */ + +#include "serverContext.h" +#include "clientContextImpl.h" +#include +#include +#include + +using namespace epics::pvAccess; +using namespace epics::pvData; +using namespace std; + + + +PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelProcess); + +class MockChannelProcess : public ChannelProcess +{ + private: + ChannelProcessRequester* m_channelProcessRequester; + PVStructure* m_pvStructure; + PVScalar* m_valueField; + + private: + ~MockChannelProcess() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelProcess); + } + + public: + MockChannelProcess(ChannelProcessRequester* channelProcessRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + m_channelProcessRequester(channelProcessRequester), m_pvStructure(pvStructure) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelProcess); + + PVField* field = pvStructure->getSubField(String("value")); + if (field == 0) + { + Status noValueFieldStatus(Status::STATUSTYPE_ERROR, "no 'value' field"); + m_channelProcessRequester->channelProcessConnect(noValueFieldStatus, this); + + // NOTE client must destroy this instance... + // do not access any fields and return ASAP + return; + } + + if (field->getField()->getType() != scalar) + { + Status notAScalarStatus(Status::STATUSTYPE_ERROR, "'value' field not scalar type"); + m_channelProcessRequester->channelProcessConnect(notAScalarStatus, this); + + // NOTE client must destroy this instance…. + // do not access any fields and return ASAP + return; + } + + m_valueField = static_cast(field); + + // TODO pvRequest + m_channelProcessRequester->channelProcessConnect(Status::OK, this); + } + + virtual void process(bool lastRequest) + { + switch (m_valueField->getScalar()->getScalarType()) + { + case pvBoolean: + { + // negate + PVBoolean *pvBoolean = static_cast(m_valueField); + pvBoolean->put(!pvBoolean->get()); + break; + } + case pvByte: + { + // increment by one + PVByte *pvByte = static_cast(m_valueField); + pvByte->put(pvByte->get() + 1); + break; + } + case pvShort: + { + // increment by one + PVShort *pvShort = static_cast(m_valueField); + pvShort->put(pvShort->get() + 1); + break; + } + case pvInt: + { + // increment by one + PVInt *pvInt = static_cast(m_valueField); + pvInt->put(pvInt->get() + 1); + break; + } + case pvLong: + { + // increment by one + PVLong *pvLong = static_cast(m_valueField); + pvLong->put(pvLong->get() + 1); + break; + } + case pvFloat: + { + // increment by one + PVFloat *pvFloat = static_cast(m_valueField); + pvFloat->put(pvFloat->get() + 1.0f); + break; + } + case pvDouble: + { + // increment by one + PVDouble *pvDouble = static_cast(m_valueField); + pvDouble->put(pvDouble->get() + 1.0); + break; + } + case pvString: + { + // increment by one + PVString *pvString = static_cast(m_valueField); + String val = pvString->get(); + if (val.empty()) + pvString->put("gen0"); + else + { + char c = val[0]; + c++; + pvString->put("gen" + c); + } + break; + } + default: + // noop + break; + + } + m_channelProcessRequester->processDone(Status::OK); + + if (lastRequest) + destroy(); + } + + virtual void destroy() + { + delete this; + } + +}; + + + + + + +PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelGet); + +class MockChannelGet : public ChannelGet +{ + private: + ChannelGetRequester* m_channelGetRequester; + PVStructure* m_pvStructure; + BitSet* m_bitSet; + bool m_first; + + private: + ~MockChannelGet() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelGet); + } + + public: + MockChannelGet(ChannelGetRequester* channelGetRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + m_channelGetRequester(channelGetRequester), m_pvStructure(pvStructure), + m_bitSet(new BitSet(pvStructure->getNumberFields())), m_first(true) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelGet); + + // TODO pvRequest + m_channelGetRequester->channelGetConnect(Status::OK, this, m_pvStructure, m_bitSet); + } + + virtual void get(bool lastRequest) + { + m_channelGetRequester->getDone(Status::OK); + if (m_first) + { + m_first = false; + m_bitSet->set(0); // TODO + } + + if (lastRequest) + destroy(); + } + + virtual void destroy() + { + delete m_bitSet; + delete this; + } + +}; + + + + + + + + +PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannelPut); + +class MockChannelPut : public ChannelPut +{ + private: + ChannelPutRequester* m_channelPutRequester; + PVStructure* m_pvStructure; + BitSet* m_bitSet; + bool m_first; + + private: + ~MockChannelPut() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannelPut); + } + + public: + MockChannelPut(ChannelPutRequester* channelPutRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + m_channelPutRequester(channelPutRequester), m_pvStructure(pvStructure), + m_bitSet(new BitSet(pvStructure->getNumberFields())), m_first(true) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannelPut); + + // TODO pvRequest + m_channelPutRequester->channelPutConnect(Status::OK, this, m_pvStructure, m_bitSet); + } + + virtual void put(bool lastRequest) + { + m_channelPutRequester->putDone(Status::OK); + if (lastRequest) + destroy(); + } + + virtual void get() + { + m_channelPutRequester->getDone(Status::OK); + } + + virtual void destroy() + { + delete m_bitSet; + delete this; + } + +}; + + + + + + + +PVDATA_REFCOUNT_MONITOR_DEFINE(mockMonitor); + +class MockMonitor : public Monitor, public MonitorElement +{ + private: + MonitorRequester* m_monitorRequester; + PVStructure* m_pvStructure; + BitSet* m_changedBitSet; + BitSet* m_overrunBitSet; + bool m_first; + Mutex m_lock; + int m_count; + + private: + ~MockMonitor() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockMonitor); + } + + public: + MockMonitor(MonitorRequester* monitorRequester, PVStructure *pvStructure, PVStructure *pvRequest) : + m_monitorRequester(monitorRequester), m_pvStructure(pvStructure), + m_changedBitSet(new BitSet(pvStructure->getNumberFields())), + m_overrunBitSet(new BitSet(pvStructure->getNumberFields())), + m_first(true), + m_lock(), + m_count(0) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockMonitor); + + m_changedBitSet->set(0); + + // TODO pvRequest + m_monitorRequester->monitorConnect(Status::OK, this, const_cast(m_pvStructure->getStructure())); + } + + virtual Status start() + { + // fist monitor + m_monitorRequester->monitorEvent(this); + + return Status::OK; + } + + virtual Status stop() + { + return Status::OK; + } + + virtual MonitorElement* poll() + { + Lock xx(m_lock); + if (m_count) + { + return 0; + } + else + { + m_count++; + return this; + } + } + + virtual void release(MonitorElement* monitorElement) + { + Lock xx(m_lock); + if (m_count) + m_count--; + } + + virtual void destroy() + { + stop(); + + delete m_overrunBitSet; + delete m_changedBitSet; + delete this; + } + + // ============ MonitorElement ============ + + virtual PVStructure* getPVStructure() + { + return m_pvStructure; + } + + virtual BitSet* getChangedBitSet() + { + return m_changedBitSet; + } + + virtual BitSet* getOverrunBitSet() + { + return m_overrunBitSet; + } + + +}; + + + +PVDATA_REFCOUNT_MONITOR_DEFINE(mockChannel); + +class MockChannel : public Channel { + private: + ChannelProvider* m_provider; + ChannelRequester* m_requester; + String m_name; + String m_remoteAddress; + + PVStructure* m_pvStructure; + + private: + ~MockChannel() + { + PVDATA_REFCOUNT_MONITOR_DESTRUCT(mockChannel); + } + + public: + + MockChannel( + ChannelProvider* provider, + ChannelRequester* requester, + String name, + String remoteAddress) : + m_provider(provider), + m_requester(requester), + m_name(name), + m_remoteAddress(remoteAddress) + { + PVDATA_REFCOUNT_MONITOR_CONSTRUCT(mockChannel); + + + ScalarType stype = pvDouble; + String allProperties("alarm,timeStamp,display,control,valueAlarm"); + + m_pvStructure = getStandardPVField()->scalar( + 0,name,stype,allProperties); + PVDouble *pvField = m_pvStructure->getDoubleField(String("value")); + pvField->put(1.123); + + + // already connected, report state + m_requester->channelStateChange(this, CONNECTED); + } + + virtual void destroy() + { + delete m_pvStructure; + delete this; + }; + + virtual String getRequesterName() + { + return getChannelName(); + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual ChannelProvider* getProvider() + { + return m_provider; + } + + virtual epics::pvData::String getRemoteAddress() + { + return m_remoteAddress; + } + + virtual epics::pvData::String getChannelName() + { + return m_name; + } + + virtual ChannelRequester* getChannelRequester() + { + return m_requester; + } + + virtual ConnectionState getConnectionState() + { + return CONNECTED; + } + + virtual bool isConnected() + { + return getConnectionState() == CONNECTED; + } + + virtual AccessRights getAccessRights(epics::pvData::PVField *pvField) + { + return readWrite; + } + + virtual void getField(GetFieldRequester *requester,epics::pvData::String subField) + { + PVFieldPtr pvField = m_pvStructure->getSubField(subField); + if(pvField == NULL) + { + string errMsg = "field '" + subField + "' not found"; + Status errorStatus(Status::STATUSTYPE_ERROR, errMsg); + requester->getDone(errorStatus,NULL); + return; + } + requester->getDone(Status::OK,m_pvStructure->getSubField(subField)->getField()); + } + + virtual ChannelProcess* createChannelProcess( + ChannelProcessRequester *channelProcessRequester, + epics::pvData::PVStructure *pvRequest) + { + return new MockChannelProcess(channelProcessRequester, m_pvStructure, pvRequest); + } + + virtual ChannelGet* createChannelGet( + ChannelGetRequester *channelGetRequester, + epics::pvData::PVStructure *pvRequest) + { + return new MockChannelGet(channelGetRequester, m_pvStructure, pvRequest); + } + + virtual ChannelPut* createChannelPut( + ChannelPutRequester *channelPutRequester, + epics::pvData::PVStructure *pvRequest) + { + return new MockChannelPut(channelPutRequester, m_pvStructure, pvRequest); + } + + virtual ChannelPutGet* createChannelPutGet( + ChannelPutGetRequester *channelPutGetRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual ChannelRPC* createChannelRPC(ChannelRPCRequester *channelRPCRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual epics::pvData::Monitor* createMonitor( + epics::pvData::MonitorRequester *monitorRequester, + epics::pvData::PVStructure *pvRequest) + { + return new MockMonitor(monitorRequester, m_pvStructure, pvRequest); + } + + virtual ChannelArray* createChannelArray( + ChannelArrayRequester *channelArrayRequester, + epics::pvData::PVStructure *pvRequest) + { + // TODO + return 0; + } + + virtual void printInfo() { + String info; + printInfo(&info); + std::cout << info.c_str() << std::endl; + } + + virtual void printInfo(epics::pvData::StringBuilder out) { + //std::ostringstream ostr; + //static String emptyString; + + out->append( "CHANNEL : "); out->append(m_name); + out->append("\nSTATE : "); out->append(ConnectionStateNames[getConnectionState()]); + if (isConnected()) + { + out->append("\nADDRESS : "); out->append(getRemoteAddress()); + //out->append("\nRIGHTS : "); out->append(getAccessRights()); + } + out->append("\n"); + } +}; + + +class MockServerChannelProvider; + +class MockChannelFind : public ChannelFind +{ + public: + MockChannelFind(ChannelProvider* provider) : m_provider(provider) + { + } + + virtual void destroy() + { + // one instance for all, do not delete at all + } + + virtual ChannelProvider* getChannelProvider() + { + return m_provider; + }; + + virtual void cancelChannelFind() + { + throw std::runtime_error("not supported"); + } + + private: + + // only to be destroyed by it + friend class MockServerChannelProvider; + virtual ~MockChannelFind() {} + + ChannelProvider* m_provider; +}; + + +class MockServerChannelProvider : public ChannelProvider { + public: + + MockServerChannelProvider() : m_mockChannelFind(new MockChannelFind(this)) { + } + + virtual epics::pvData::String getProviderName() + { + return "local"; + } + + virtual void destroy() + { + delete m_mockChannelFind; + delete this; + } + + virtual ChannelFind* channelFind( + epics::pvData::String channelName, + ChannelFindRequester *channelFindRequester) + { + channelFindRequester->channelFindResult(Status::OK, m_mockChannelFind, true); + return m_mockChannelFind; + } + + virtual Channel* createChannel( + epics::pvData::String channelName, + ChannelRequester *channelRequester, + short priority) + { + return createChannel(channelName, channelRequester, priority, "local"); + } + + virtual Channel* createChannel( + epics::pvData::String channelName, + ChannelRequester *channelRequester, + short priority, + epics::pvData::String address) + { + if (address == "local") + { + Channel* channel = new MockChannel(this, channelRequester, channelName, address); + channelRequester->channelCreated(Status::OK, channel); + return channel; + } + else + { + Status errorStatus(Status::STATUSTYPE_ERROR, "only local supported"); + channelRequester->channelCreated(errorStatus, 0); + return 0; + } + } + + private: + ~MockServerChannelProvider() {}; + + MockChannelFind* m_mockChannelFind; + +}; + + +class ChannelFindRequesterImpl : public ChannelFindRequester +{ + virtual void channelFindResult(const epics::pvData::Status& status,ChannelFind *channelFind,bool wasFound) + { + std::cout << "[ChannelFindRequesterImpl] channelFindResult(" + << status.toString() << ", ..., " << wasFound << ")" << std::endl; + } +}; + +class ChannelRequesterImpl : public ChannelRequester +{ + virtual String getRequesterName() + { + return "ChannelRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void channelCreated(const epics::pvData::Status& status, Channel *channel) + { + std::cout << "channelCreated(" << status.toString() << ", " + << (channel ? channel->getChannelName() : "(null)") << ")" << std::endl; + } + + virtual void channelStateChange(Channel *c, Channel::ConnectionState connectionState) + { + std::cout << "channelStateChange(" << c->getChannelName() << ", " << Channel::ConnectionStateNames[connectionState] << ")" << std::endl; + } +}; + +class GetFieldRequesterImpl : public GetFieldRequester +{ + virtual String getRequesterName() + { + return "GetFieldRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void getDone(const epics::pvData::Status& status,epics::pvData::FieldConstPtr field) + { + std::cout << "getDone(" << status.toString() << ", "; + if (field) + { + String str; + field->toString(&str); + std::cout << str; + } + else + std::cout << "(null)"; + std::cout << ")" << std::endl; + } +}; + +class ChannelGetRequesterImpl : public ChannelGetRequester +{ + ChannelGet *m_channelGet; + epics::pvData::PVStructure *m_pvStructure; + epics::pvData::BitSet *m_bitSet; + + virtual String getRequesterName() + { + return "ChannelGetRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void channelGetConnect(const epics::pvData::Status& status,ChannelGet *channelGet, + epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + { + std::cout << "channelGetConnect(" << status.toString() << ")" << std::endl; + + // TODO sync + m_channelGet = channelGet; + m_pvStructure = pvStructure; + m_bitSet = bitSet; + } + + virtual void getDone(const epics::pvData::Status& status) + { + std::cout << "getDone(" << status.toString() << ")" << std::endl; + String str; + m_pvStructure->toString(&str); + std::cout << str; + std::cout << std::endl; + } +}; + +class ChannelPutRequesterImpl : public ChannelPutRequester +{ + ChannelPut *m_channelPut; + epics::pvData::PVStructure *m_pvStructure; + epics::pvData::BitSet *m_bitSet; + + virtual String getRequesterName() + { + return "ChannelPutRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void channelPutConnect(const epics::pvData::Status& status,ChannelPut *channelPut, + epics::pvData::PVStructure *pvStructure,epics::pvData::BitSet *bitSet) + { + std::cout << "channelPutConnect(" << status.toString() << ")" << std::endl; + + // TODO sync + m_channelPut = channelPut; + m_pvStructure = pvStructure; + m_bitSet = bitSet; + } + + virtual void getDone(const epics::pvData::Status& status) + { + std::cout << "getDone(" << status.toString() << ")" << std::endl; + String str; + m_pvStructure->toString(&str); + std::cout << str; + std::cout << std::endl; + } + + virtual void putDone(const epics::pvData::Status& status) + { + std::cout << "putDone(" << status.toString() << ")" << std::endl; + String str; + m_pvStructure->toString(&str); + std::cout << str; + std::cout << std::endl; + } + +}; + + +class MonitorRequesterImpl : public MonitorRequester +{ + virtual String getRequesterName() + { + return "MonitorRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void monitorConnect(const Status& status, Monitor* monitor, Structure* structure) + { + std::cout << "monitorConnect(" << status.toString() << ")" << std::endl; + if (structure) + { + String str; + structure->toString(&str); + std::cout << str << std::endl; + } + } + + virtual void monitorEvent(Monitor* monitor) + { + std::cout << "monitorEvent" << std::endl; + + MonitorElement* element = monitor->poll(); + + String str("changed/overrun "); + element->getChangedBitSet()->toString(&str); + str += '/'; + element->getOverrunBitSet()->toString(&str); + str += '\n'; + element->getPVStructure()->toString(&str); + std::cout << str << std::endl; + + monitor->release(element); + } + + virtual void unlisten(Monitor* monitor) + { + std::cout << "unlisten" << std::endl; + } +}; + + +class ChannelProcessRequesterImpl : public ChannelProcessRequester +{ + ChannelProcess *m_channelProcess; + + virtual String getRequesterName() + { + return "ProcessRequesterImpl"; + }; + + virtual void message(String message,MessageType messageType) + { + std::cout << "[" << getRequesterName() << "] message(" << message << ", " << messageTypeName[messageType] << ")" << std::endl; + } + + virtual void channelProcessConnect(const epics::pvData::Status& status,ChannelProcess *channelProcess) + { + std::cout << "channelProcessConnect(" << status.toString() << ")" << std::endl; + + // TODO sync + m_channelProcess = channelProcess; + } + + virtual void processDone(const epics::pvData::Status& status) + { + std::cout << "processDone(" << status.toString() << ")" << std::endl; + } + +}; + + +void testServer() +{ + ChannelAccess* channelAccess = getChannelAccess(); + MockServerChannelProvider* channelProvider = new MockServerChannelProvider(); + registerChannelProvider(static_cast(channelProvider)); + + ServerContextImpl ctx; + ctx.initialize(channelAccess); + + ctx.printInfo(); + + ctx.run(0); + + ctx.destroy(); + + unregisterChannelProvider(static_cast(channelProvider)); +} + +int main(int argc, char *argv[]) +{ + testServer(); + + cout << "Done" << endl; + + epicsExitCallAtExits(); + CDRMonitor::get().show(stdout); + return (0); +}