initial load of upstream version 1.06.32
[xmlrpc-c] / src / cpp / test / server_abyss.cpp
1 /*=============================================================================
2                                   server_abyss
3 ===============================================================================
4   Test the Abyss server C++ facilities of XML-RPC for C/C++.
5   
6 =============================================================================*/
7 #include <sys/unistd.h>
8 #include <sys/socket.h>
9 #include <arpa/inet.h>
10 #include <errno.h>
11 #include <string>
12 #include <iostream>
13 #include <vector>
14 #include <sstream>
15 #include <memory>
16 #include <time.h>
17 #include <cstring>
18
19 #include "xmlrpc-c/girerr.hpp"
20 using girerr::error;
21 using girerr::throwf;
22 #include "xmlrpc-c/base.hpp"
23 #include "xmlrpc-c/registry.hpp"
24 #include "xmlrpc-c/server_abyss.hpp"
25
26 #include "tools.hpp"
27 #include "server_abyss.hpp"
28
29 using namespace xmlrpc_c;
30 using namespace std;
31
32
33
34 class boundSocket {
35
36 public:
37     boundSocket(short const portNumber) {
38         this->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
39
40         if (this->fd < 0)
41             throwf("socket() failed.  errno=%d (%s)",
42                    errno, strerror(errno));
43         
44         struct sockaddr_in sockAddr;
45         int rc;
46
47         sockAddr.sin_family = AF_INET;
48         sockAddr.sin_port   = htons(portNumber);
49         sockAddr.sin_addr.s_addr = 0;
50
51         rc = bind(this->fd, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
52         
53         if (rc != 0) {
54             close(this->fd);
55             throwf("Couldn't bind.  bind() failed with errno=%d (%s)",
56                    errno, strerror(errno));
57         }
58     }
59
60     ~boundSocket() {
61         close(this->fd);
62     }
63
64     int fd;
65 };
66
67
68
69 class sampleAddMethod : public method {
70 public:
71     sampleAddMethod() {
72         this->_signature = "i:ii";
73         this->_help = "This method adds two integers together";
74     }
75     void
76     execute(xmlrpc_c::paramList const& paramList,
77             value *             const  retvalP) {
78         
79         int const addend(paramList.getInt(0));
80         int const adder(paramList.getInt(1));
81         
82         paramList.verifyEnd(2);
83         
84         *retvalP = value_int(addend + adder);
85     }
86 };
87
88
89
90 class addHandlerTestSuite : public testSuite {
91
92 public:
93     virtual string suiteName() {
94         return "addHandlerTestSuite";
95     }
96     virtual void runtests(unsigned int) {
97         TServer abyssServer;
98
99         ServerCreate(&abyssServer, "testserver", 8080, NULL, NULL);
100
101         registry myRegistry;
102         
103         myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
104         
105         registryPtr myRegistryP(new registry);
106         
107         myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod));
108
109         server_abyss_set_handlers(&abyssServer, myRegistry);
110
111         server_abyss_set_handlers(&abyssServer, &myRegistry);
112         
113         server_abyss_set_handlers(&abyssServer, myRegistryP);
114
115         server_abyss_set_handlers(&abyssServer, myRegistry, "/RPC3");
116
117         server_abyss_set_handlers(&abyssServer, &myRegistry, "/RPC3");
118         
119         server_abyss_set_handlers(&abyssServer, myRegistryP, "/RPC3");
120
121         ServerFree(&abyssServer);
122     }
123 };
124
125
126
127 string
128 serverAbyssTestSuite::suiteName() {
129     return "serverAbyssTestSuite";
130 }
131
132
133 void
134 serverAbyssTestSuite::runtests(unsigned int const indentation) {
135
136     addHandlerTestSuite().run(indentation+1);
137
138     registry myRegistry;
139         
140     myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod));
141
142     registryPtr myRegistryP(new registry);
143
144     myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod));
145
146     EXPECT_ERROR(  // No registry
147         serverAbyss::constrOpt opt;
148         serverAbyss abyssServer(opt);
149         );
150     EXPECT_ERROR(  // Both portNumber and socketFd
151         serverAbyss abyssServer(serverAbyss::constrOpt()
152                                 .portNumber(8080)
153                                 .socketFd(3));
154         );
155
156     // Due to the vagaries of Abyss, construction of the following
157     // objects may exit the program if it detects an error, such as
158     // port number already in use.  We need to fix Abyss some day.
159
160     {
161         serverAbyss abyssServer(serverAbyss::constrOpt()
162                                 .registryP(&myRegistry)
163                                 .portNumber(12345)
164             );
165     }
166     {
167         serverAbyss abyssServer(serverAbyss::constrOpt()
168                                 .registryPtr(myRegistryP)
169                                 .portNumber(12345)
170             );
171
172         EXPECT_ERROR(  // Both registryP and registryPtr
173             serverAbyss abyssServer(serverAbyss::constrOpt()
174                                     .registryPtr(myRegistryP)
175                                     .registryP(&myRegistry)
176                                     .portNumber(12345)
177                 );
178             );
179     }
180     {
181         boundSocket socket(12345);
182         
183         serverAbyss abyssServer(serverAbyss::constrOpt()
184                                 .registryP(&myRegistry)
185                                 .socketFd(socket.fd)
186             );
187     }
188     {
189         serverAbyss abyssServer(serverAbyss::constrOpt()
190                                 .registryP(&myRegistry)
191             );
192     }
193
194     {
195         // Test all the options
196         serverAbyss abyssServer(serverAbyss::constrOpt()
197                                 .registryPtr(myRegistryP)
198                                 .portNumber(12345)
199                                 .logFileName("/tmp/logfile")
200                                 .keepaliveTimeout(5)
201                                 .keepaliveMaxConn(4)
202                                 .timeout(20)
203                                 .dontAdvertise(true)
204                                 .uriPath("/xmlrpc")
205             );
206
207     }
208     {
209         serverAbyss abyssServer(
210             myRegistry,
211             12345,              // TCP port on which to listen
212             "/tmp/xmlrpc_log"  // Log file
213             );
214     }
215 }