1 /*=============================================================================
3 ===============================================================================
4 Test the client C++ facilities of XML-RPC for C/C++.
6 Contrary to what you might expect, we use the server facilities too
7 because we test of the client using a simulated server, via the
8 "direct" client XML transport we define herein.
9 =============================================================================*/
17 #include "xmlrpc-c/girerr.hpp"
19 #include "transport_config.h"
20 #include "xmlrpc-c/base.hpp"
21 #include "xmlrpc-c/registry.hpp"
22 #include "xmlrpc-c/client.hpp"
23 #include "xmlrpc-c/client_simple.hpp"
26 #include "testclient.hpp"
28 using namespace xmlrpc_c;
33 class sampleAddMethod : public method {
36 this->_signature = "i:ii";
37 this->_help = "This method adds two integers together";
40 execute(xmlrpc_c::paramList const& paramList,
41 value * const retvalP) {
43 int const addend(paramList.getInt(0));
44 int const adder(paramList.getInt(1));
46 paramList.verifyEnd(2);
48 *retvalP = value_int(addend + adder);
54 class carriageParm_direct : public carriageParm {
56 carriageParm_direct(registry * const registryP) : registryP(registryP) {}
62 class clientXmlTransport_direct : public clientXmlTransport {
66 call(xmlrpc_c::carriageParm * const carriageParmP,
67 string const& callXml,
68 string * const responseXmlP) {
70 carriageParm_direct * const parmP =
71 dynamic_cast<carriageParm_direct *>(carriageParmP);
74 throw(error("Carriage parameter passed to the direct "
75 "transport is not type carriageParm_direct"));
77 parmP->registryP->processCall(callXml, responseXmlP);
83 class clientDirectAsyncTestSuite : public testSuite {
84 /*----------------------------------------------------------------------------
85 See clientDirectTestSuite for a description of how we use a
86 clientXmlTransport_direct object to test client functions.
88 The object of this class tests the async client functions. With
89 clientXmlTransport_direct, these are pretty simple because the
90 transport doesn't even implement an asynchronous interface; it
91 relies on the base class' emulation of start() using call().
93 Some day, we should add true asynchronous capability to
94 clientXmlTransport_direct and really test things.
95 -----------------------------------------------------------------------------*/
97 virtual string suiteName() {
98 return "clientDirectAsyncTestSuite";
100 virtual void runtests(unsigned int const) {
104 myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
106 carriageParm_direct carriageParmDirect(&myRegistry);
107 clientXmlTransport_direct transportDirect;
108 client_xml clientDirect(&transportDirect);
109 paramList paramListSampleAdd1;
110 paramListSampleAdd1.add(value_int(5));
111 paramListSampleAdd1.add(value_int(7));
112 paramList paramListSampleAdd2;
113 paramListSampleAdd2.add(value_int(30));
114 paramListSampleAdd2.add(value_int(-10));
116 rpcPtr const rpcSampleAdd1P("sample.add", paramListSampleAdd1);
117 rpcSampleAdd1P->start(&clientDirect, &carriageParmDirect);
118 rpcPtr const rpcSampleAdd2P("sample.add", paramListSampleAdd2);
119 rpcSampleAdd2P->start(&clientDirect, &carriageParmDirect);
121 TEST(rpcSampleAdd1P->isFinished());
122 TEST(rpcSampleAdd1P->isSuccessful());
123 value_int const result1(rpcSampleAdd1P->getResult());
124 TEST(static_cast<int>(result1) == 12);
126 TEST(rpcSampleAdd2P->isFinished());
127 TEST(rpcSampleAdd1P->isSuccessful());
128 value_int const result2(rpcSampleAdd2P->getResult());
129 TEST(static_cast<int>(result2) == 20);
131 EXPECT_ERROR(clientDirect.finishAsync(timeout()););
132 EXPECT_ERROR(clientDirect.finishAsync(timeout(50)););
138 class clientDirectTestSuite : public testSuite {
139 /*----------------------------------------------------------------------------
140 The object of this class tests the client facilities by using a
141 special client XML transport defined above and an XML-RPC server we
142 build ourselves and run inline. We build the server out of a
143 xmlrpc_c::registry object and our transport just delivers XML
144 directly to the registry object and gets the response XML from it
145 and delivers that back. There's no network or socket or pipeline or
146 anything -- the transport actually executes the XML-RPC method.
147 -----------------------------------------------------------------------------*/
149 virtual string suiteName() {
150 return "clientDirectTestSuite";
152 virtual void runtests(unsigned int const indentation) {
155 myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
157 carriageParm_direct carriageParmDirect(&myRegistry);
158 clientXmlTransport_direct transportDirect;
159 client_xml clientDirect(&transportDirect);
160 paramList paramListSampleAdd;
161 paramListSampleAdd.add(value_int(5));
162 paramListSampleAdd.add(value_int(7));
163 paramList paramListEmpty;
165 /* Test a successful RPC */
166 rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd);
167 rpcSampleAddP->call(&clientDirect, &carriageParmDirect);
168 TEST(rpcSampleAddP->isFinished());
169 TEST(rpcSampleAddP->isSuccessful());
170 value_int const resultDirect(rpcSampleAddP->getResult());
171 TEST(static_cast<int>(resultDirect) == 12);
174 /* Test a failed RPC */
175 rpcPtr const rpcSampleAddP("sample.add", paramListEmpty);
176 rpcSampleAddP->call(&clientDirect, &carriageParmDirect);
177 TEST(rpcSampleAddP->isFinished());
178 TEST(!rpcSampleAddP->isSuccessful());
179 fault const fault0(rpcSampleAddP->getFault());
180 TEST(fault0.getCode() == fault::CODE_TYPE);
184 /* Test with an auto object transport */
185 client_xml clientDirect(
186 clientXmlTransportPtr(new clientXmlTransport_direct));
187 rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd);
188 rpcSampleAddP->call(&clientDirect, &carriageParmDirect);
189 TEST(rpcSampleAddP->isFinished());
190 TEST(rpcSampleAddP->isSuccessful());
191 EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault()););
192 value_int const resultDirect(rpcSampleAddP->getResult());
193 TEST(static_cast<int>(resultDirect) == 12);
196 /* Test with implicit RPC -- success */
198 clientDirect.call(&carriageParmDirect, "sample.add",
199 paramListSampleAdd, &outcome);
200 TEST(outcome.succeeded());
201 value_int const result(outcome.getResult());
202 TEST(static_cast<int>(result) == 12);
205 /* Test with implicit RPC - failure */
207 clientDirect.call(&carriageParmDirect, "nosuchmethod",
208 paramList(), &outcome);
209 TEST(!outcome.succeeded());
210 TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD);
211 TEST(outcome.getFault().getDescription().size() > 0);
214 clientDirectAsyncTestSuite().run(indentation+1);
220 class curlTransportTestSuite : public testSuite {
223 virtual string suiteName() {
224 return "curlTransportTestSuite";
226 virtual void runtests(unsigned int const) {
227 #if MUST_BUILD_CURL_CLIENT
228 clientXmlTransport_curl transport0;
229 clientXmlTransport_curl transport1("eth0");
230 clientXmlTransport_curl transport2("eth0", true);
231 clientXmlTransport_curl transport3("eth0", true, true);
232 clientXmlTransport_curl transport4(
233 clientXmlTransport_curl::constrOpt()
234 .network_interface("eth0")
235 .no_ssl_verifypeer(true)
236 .no_ssl_verifyhost(true)
237 .user_agent("my user agent")
238 .ssl_cert("/etc/sslcert")
240 .sslcertpasswd("mypass")
241 .sslkey("/etc/sslkey")
243 .sslkeypasswd("mykeypass")
244 .sslengine("mysslengine")
245 .sslengine_default(true)
246 .sslversion(XMLRPC_SSLVERSION_SSLv2)
247 .cainfo("/etc/cainfo")
248 .capath("/etc/cadir")
249 .randomfile("/dev/random")
250 .egdsocket("/tmp/egdsocket")
251 .ssl_cipher_list("RC4-SHA:DEFAULT")
254 clientXmlTransport_curl transport5(
255 clientXmlTransport_curl::constrOpt()
256 .no_ssl_verifypeer(false));
258 clientXmlTransport_curl transport6(
259 clientXmlTransport_curl::constrOpt());
261 clientXmlTransportPtr transport1P(new clientXmlTransport_curl);
262 clientXmlTransportPtr transport2P;
263 transport2P = transport1P;
265 EXPECT_ERROR(clientXmlTransport_curl transport0;);
266 EXPECT_ERROR(clientXmlTransport_curl transport1("eth0"););
267 EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true););
268 EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true, true););
275 class libwwwTransportTestSuite : public testSuite {
278 virtual string suiteName() {
279 return "libwwwTransportTestSuite";
281 virtual void runtests(unsigned int const) {
282 #if MUST_BUILD_LIBWWW_CLIENT
283 clientXmlTransport_libwww transport0;
284 clientXmlTransport_libwww transport1("getbent");
285 clientXmlTransport_libwww transport2("getbent", "1.0");
286 clientXmlTransportPtr transport1P(new clientXmlTransport_libwww);
287 clientXmlTransportPtr transport2P;
288 transport2P = transport1P;
290 EXPECT_ERROR(clientXmlTransport_libwww transport0;);
291 EXPECT_ERROR(clientXmlTransport_libwww transport1("getbent"););
292 EXPECT_ERROR(clientXmlTransport_libwww transport2("getbent", "1.0"););
299 class wininetTransportTestSuite : public testSuite {
302 virtual string suiteName() {
303 return "wininetTransportTestSuite";
305 virtual void runtests(unsigned int const) {
306 #if MUST_BUILD_WININET_CLIENT
307 clientXmlTransport_wininet transport0;
308 clientXmlTransport_wininet transport1(true);
309 clientXmlTransportPtr transport1P(new clientXmlTransport_wininet);
310 clientXmlTransportPtr transport2P;
311 transport2P = transport1P;
313 EXPECT_ERROR(clientXmlTransport_wininet transport0;);
314 EXPECT_ERROR(clientXmlTransport_wininet transport1(true););
321 class ambivalentTransportTestSuite : public testSuite {
324 virtual string suiteName() {
325 return "ambivalentTransportTestSuite";
327 virtual void runtests(unsigned int const) {
328 vector<string> const typeList(
329 clientXmlTransport_http::availableTypes());
331 TEST(typeList.size() > 0);
333 clientXmlTransportPtr const transportP(
334 clientXmlTransport_http::create());
335 carriageParm_http0 carriageParm0("http://whatsamatta.edux");
336 client_xml client0(transportP);
340 // Fails because there's no such server
342 client0.call(&carriageParm0, "nosuchmethod", paramList(),
350 class clientXmlTransportTestSuite : public testSuite {
353 virtual string suiteName() {
354 return "clientXmlTransportTestSuite";
356 virtual void runtests(unsigned int const indentation) {
357 curlTransportTestSuite().run(indentation + 1);
358 libwwwTransportTestSuite().run(indentation + 1);
359 wininetTransportTestSuite().run(indentation + 1);
360 ambivalentTransportTestSuite().run(indentation + 1);
366 class clientSimpleTestSuite : public testSuite {
369 virtual string suiteName() {
370 return "clientSimpleTestSuite";
372 virtual void runtests(unsigned int const) {
374 clientSimple clientS0;
375 paramList paramList0;
379 // These will fail because there's no such server
380 EXPECT_ERROR(clientS0.call("http://mf.comm", "biteme", &result0););
383 clientS0.call("http://mf.comm", "biteme", "s", &result0, "hard");
387 clientS0.call("http://mf.comm", "biteme", paramList0, &result0);
394 class clientCurlTestSuite : public testSuite {
395 /*----------------------------------------------------------------------------
396 The object of this class tests the combination of a client with
397 Curl transport. We assume Curl transports themselves have already
398 been tested and clients with direct transports have already been tested.
400 We don't have an HTTP server, so we test only superficially.
402 In the future, we could either start a server or use some server that's
403 normally avaailble on the Internet.
404 -----------------------------------------------------------------------------*/
406 virtual string suiteName() {
407 return "clientCurlTestSuite";
409 virtual void runtests(unsigned int) {
410 #if MUST_BUILD_CURL_CLIENT
411 clientXmlTransport_curl transportc0;
412 client_xml client0(&transportc0);
413 carriageParm_http0 carriageParmHttp("http://suckthis.com");
414 carriageParm_curl0 carriageParmCurl("http://suckthis.com");
415 connection connection0(&client0, &carriageParmHttp);
416 paramList paramList0;
420 // This fails because server doesn't exist
422 client0.call(&carriageParmHttp, "blowme", paramList0, &outcome0);
425 // This fails because server doesn't exist
427 client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0);
430 rpcPtr rpc0P("blowme", paramList0);
432 // This fails because server doesn't exist
433 EXPECT_ERROR(rpc0P->call(&client0, &carriageParmCurl););
435 rpcPtr rpc1P("blowme", paramList0);
436 // This fails because server doesn't exist
437 EXPECT_ERROR(rpc1P->call(connection0););
440 // This fails because there is no Curl transport in the library.
441 EXPECT_ERROR(clientXmlTransport_curl transportc0;);
448 class carriageParmTestSuite : public testSuite {
451 virtual string suiteName() {
452 return "carriageParmTestSuite";
454 virtual void runtests(unsigned int) {
455 carriageParm_http0 carriageParm1("http://suckthis.com");
456 carriageParm_curl0 carriageParm2("http://suckthis.com");
457 carriageParm_libwww0 carriageParm3("http://suckthis.com");
458 carriageParm_wininet0 carriageParm4("http://suckthis.com");
460 carriageParm_http0Ptr carriageParm_http1P(
461 new carriageParm_http0("http://suckthis.com"));
463 carriageParm_http1P->setBasicAuth("bryanh", "12345");
465 carriageParm_curl0Ptr carriageParm_curl1P(
466 new carriageParm_curl0("http://suckthis.com"));
468 carriageParm_curl1P->setBasicAuth("bryanh", "12345");
470 carriageParm_libwww0Ptr carriageParm_libwww1P(
471 new carriageParm_libwww0("http://suckthis.com"));
473 carriageParm_libwww1P->setBasicAuth("bryanh", "12345");
475 carriageParm_wininet0Ptr carriageParm_wininet1P(
476 new carriageParm_wininet0("http://suckthis.com"));
478 carriageParm_wininet1P->setBasicAuth("bryanh", "12345");
484 class clientRpcTestSuite : public testSuite {
487 virtual string suiteName() {
488 return "clientRpcTestSuite";
490 virtual void runtests(unsigned int) {
494 myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
496 carriageParm_direct carriageParm0(&myRegistry);
497 clientXmlTransport_direct transportDirect;
498 client_xml client0(&transportDirect);
499 paramList paramListSampleAdd;
500 paramListSampleAdd.add(value_int(5));
501 paramListSampleAdd.add(value_int(7));
502 paramList paramListEmpty;
505 /* Test a successful RPC */
506 rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd);
507 TEST(!rpcSampleAddP->isFinished());
508 // This fails because RPC has not been executed
509 EXPECT_ERROR(value result(rpcSampleAddP->getResult()););
511 rpcSampleAddP->call(&client0, &carriageParm0);
513 TEST(rpcSampleAddP->isFinished());
514 TEST(rpcSampleAddP->isSuccessful());
515 value_int const resultDirect(rpcSampleAddP->getResult());
516 TEST(static_cast<int>(resultDirect) == 12);
517 // This fails because the RPC succeeded
518 EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault()););
519 // This fails because the RPC has already been executed
521 rpcSampleAddP->call(&client0, &carriageParm0););
522 // This fails because the RPC has already been executed
524 rpcSampleAddP->start(&client0, &carriageParm0););
527 /* Test a failed RPC */
528 rpcPtr const rpcSampleAddP("sample.add", paramListEmpty);
529 rpcSampleAddP->call(&client0, &carriageParm0);
530 TEST(rpcSampleAddP->isFinished());
531 TEST(!rpcSampleAddP->isSuccessful());
532 fault const fault0(rpcSampleAddP->getFault());
533 TEST(fault0.getCode() == fault::CODE_TYPE);
534 // This fails because the RPC failed
535 EXPECT_ERROR(value result(rpcSampleAddP->getResult()););
536 // This fails because the RPC has already been executed
538 rpcSampleAddP->call(&client0, &carriageParm0););
539 // This fails because the RPC has already been executed
541 rpcSampleAddP->start(&client0, &carriageParm0););
544 /* Test with a connection */
546 connection connection0(&client0, &carriageParm0);
548 rpcPtr const rpcSampleAddP("sample.add", paramListSampleAdd);
550 rpcSampleAddP->call(connection0);
552 TEST(rpcSampleAddP->isFinished());
553 value_int const resultDirect(rpcSampleAddP->getResult());
554 TEST(static_cast<int>(resultDirect) == 12);
561 class clientPtrTestSuite : public testSuite {
564 virtual string suiteName() {
565 return "clientPtrTestSuite";
567 virtual void runtests(unsigned int) {
570 myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
571 carriageParm_direct carriageParmDirect(&myRegistry);
572 clientXmlTransport_direct transportDirect;
574 clientPtr clientP(new client_xml(&transportDirect));
576 clientPtr client2P(clientP);
584 clientP->call(&carriageParmDirect, "nosuchmethod",
585 paramList(), &outcome);
586 TEST(!outcome.succeeded());
587 TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD);
593 class serverAccessorTestSuite : public testSuite {
596 virtual string suiteName() {
597 return "serverAccessorTestSuite";
599 virtual void runtests(unsigned int) {
600 clientXmlTransportPtr const transportP(new clientXmlTransport_direct);
601 clientPtr const clientP(new client_xml(transportP));
603 carriageParmPtr const carriageParmP(
604 new carriageParm_direct(&myRegistry));
606 serverAccessor server1(clientP, carriageParmP);
609 server1.call("nosuchmethod", paramList(), &outcome);
610 TEST(!outcome.succeeded());
611 TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD);
612 TEST(outcome.getFault().getDescription().size() > 0);
619 clientTestSuite::suiteName() {
620 return "clientTestSuite";
626 clientTestSuite::runtests(unsigned int const indentation) {
628 clientDirectTestSuite().run(indentation+1);
630 clientXmlTransportTestSuite().run(indentation+1);
632 carriageParmTestSuite().run(indentation+1);
634 clientCurlTestSuite().run(indentation+1);
636 clientRpcTestSuite().run(indentation+1);
638 clientPtrTestSuite().run(indentation+1);
640 clientSimpleTestSuite().run(indentation+1);
642 serverAccessorTestSuite().run(indentation+1);