initial load of upstream version 1.06.32
[xmlrpc-c] / src / cpp / test / testclient.cpp
1 /*=============================================================================
2                                   testclient
3 ===============================================================================
4   Test the client C++ facilities of XML-RPC for C/C++.
5   
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 =============================================================================*/
10 #include <string>
11 #include <iostream>
12 #include <vector>
13 #include <sstream>
14 #include <memory>
15 #include <time.h>
16
17 #include "xmlrpc-c/girerr.hpp"
18 using girerr::error;
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"
24
25 #include "tools.hpp"
26 #include "testclient.hpp"
27
28 using namespace xmlrpc_c;
29 using namespace std;
30
31
32
33 class sampleAddMethod : public method {
34 public:
35     sampleAddMethod() {
36         this->_signature = "i:ii";
37         this->_help = "This method adds two integers together";
38     }
39     void
40     execute(xmlrpc_c::paramList const& paramList,
41             value *             const  retvalP) {
42         
43         int const addend(paramList.getInt(0));
44         int const adder(paramList.getInt(1));
45         
46         paramList.verifyEnd(2);
47         
48         *retvalP = value_int(addend + adder);
49     }
50 };
51
52
53
54 class carriageParm_direct : public carriageParm {
55 public:
56     carriageParm_direct(registry * const registryP) : registryP(registryP) {}
57
58     registry * registryP;
59 };
60
61
62 class clientXmlTransport_direct : public clientXmlTransport {
63
64 public:    
65     void
66     call(xmlrpc_c::carriageParm * const  carriageParmP,
67          string                   const& callXml,
68          string *                 const  responseXmlP) {
69
70         carriageParm_direct * const parmP =
71             dynamic_cast<carriageParm_direct *>(carriageParmP);
72
73         if (parmP == NULL)
74             throw(error("Carriage parameter passed to the direct "
75                         "transport is not type carriageParm_direct"));
76
77         parmP->registryP->processCall(callXml, responseXmlP);
78     }
79 };
80
81
82
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.
87
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().
92
93    Some day, we should add true asynchronous capability to
94    clientXmlTransport_direct and really test things.
95 -----------------------------------------------------------------------------*/
96 public:
97     virtual string suiteName() {
98         return "clientDirectAsyncTestSuite";
99     }
100     virtual void runtests(unsigned int const) {
101         
102         registry myRegistry;
103         
104         myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
105         
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));
115
116         rpcPtr const rpcSampleAdd1P("sample.add", paramListSampleAdd1);
117         rpcSampleAdd1P->start(&clientDirect, &carriageParmDirect);
118         rpcPtr const rpcSampleAdd2P("sample.add", paramListSampleAdd2);
119         rpcSampleAdd2P->start(&clientDirect, &carriageParmDirect);
120
121         TEST(rpcSampleAdd1P->isFinished());
122         TEST(rpcSampleAdd1P->isSuccessful());
123         value_int const result1(rpcSampleAdd1P->getResult());
124         TEST(static_cast<int>(result1) == 12);
125         
126         TEST(rpcSampleAdd2P->isFinished());
127         TEST(rpcSampleAdd1P->isSuccessful());
128         value_int const result2(rpcSampleAdd2P->getResult());
129         TEST(static_cast<int>(result2) == 20);
130
131         EXPECT_ERROR(clientDirect.finishAsync(timeout()););
132         EXPECT_ERROR(clientDirect.finishAsync(timeout(50)););
133     }
134 };
135
136
137
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 -----------------------------------------------------------------------------*/
148 public:
149     virtual string suiteName() {
150         return "clientDirectTestSuite";
151     }
152     virtual void runtests(unsigned int const indentation) {
153         registry myRegistry;
154         
155         myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
156         
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;
164         {
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);
172         }
173         {
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);
181         }
182
183         {
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);
194         }
195         {
196             /* Test with implicit RPC -- success */
197             rpcOutcome outcome;
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);
203         }
204         {
205             /* Test with implicit RPC - failure */
206             rpcOutcome outcome;
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);
212         }
213
214         clientDirectAsyncTestSuite().run(indentation+1);
215     }
216 };
217
218
219
220 class curlTransportTestSuite : public testSuite {
221
222 public:
223     virtual string suiteName() {
224         return "curlTransportTestSuite";
225     }
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")
239             .sslcerttype("PEM")
240             .sslcertpasswd("mypass")
241             .sslkey("/etc/sslkey")
242             .sslkeytype("DER")
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")
252             );            
253
254         clientXmlTransport_curl transport5(
255             clientXmlTransport_curl::constrOpt()
256             .no_ssl_verifypeer(false));
257
258         clientXmlTransport_curl transport6(
259             clientXmlTransport_curl::constrOpt());
260         
261         clientXmlTransportPtr transport1P(new clientXmlTransport_curl);
262         clientXmlTransportPtr transport2P;
263         transport2P = transport1P;
264 #else
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););
269 #endif
270     }
271 };
272
273
274
275 class libwwwTransportTestSuite : public testSuite {
276
277 public:
278     virtual string suiteName() {
279         return "libwwwTransportTestSuite";
280     }
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;
289 #else
290         EXPECT_ERROR(clientXmlTransport_libwww transport0;);
291         EXPECT_ERROR(clientXmlTransport_libwww transport1("getbent"););
292         EXPECT_ERROR(clientXmlTransport_libwww transport2("getbent", "1.0"););
293 #endif
294     }
295 };
296
297
298
299 class wininetTransportTestSuite : public testSuite {
300
301 public:
302     virtual string suiteName() {
303         return "wininetTransportTestSuite";
304     }
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;
312 #else
313         EXPECT_ERROR(clientXmlTransport_wininet transport0;);
314         EXPECT_ERROR(clientXmlTransport_wininet transport1(true););
315 #endif
316     }
317 };
318
319
320
321 class ambivalentTransportTestSuite : public testSuite {
322
323 public:
324     virtual string suiteName() {
325         return "ambivalentTransportTestSuite";
326     }
327     virtual void runtests(unsigned int const) {
328         vector<string> const typeList(
329             clientXmlTransport_http::availableTypes());
330
331         TEST(typeList.size() > 0);
332
333         clientXmlTransportPtr const transportP(
334             clientXmlTransport_http::create());
335         carriageParm_http0 carriageParm0("http://whatsamatta.edux");
336         client_xml client0(transportP);
337         
338         rpcOutcome outcome;
339
340         // Fails because there's no such server
341         EXPECT_ERROR(
342             client0.call(&carriageParm0, "nosuchmethod", paramList(),
343                          &outcome);
344             );
345     }
346 };
347
348
349
350 class clientXmlTransportTestSuite : public testSuite {
351
352 public:
353     virtual string suiteName() {
354         return "clientXmlTransportTestSuite";
355     }
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);
361     }
362 };
363
364
365
366 class clientSimpleTestSuite : public testSuite {
367
368 public:
369     virtual string suiteName() {
370         return "clientSimpleTestSuite";
371     }
372     virtual void runtests(unsigned int const) {
373
374         clientSimple clientS0;
375         paramList paramList0;
376
377         value result0;
378
379         // These will fail because there's no such server
380         EXPECT_ERROR(clientS0.call("http://mf.comm", "biteme", &result0););
381
382         EXPECT_ERROR(
383             clientS0.call("http://mf.comm", "biteme", "s", &result0, "hard");
384             );
385
386         EXPECT_ERROR(
387             clientS0.call("http://mf.comm", "biteme", paramList0, &result0);
388             );
389     }
390 };
391         
392
393
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.
399
400   We don't have an HTTP server, so we test only superficially.
401
402   In the future, we could either start a server or use some server that's
403   normally avaailble on the Internet.
404 -----------------------------------------------------------------------------*/
405 public:
406     virtual string suiteName() {
407         return "clientCurlTestSuite";
408     }
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;
417         
418         rpcOutcome outcome0;
419
420         // This fails because server doesn't exist
421         EXPECT_ERROR(
422             client0.call(&carriageParmHttp, "blowme", paramList0, &outcome0);
423                 );
424
425         // This fails because server doesn't exist
426         EXPECT_ERROR(
427             client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0);
428             );
429
430         rpcPtr rpc0P("blowme", paramList0);
431
432         // This fails because server doesn't exist
433         EXPECT_ERROR(rpc0P->call(&client0, &carriageParmCurl););
434
435         rpcPtr rpc1P("blowme", paramList0);
436         // This fails because server doesn't exist
437         EXPECT_ERROR(rpc1P->call(connection0););
438
439 #else
440         // This fails because there is no Curl transport in the library.
441         EXPECT_ERROR(clientXmlTransport_curl transportc0;);
442 #endif
443     }
444 };
445
446
447
448 class carriageParmTestSuite : public testSuite {
449
450 public:
451     virtual string suiteName() {
452         return "carriageParmTestSuite";
453     }
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");
459
460         carriageParm_http0Ptr carriageParm_http1P(
461             new carriageParm_http0("http://suckthis.com"));
462
463         carriageParm_http1P->setBasicAuth("bryanh", "12345");
464
465         carriageParm_curl0Ptr carriageParm_curl1P(
466             new carriageParm_curl0("http://suckthis.com"));
467
468         carriageParm_curl1P->setBasicAuth("bryanh", "12345");
469
470         carriageParm_libwww0Ptr carriageParm_libwww1P(
471             new carriageParm_libwww0("http://suckthis.com"));
472
473         carriageParm_libwww1P->setBasicAuth("bryanh", "12345");
474
475         carriageParm_wininet0Ptr carriageParm_wininet1P(
476             new carriageParm_wininet0("http://suckthis.com"));
477
478         carriageParm_wininet1P->setBasicAuth("bryanh", "12345");
479     }
480 };
481
482
483
484 class clientRpcTestSuite : public testSuite {
485
486 public:
487     virtual string suiteName() {
488         return "clientRpcTestSuite";
489     }
490     virtual void runtests(unsigned int) {
491
492         registry myRegistry;
493         
494         myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
495         
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;
503
504         {
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()););
510             
511             rpcSampleAddP->call(&client0, &carriageParm0);
512
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
520             EXPECT_ERROR(
521                 rpcSampleAddP->call(&client0, &carriageParm0););
522             // This fails because the RPC has already been executed
523             EXPECT_ERROR(
524                 rpcSampleAddP->start(&client0, &carriageParm0););
525         }
526         {
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
537             EXPECT_ERROR(
538                 rpcSampleAddP->call(&client0, &carriageParm0););
539             // This fails because the RPC has already been executed
540             EXPECT_ERROR(
541                 rpcSampleAddP->start(&client0, &carriageParm0););
542         }
543         {
544             /* Test with a connection */
545
546             connection connection0(&client0, &carriageParm0);
547
548             rpcPtr const rpcSampleAddP("sample.add", paramListSampleAdd);
549
550             rpcSampleAddP->call(connection0);
551
552             TEST(rpcSampleAddP->isFinished());
553             value_int const resultDirect(rpcSampleAddP->getResult());
554             TEST(static_cast<int>(resultDirect) == 12);
555         }
556     }
557 };
558
559
560
561 class clientPtrTestSuite : public testSuite {
562
563 public:
564     virtual string suiteName() {
565         return "clientPtrTestSuite";
566     }
567     virtual void runtests(unsigned int) {
568         registry myRegistry;
569         
570         myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
571         carriageParm_direct carriageParmDirect(&myRegistry);
572         clientXmlTransport_direct transportDirect;
573         
574         clientPtr clientP(new client_xml(&transportDirect));
575
576         clientPtr client2P(clientP);
577
578         {
579             clientPtr client3P;
580             client3P = client2P;
581         }
582         rpcOutcome outcome;
583
584         clientP->call(&carriageParmDirect, "nosuchmethod",
585                       paramList(), &outcome);
586         TEST(!outcome.succeeded());
587         TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD);
588     }
589 };
590
591
592
593 class serverAccessorTestSuite : public testSuite {
594
595 public:
596     virtual string suiteName() {
597         return "serverAccessorTestSuite";
598     }
599     virtual void runtests(unsigned int) {
600         clientXmlTransportPtr const transportP(new clientXmlTransport_direct);
601         clientPtr const clientP(new client_xml(transportP));
602         registry myRegistry;
603         carriageParmPtr const carriageParmP(
604             new carriageParm_direct(&myRegistry));
605
606         serverAccessor server1(clientP, carriageParmP);
607
608         rpcOutcome outcome;
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);
613     }
614 };
615
616
617
618 string
619 clientTestSuite::suiteName() {
620     return "clientTestSuite";
621 }
622
623
624
625 void
626 clientTestSuite::runtests(unsigned int const indentation) {
627
628     clientDirectTestSuite().run(indentation+1);
629
630     clientXmlTransportTestSuite().run(indentation+1);
631     
632     carriageParmTestSuite().run(indentation+1);
633     
634     clientCurlTestSuite().run(indentation+1);
635
636     clientRpcTestSuite().run(indentation+1);
637     
638     clientPtrTestSuite().run(indentation+1);
639
640     clientSimpleTestSuite().run(indentation+1);
641
642     serverAccessorTestSuite().run(indentation+1);
643 }