diff --git a/test/Makefile b/test/Makefile index 780993c..3a474cf 100644 --- a/test/Makefile +++ b/test/Makefile @@ -54,6 +54,10 @@ TESTPROD += testput testput_SRCS += testput.cpp TESTS += testput +TESTPROD += testrpc +testrpc_SRCS += testrpc.cpp +TESTS += testrpc + TESTPROD += dummyserv dummyserv_SRCS += dummyserv.cpp # not a unittest diff --git a/test/testrpc.cpp b/test/testrpc.cpp new file mode 100644 index 0000000..77a6568 --- /dev/null +++ b/test/testrpc.cpp @@ -0,0 +1,173 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvxs is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ + +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { +using namespace pvxs; + +struct Tester { + client::Result actual; + epicsEvent done; + Value initial; + server::SharedPV mbox; + server::Server serv; + client::Context cli; + bool fail = false; + + Tester() + :initial(nt::NTScalar{TypeCode::Int32}.create()) + ,mbox(server::SharedPV::buildMailbox()) + ,serv(server::Config::localhost() + .build() + .addPV("mailbox", mbox)) + ,cli(serv.clientConfig().build()) + { + testShow()<<"Server:\n"<&& op, Value&& arg) { + if(fail) + op->error("oops"); + else + op->reply(arg); // echo + }); + } + + std::shared_ptr doCall(Value&& arg) + { + + auto op = cli.rpc("mailbox", std::move(arg)) + .result([this](client::Result&& result) { + actual = std::move(result); + done.trigger(); + }) + .exec(); + + cli.hurryUp(); + + return op; + } + + Value testWaitOk() + { + if(testOk1(done.wait(5.0))) { + try { + auto ret = actual(); + testPass("RPC success"); + return ret; + }catch(std::exception& e){ + testFail("RPC error %s : %s", typeid (e).name(), e.what()); + } + } else { + testSkip(1, "timeout"); + } + return Value(); + } + + void echo() + { + mbox.open(initial); + serv.start(); + + auto arg = initial.cloneEmpty(); + arg["value"] = 42; + auto op = doCall(std::move(arg)); + if(auto ret = testWaitOk()) { + + int32_t v=0; + testOk1(!!ret["value"].as(v)); + testEq(v, 42); + } + } + + void lazy() + { + // mbox not open + serv.start(); + + auto arg = initial.cloneEmpty(); + arg["value"] = 42; + auto op = doCall(std::move(arg)); + if(auto ret = testWaitOk()) { + + int32_t v=0; + testOk1(!!ret["value"].as(v)); + testEq(v, 42); + } + } + + void timeout() + { + // server not started + + auto arg = initial.cloneEmpty(); + arg["value"] = 42; + auto op = doCall(std::move(arg)); + testOk1(!done.wait(2.1)); + } + + void cancel() + { + mbox.open(initial); + serv.start(); + + auto arg = initial.cloneEmpty(); + arg["value"] = 42; + (void)doCall(std::move(arg)); + testOk1(!done.wait(2.1)); + + } + + void error() + { + mbox.open(initial); + serv.start(); + fail=true; + + auto arg = initial.cloneEmpty(); + arg["value"] = 42; + auto op = doCall(std::move(arg)); + + if(testOk1(done.wait(5.0))) { + testThrows([this](){ + actual(); + }); + } else { + testSkip(1, "timeout"); + } + } +}; + +} // namespace + +MAIN(testrpc) +{ + testPlan(12); + Tester().echo(); + Tester().lazy(); + Tester().timeout(); + Tester().cancel(); + Tester().error(); + cleanup_for_valgrind(); + return testDone(); +}