Migrate from cppunit to Boost.test
[libt2n] / test / reentrant.cpp
1 /*
2 Copyright (C) 2004 by Intra2net AG
3
4 The software in this package is distributed under the GNU General
5 Public License version 2 (with a special exception described below).
6
7 A copy of GNU General Public License (GPL) is included in this distribution,
8 in the file COPYING.GPL.
9
10 As a special exception, if other files instantiate templates or use macros
11 or inline functions from this file, or you compile this file and link it
12 with other works to produce a work based on this file, this file
13 does not by itself cause the resulting work to be covered
14 by the GNU General Public License.
15
16 However the source code for this file must still be made available
17 in accordance with section (3) of the GNU General Public License.
18
19 This exception does not invalidate any other reasons why a work based
20 on this file might be covered by the GNU General Public License.
21 */
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <stdio.h>
27
28 #include <iostream>
29 #include <string>
30 #include <sstream>
31 #include <stdexcept>
32
33 #define BOOST_TEST_DYN_LINK
34 #include <boost/test/unit_test.hpp>
35
36 #include <boost/archive/binary_oarchive.hpp>
37 #include <boost/archive/binary_iarchive.hpp>
38 #include <boost/archive/xml_oarchive.hpp>
39 #include <boost/archive/xml_iarchive.hpp>
40 #include <boost/serialization/serialization.hpp>
41
42 #include <container.hxx>
43 #include <socket_client.hxx>
44 #include <socket_server.hxx>
45 #include <command_client.hxx>
46 #include <command_server.hxx>
47
48 using namespace std;
49 using namespace libt2n;
50
51 namespace reentrant
52 {
53
54 command_server *global_server = NULL;
55
56 int fork_count = 3;
57 int requests_per_child = 100;
58 int all_requests = (2 << (fork_count-1)) * requests_per_child;
59
60 int seen_client_requests = 0;
61
62 string testfunc(const string& str)
63 {
64     string ret;
65     ret=str+", testfunc() was here";
66
67     // call handle, eventually reentrant
68     if (global_server)
69         global_server->handle(10000);
70
71     ++seen_client_requests;
72
73     return ret;
74 }
75
76 class testfunc_res : public libt2n::result
77 {
78     private:
79         string res;
80
81         friend class boost::serialization::access;
82         template<class Archive>
83         void serialize(Archive & ar, const unsigned int version)
84         {
85             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
86             ar & BOOST_SERIALIZATION_NVP(res);
87         }
88
89     public:
90         testfunc_res()
91             {
92             }
93
94         testfunc_res(const string& str)
95         {
96             res=str;
97         }
98
99         string get_data()
100         {
101             return res;
102         }
103 };
104
105
106 class testfunc_cmd : public libt2n::command
107 {
108     private:
109         string param;
110
111         friend class boost::serialization::access;
112         template<class Archive>
113         void serialize(Archive & ar, const unsigned int version)
114         {
115             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
116             ar & BOOST_SERIALIZATION_NVP(param);
117         }
118
119     public:
120         testfunc_cmd()
121             {
122             }
123
124         testfunc_cmd(const string& str)
125         {
126             param=str;
127         }
128
129         libt2n::result* operator()()
130         {
131             return new testfunc_res(testfunc(param));
132         }
133 };
134
135 }
136
137
138 #include <boost/serialization/export.hpp>
139
140 BOOST_CLASS_EXPORT(reentrant::testfunc_cmd)
141 BOOST_CLASS_EXPORT(reentrant::testfunc_res)
142
143 using namespace reentrant;
144
145 BOOST_AUTO_TEST_SUITE(test_reentrant)
146
147 BOOST_AUTO_TEST_CASE(ReentrantServer)
148 {
149     switch(fork())
150     {
151         case -1:
152         {
153             BOOST_FAIL("fork error");
154             break;
155         }
156         case 0:
157         // child
158         {
159             // wait till server is up
160             sleep(2);
161
162             // hammer the server
163             for (int i = 0; i < fork_count; i++)
164                 fork();
165
166             try
167             {
168                 for (int i=0; i < requests_per_child; i++)
169                 {
170                     socket_client_connection sc("./socket");
171                     // sc.set_logging(&cerr,debug);
172                     command_client cc(&sc);
173
174                     result_container rc;
175                     cc.send_command(new testfunc_cmd("hello"),rc);
176
177                     testfunc_res *res = dynamic_cast<testfunc_res*>(rc.get_result());
178                     if (res)
179                     {
180                         string ret = res->get_data();
181                         if (ret != "hello, testfunc() was here")
182                             std::cout << "ERROR reentrant server testfunc_res failed, res: \"" << ret << "\"\n";
183                     }
184                     else
185                     {
186                         std::cout << "ERROR result from reentrant server empty (" << rc.get_result() << ")\n";
187                     }
188                 }
189             } catch (exception &e)
190             {
191                 cerr << "caught exception: " << e.what() << endl;
192             } catch(...)
193             {
194                 std::cerr << "exception in child. ignoring\n";
195             }
196
197             // don't call atexit and stuff
198             _exit(0);
199         }
200
201         default:
202         // parent
203         {
204             // don't kill us on broken pipe
205             signal(SIGPIPE, SIG_IGN);
206
207             socket_server ss("./socket");
208             command_server cs(ss);
209
210             global_server=&cs;
211
212             // Wait until all requests have successed
213             int safety_check = 0;
214             while (seen_client_requests < all_requests)
215             {
216                 ++safety_check;
217                 if (safety_check > 10) {
218                     std::cerr << "reached safety check, aborting.\n";
219                     break;
220                 }
221
222                 long long maxtime=1000000;
223                 while(maxtime > 0)
224                     cs.handle(maxtime,&maxtime);
225             }
226
227             global_server = NULL;
228         }
229
230         // we are still alive, everything is ok
231         BOOST_CHECK_EQUAL(all_requests, seen_client_requests);
232     }
233 }
234
235 BOOST_AUTO_TEST_SUITE_END()