/*============================================================================= testclient =============================================================================== Test the client C++ facilities of XML-RPC for C/C++. Contrary to what you might expect, we use the server facilities too because we test much of the client using a simulated server, via the "direct" client XML transport we define herein. =============================================================================*/ #include #include #include #include #include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "transport_config.h" #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/registry.hpp" #include "xmlrpc-c/client.hpp" #include "xmlrpc-c/client_simple.hpp" #include "tools.hpp" #include "testclient.hpp" using namespace xmlrpc_c; using namespace std; namespace { class sampleAddMethod : public method { public: sampleAddMethod() { this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = value_int(addend + adder); } }; class testApacheDialectMethod : public method { public: void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { paramList.getNil(0); paramList.verifyEnd(1); *retvalP = value_i8(7ll); } }; class carriageParm_direct : public carriageParm { public: carriageParm_direct(registry * const registryP) : registryP(registryP) {} registry * registryP; }; class clientXmlTransport_direct : public clientXmlTransport { /*---------------------------------------------------------------------------- Though this fills the shoes of a client XML transport, it's really a simulation, because it doesn't transport anything anywhere. The call() method, which is supposed to transport a call to a server and then transport the response back, actually just executes the method itself. Part of a carriage parameter for a transport of this class is the handle of a method registry, so the transport knows how to execute the method. -----------------------------------------------------------------------------*/ public: void call(xmlrpc_c::carriageParm * const carriageParmP, string const& callXml, string * const responseXmlP) { carriageParm_direct * const parmP = dynamic_cast(carriageParmP); if (parmP == NULL) throw(error("Carriage parameter passed to the direct " "transport is not type carriageParm_direct")); parmP->registryP->processCall(callXml, responseXmlP); } }; class clientDirectAsyncTestSuite : public testSuite { /*---------------------------------------------------------------------------- See clientDirectTestSuite for a description of how we use a clientXmlTransport_direct object to test client functions. The object of this class tests the async client functions. With clientXmlTransport_direct, these are pretty simple because the transport doesn't even implement an asynchronous interface; it relies on the base class' emulation of start() using call(). Some day, we should add true asynchronous capability to clientXmlTransport_direct and really test things. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientDirectAsyncTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect); paramList paramListSampleAdd1; paramListSampleAdd1.add(value_int(5)); paramListSampleAdd1.add(value_int(7)); paramList paramListSampleAdd2; paramListSampleAdd2.add(value_int(30)); paramListSampleAdd2.add(value_int(-10)); rpcPtr const rpcSampleAdd1P("sample.add", paramListSampleAdd1); rpcSampleAdd1P->start(&clientDirect, &carriageParmDirect); rpcPtr const rpcSampleAdd2P("sample.add", paramListSampleAdd2); rpcSampleAdd2P->start(&clientDirect, &carriageParmDirect); // Note that for clientXmlTransport_direct, start() and call() are // the same thing. I.e. the RPC is guaranteed finished as soon // as it is started. clientDirect.finishAsync(timeout()); clientDirect.finishAsync(timeout(50)); TEST(rpcSampleAdd1P->isFinished()); TEST(rpcSampleAdd1P->isSuccessful()); value_int const result1(rpcSampleAdd1P->getResult()); TEST(static_cast(result1) == 12); TEST(rpcSampleAdd2P->isFinished()); TEST(rpcSampleAdd1P->isSuccessful()); value_int const result2(rpcSampleAdd2P->getResult()); TEST(static_cast(result2) == 20); } }; class MyRpc : public rpc { public: MyRpc(std::string const methodName, paramList const& paramList) : rpc(methodName, paramList) {} void progress(struct xmlrpc_progress_data const& data) const { // The way the tests are currently written, this never actually // runs; we're just testing for ability to compile. cout << "Progress of " << this << ": " << data.call.total << " " << data.call.now << " " << data.response.total << " " << data.response.now << endl; } }; class clientDerivedRpcTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests the ability to derive a class from xmlrpc_c::rpc in order to override certain methods. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientDerivedRpcTestSuite"; } virtual void runtests(unsigned int const ) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); { /* Test a successful RPC */ rpcPtr rpcSampleAddP(new MyRpc("sample.add", paramListSampleAdd)); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } } }; class clientDirectTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests the client facilities by using a special client XML transport defined above and an XML-RPC server we build ourselves and run inline. We build the server out of a xmlrpc_c::registry object and our transport just delivers XML directly to the registry object and gets the response XML from it and delivers that back. There's no network or socket or pipeline or anything -- the transport actually executes the XML-RPC method. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientDirectTestSuite"; } virtual void runtests(unsigned int const indentation) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); paramList paramListEmpty; { /* Test a successful RPC */ rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } { /* Test a failed RPC */ rpcPtr const rpcSampleAddP("sample.add", paramListEmpty); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(!rpcSampleAddP->isSuccessful()); fault const fault0(rpcSampleAddP->getFault()); TEST(fault0.getCode() == fault::CODE_TYPE); } { /* Test with an auto object transport */ client_xml clientDirect( clientXmlTransportPtr(new clientXmlTransport_direct)); rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault());); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } { /* Test with implicit RPC -- success */ rpcOutcome outcome; clientDirect.call(&carriageParmDirect, "sample.add", paramListSampleAdd, &outcome); TEST(outcome.succeeded()); value_int const result(outcome.getResult()); TEST(static_cast(result) == 12); } { /* Test with implicit RPC - failure */ rpcOutcome outcome; clientDirect.call(&carriageParmDirect, "nosuchmethod", paramList(), &outcome); TEST(!outcome.succeeded()); TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); TEST(outcome.getFault().getDescription().size() > 0); } int interruptFlag(0); EXPECT_ERROR(transportDirect.setInterrupt(&interruptFlag);); // This transport class isn't interruptible EXPECT_ERROR(clientDirect.setInterrupt(&interruptFlag);); // Same as above clientDirectAsyncTestSuite().run(indentation+1); clientDerivedRpcTestSuite().run(indentation+1); } }; class curlTransportTestSuite : public testSuite { public: virtual string suiteName() { return "curlTransportTestSuite"; } virtual void runtests(unsigned int const) { #if MUST_BUILD_CURL_CLIENT clientXmlTransport_curl transport0; clientXmlTransport_curl transport1("eth0"); clientXmlTransport_curl transport2("eth0", true); clientXmlTransport_curl transport3("eth0", true, true); clientXmlTransport_curl transport4( clientXmlTransport_curl::constrOpt() .network_interface("eth0") .dont_advertise(true) .user_agent("my user agent") .referer("my referer") .no_ssl_verifypeer(true) .no_ssl_verifyhost(true) .ssl_cert("/etc/sslcert") .sslcerttype("PEM") .sslcertpasswd("mypass") .sslkey("/etc/sslkey") .sslkeytype("DER") .sslkeypasswd("mykeypass") .sslengine("mysslengine") .sslengine_default(true) .sslversion(XMLRPC_SSLVERSION_SSLv2) .cainfo("/etc/cainfo") .capath("/etc/cadir") .randomfile("/dev/random") .egdsocket("/tmp/egdsocket") .ssl_cipher_list("RC4-SHA:DEFAULT") .proxy("example.com") .proxy_port(8080) .proxy_userpwd("password") .proxy_type(XMLRPC_HTTPPROXY_SOCKS5) .proxy_auth(XMLRPC_HTTPAUTH_BASIC) .proxy_userpwd("mypassword") .gssapi_delegation(true) .timeout(0) .connect_timeout(0) ); clientXmlTransport_curl transport5( clientXmlTransport_curl::constrOpt() .no_ssl_verifypeer(false)); clientXmlTransport_curl transport6( clientXmlTransport_curl::constrOpt()); clientXmlTransportPtr transport1P(new clientXmlTransport_curl); clientXmlTransportPtr transport2P; transport2P = transport1P; time_t nowtime = time(NULL); transport2P->finishAsync(timeout()); transport2P->finishAsync(timeout(2000)); transport2P->finishAsync(2000); TEST(time(NULL) <= nowtime + 1); int interruptFlag; transport2P->setInterrupt(&interruptFlag); interruptFlag = 0; transport2P->finishAsync(2000); transport2P->finishAsync(timeout()); #else EXPECT_ERROR(clientXmlTransport_curl transport0;); EXPECT_ERROR(clientXmlTransport_curl transport1("eth0");); EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true);); EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true, true);); #endif } }; class libwwwTransportTestSuite : public testSuite { public: virtual string suiteName() { return "libwwwTransportTestSuite"; } virtual void runtests(unsigned int const) { #if MUST_BUILD_LIBWWW_CLIENT clientXmlTransport_libwww transport0; clientXmlTransport_libwww transport1("getbent"); clientXmlTransport_libwww transport2("getbent", "1.0"); clientXmlTransportPtr transport1P(new clientXmlTransport_libwww); clientXmlTransportPtr transport2P; transport2P = transport1P; #else EXPECT_ERROR(clientXmlTransport_libwww transport0;); EXPECT_ERROR(clientXmlTransport_libwww transport1("getbent");); EXPECT_ERROR(clientXmlTransport_libwww transport2("getbent", "1.0");); #endif } }; class wininetTransportTestSuite : public testSuite { public: virtual string suiteName() { return "wininetTransportTestSuite"; } virtual void runtests(unsigned int const) { #if MUST_BUILD_WININET_CLIENT clientXmlTransport_wininet transport0; clientXmlTransport_wininet transport1(true); clientXmlTransportPtr transport1P(new clientXmlTransport_wininet); clientXmlTransportPtr transport2P; transport2P = transport1P; #else EXPECT_ERROR(clientXmlTransport_wininet transport0;); EXPECT_ERROR(clientXmlTransport_wininet transport1(true);); #endif } }; class ambivalentHttpTransportTestSuite : public testSuite { public: virtual string suiteName() { return "ambivalentHttpTransportTestSuite"; } virtual void runtests(unsigned int const) { vector const typeList( clientXmlTransport_http::availableTypes()); TEST(typeList.size() > 0); clientXmlTransportPtr const transportP( clientXmlTransport_http::create()); carriageParm_http0 carriageParm0("http://whatsamatta.edux"); client_xml client0(transportP); rpcOutcome outcome; // Fails because there's no such server EXPECT_ERROR( client0.call(&carriageParm0, "nosuchmethod", paramList(), &outcome); ); } }; class pstreamTransportTestSuite : public testSuite { public: virtual string suiteName() { return "pstreamTransportTestSuite"; } virtual void runtests(unsigned int const) { int const devNullFd(open("/dev/null", 0)); if (devNullFd < 0) throw error("Failed to open /dev/null, needed for test."); EXPECT_ERROR(clientXmlTransport_pstream transport1( clientXmlTransport_pstream::constrOpt() .fd(37) );); // ERROR: no such file descriptor carriageParm_pstream carriageParm0; { clientXmlTransport_pstream transport2( clientXmlTransport_pstream::constrOpt() .fd(devNullFd) ); string callXml("hello"); string responseXml; EXPECT_ERROR(transport2.call(NULL, callXml, &responseXml);); // Error: carriage parm not of type carriageParm_pstream EXPECT_ERROR(transport2.call(&carriageParm0, callXml, &responseXml);); // Error: no response } { clientXmlTransport_pstream transport2( clientXmlTransport_pstream::constrOpt() .fd(devNullFd) .useBrokenConnEx(true) ); } clientXmlTransportPtr transport1P(new clientXmlTransport_pstream( clientXmlTransport_pstream::constrOpt() .fd(devNullFd) )); clientXmlTransportPtr transport2P; transport2P = transport1P; close(devNullFd); } }; class clientXmlTransportTestSuite : public testSuite { public: virtual string suiteName() { return "clientXmlTransportTestSuite"; } virtual void runtests(unsigned int const indentation) { curlTransportTestSuite().run(indentation + 1); libwwwTransportTestSuite().run(indentation + 1); wininetTransportTestSuite().run(indentation + 1); ambivalentHttpTransportTestSuite().run(indentation + 1); pstreamTransportTestSuite().run(indentation + 1); } }; class clientSimpleTestSuite : public testSuite { public: virtual string suiteName() { return "clientSimpleTestSuite"; } virtual void runtests(unsigned int const) { clientSimple clientS0; paramList paramList0; value result0; // These will fail because there's no such server EXPECT_ERROR(clientS0.call("http://mf.comm", "biteme", &result0);); EXPECT_ERROR( clientS0.call("http://mf.comm", "biteme", "s", &result0, "hard"); ); EXPECT_ERROR( clientS0.call("http://mf.comm", "biteme", paramList0, &result0); ); } }; class clientCurlIntTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests interruptibility functions of the combination of a client with Curl transport. We don't have an HTTP server, so we test only superficially. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientCurlIntTestSuite"; } virtual void runtests(unsigned int) { #if MUST_BUILD_CURL_CLIENT clientXmlTransport_curl transportc0; client_xml client0(&transportc0); carriageParm_curl0 carriageParmCurl("http://nosuchserver8677.com"); paramList paramList0; rpcOutcome outcome0; int interruptFlag; client0.setInterrupt(&interruptFlag); interruptFlag = 1; // This fails because the call gets immediately interrupted EXPECT_ERROR( client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); ); interruptFlag = 0; // This fails because server doesn't exist EXPECT_ERROR( client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); ); #endif } }; class clientCurlTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests the combination of a client with Curl transport. We assume Curl transports themselves have already been tested and clients with direct transports have already been tested. We don't have an HTTP server, so we test only superficially. In the future, we could either start a server or use some server that's normally avaailble on the Internet. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientCurlTestSuite"; } virtual void runtests(unsigned int const indentation) { #if MUST_BUILD_CURL_CLIENT clientXmlTransport_curl transportc0; client_xml client0(&transportc0); carriageParm_http0 carriageParmHttp("http://nosuchserver8677.com"); carriageParm_curl0 carriageParmCurl("http://nosuchserver8677.com"); connection connection0(&client0, &carriageParmHttp); paramList paramList0; rpcOutcome outcome0; // This fails because server doesn't exist EXPECT_ERROR( client0.call(&carriageParmHttp, "blowme", paramList0, &outcome0); ); // This fails because server doesn't exist EXPECT_ERROR( client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); ); rpcPtr rpc0P("blowme", paramList0); // This fails because server doesn't exist EXPECT_ERROR(rpc0P->call(&client0, &carriageParmCurl);); rpcPtr rpc1P("blowme", paramList0); // This fails because server doesn't exist EXPECT_ERROR(rpc1P->call(connection0);); rpcPtr rpc2P("blowme", paramList0); // This RPC fails to execute because the server doesn't exist, // But libcurl "starts" it just fine. rpc2P->start(&client0, &carriageParmCurl); transportc0.finishAsync(5000); TEST(rpc2P->isFinished()); TEST(!rpc2P->isSuccessful()); // Because the RPC did not return an XML-RPC failure (because the // server doesn't exist), this throws: EXPECT_ERROR(rpc2P->getFault();); rpcPtr rpc3P("blowme", paramList0); // This RPC fails to execute because the server doesn't exist rpc3P->start(connection0); transportc0.finishAsync(5000); TEST(rpc2P->isFinished()); TEST(!rpc2P->isSuccessful()); clientCurlIntTestSuite().run(indentation+1); #else // This fails because there is no Curl transport in the library. EXPECT_ERROR(clientXmlTransport_curl transportc0;); #endif } }; class carriageParmTestSuite : public testSuite { public: virtual string suiteName() { return "carriageParmTestSuite"; } virtual void runtests(unsigned int) { carriageParm_http0 carriageParm1("http://suckthis.com"); carriageParm_curl0 carriageParm2("http://suckthis.com"); carriageParm_libwww0 carriageParm3("http://suckthis.com"); carriageParm_wininet0 carriageParm4("http://suckthis.com"); carriageParm_http0Ptr carriageParm_http1P( new carriageParm_http0("http://suckthis.com")); carriageParm_http1P->setBasicAuth("bryanh", "12345"); carriageParm_curl0Ptr carriageParm_curl1P( new carriageParm_curl0("http://suckthis.com")); carriageParm_curl1P->setBasicAuth("bryanh", "12345"); carriageParm_curl1P->setUser("bryanh", "12345"); carriageParm_curl1P->allowAuthBasic(); carriageParm_curl1P->disallowAuthBasic(); carriageParm_curl1P->allowAuthDigest(); carriageParm_curl1P->disallowAuthDigest(); carriageParm_curl1P->allowAuthNegotiate(); carriageParm_curl1P->disallowAuthNegotiate(); carriageParm_curl1P->allowAuthNtlm(); carriageParm_curl1P->disallowAuthNtlm(); carriageParm_libwww0Ptr carriageParm_libwww1P( new carriageParm_libwww0("http://suckthis.com")); carriageParm_libwww1P->setUser("bryanh", "12345"); carriageParm_libwww1P->allowAuthBasic(); carriageParm_wininet0Ptr carriageParm_wininet1P( new carriageParm_wininet0("http://suckthis.com")); carriageParm_wininet1P->setUser("bryanh", "12345"); carriageParm_wininet1P->allowAuthBasic(); } }; class clientRpcTestSuite : public testSuite { public: virtual string suiteName() { return "clientRpcTestSuite"; } virtual void runtests(unsigned int) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParm0(&myRegistry); clientXmlTransport_direct transportDirect; client_xml client0(&transportDirect); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); paramList paramListEmpty; { /* Test a successful RPC */ rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); TEST(!rpcSampleAddP->isFinished()); // This fails because RPC has not been executed EXPECT_ERROR(value result(rpcSampleAddP->getResult());); rpcSampleAddP->call(&client0, &carriageParm0); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); // This fails because the RPC succeeded EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault());); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->call(&client0, &carriageParm0);); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->start(&client0, &carriageParm0);); } { /* Test a failed RPC */ rpcPtr const rpcSampleAddP("sample.add", paramListEmpty); rpcSampleAddP->call(&client0, &carriageParm0); TEST(rpcSampleAddP->isFinished()); TEST(!rpcSampleAddP->isSuccessful()); fault const fault0(rpcSampleAddP->getFault()); TEST(fault0.getCode() == fault::CODE_TYPE); // This fails because the RPC failed EXPECT_ERROR(value result(rpcSampleAddP->getResult());); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->call(&client0, &carriageParm0);); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->start(&client0, &carriageParm0);); } { /* Test with a connection */ connection connection0(&client0, &carriageParm0); rpcPtr const rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(connection0); TEST(rpcSampleAddP->isFinished()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } } }; class clientPtrTestSuite : public testSuite { public: virtual string suiteName() { return "clientPtrTestSuite"; } virtual void runtests(unsigned int) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; clientPtr clientP(new client_xml(&transportDirect)); clientPtr client2P(clientP); { clientPtr client3P; client3P = client2P; } rpcOutcome outcome; clientP->call(&carriageParmDirect, "nosuchmethod", paramList(), &outcome); TEST(!outcome.succeeded()); TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); } }; class serverAccessorTestSuite : public testSuite { public: virtual string suiteName() { return "serverAccessorTestSuite"; } virtual void runtests(unsigned int) { clientXmlTransportPtr const transportP(new clientXmlTransport_direct); clientPtr const clientP(new client_xml(transportP)); registry myRegistry; carriageParmPtr const carriageParmP( new carriageParm_direct(&myRegistry)); serverAccessor server1(clientP, carriageParmP); rpcOutcome outcome; server1.call("nosuchmethod", paramList(), &outcome); TEST(!outcome.succeeded()); TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); TEST(outcome.getFault().getDescription().size() > 0); } }; class xmlTestSuite : public testSuite { /*---------------------------------------------------------------------------- This test suite tests the generation an interpretation of XML-RPC XML, by doing RPCs via an XML client and server. Each complete RPC involves generating XML and interpreting it, so this is a handy way to test. A stronger test would be to make an XML transport that actually verifies the XML. We're too lazy for that. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "xmlTestSuite"; } virtual void runtests(unsigned int) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); myRegistry.addMethod("apache", methodPtr(new testApacheDialectMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect, xmlrpc_dialect_apache); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); { rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const result(rpcSampleAddP->getResult()); TEST(static_cast(result) == 12); } paramList paramListApache; paramListApache.add(value_nil()); { rpcPtr rpcApacheP("apache", paramListApache); rpcApacheP->call(&clientDirect, &carriageParmDirect); TEST(rpcApacheP->isFinished()); TEST(rpcApacheP->isSuccessful()); value_i8 const result(rpcApacheP->getResult()); TEST(static_cast(result) == 7ll); } } }; } // unnamed namespace string clientTestSuite::suiteName() { return "clientTestSuite"; } void clientTestSuite::runtests(unsigned int const indentation) { clientDirectTestSuite().run(indentation+1); clientXmlTransportTestSuite().run(indentation+1); carriageParmTestSuite().run(indentation+1); clientCurlTestSuite().run(indentation+1); clientRpcTestSuite().run(indentation+1); clientPtrTestSuite().run(indentation+1); clientSimpleTestSuite().run(indentation+1); serverAccessorTestSuite().run(indentation+1); xmlTestSuite().run(indentation+1); }