libt2n: (reinhard) 1 Million is not enough! (+ doc fix)
[libt2n] / test / reentrant.cpp
1 /***************************************************************************
2  *   Copyright (C) 2004 by Intra2net AG                                    *
3  *   info@intra2net.com                                                    *
4  *                                                                         *
5  ***************************************************************************/
6
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <stdio.h>
12
13 #include <iostream>
14 #include <string>
15 #include <sstream>
16 #include <stdexcept>
17
18 #include <cppunit/extensions/TestFactoryRegistry.h>
19 #include <cppunit/ui/text/TestRunner.h>
20 #include <cppunit/extensions/HelperMacros.h>
21
22 #include <boost/archive/binary_oarchive.hpp>
23 #include <boost/archive/binary_iarchive.hpp>
24 #include <boost/archive/xml_oarchive.hpp>
25 #include <boost/archive/xml_iarchive.hpp>
26 #include <boost/serialization/serialization.hpp>
27
28 #include <container.hxx>
29 #include <socket_client.hxx>
30 #include <socket_server.hxx>
31 #include <command_client.hxx>
32 #include <command_server.hxx>
33
34 using namespace std;
35 using namespace CppUnit;
36 using namespace libt2n;
37
38 namespace
39 {
40
41 command_server *global_server;
42
43 string testfunc(const string& str)
44 {
45     string ret;
46     ret=str+", testfunc() was here";
47
48     // call handle, eventually reentrant
49     global_server->handle(1000);
50
51     return ret;
52 }
53
54 class testfunc_res : public libt2n::result
55 {
56     private:
57         string res;
58
59         friend class boost::serialization::access;
60         template<class Archive>
61         void serialize(Archive & ar, const unsigned int version)
62         {
63             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
64             ar & BOOST_SERIALIZATION_NVP(res);
65         }
66
67     public:
68         testfunc_res()
69             { }
70
71         testfunc_res(const string& str)
72         {
73             res=str;
74         }
75
76         string get_data()
77         {
78             return res;
79         }
80 };
81
82
83 class testfunc_cmd : public libt2n::command
84 {
85     private:
86         string param;
87
88         friend class boost::serialization::access;
89         template<class Archive>
90         void serialize(Archive & ar, const unsigned int version)
91         {
92             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
93             ar & BOOST_SERIALIZATION_NVP(param);
94         }
95
96     public:
97         testfunc_cmd()
98             { }
99
100         testfunc_cmd(const string& str)
101         {
102             param=str;
103         }
104
105         libt2n::result* operator()()
106         {
107             return new testfunc_res(testfunc(param));
108         }
109 };
110
111 }
112
113 #include <boost/serialization/export.hpp>
114
115 BOOST_CLASS_EXPORT(testfunc_cmd)
116 BOOST_CLASS_EXPORT(testfunc_res)
117
118 class test_reentrant : public TestFixture
119 {
120     CPPUNIT_TEST_SUITE(test_reentrant);
121
122     CPPUNIT_TEST(ReentrantServer);
123
124     CPPUNIT_TEST_SUITE_END();
125
126     pid_t child_pid;
127
128     public:
129
130     void setUp()
131     { }
132
133     void tearDown()
134     { }
135
136     void ReentrantServer()
137     {
138         switch(child_pid=fork())
139         {
140             case -1:
141             {
142                 CPPUNIT_FAIL("fork error");
143                 break;
144             }
145             case 0:
146             // child
147             {
148                 // wait till server is up
149                 sleep(1);
150
151                 // we want 8 identical childs hammering the server
152                 fork();
153                 fork();
154                 fork();
155
156                 for (int i=0; i < 100; i++)
157                 {
158                     socket_client_connection sc("./socket");
159                     command_client cc(&sc);
160
161                     result_container rc;
162                     cc.send_command(new testfunc_cmd("hello"),rc);
163
164                     string ret=dynamic_cast<testfunc_res*>(rc.get_result())->get_data();
165
166                     CPPUNIT_ASSERT_EQUAL(string("hello, testfunc() was here"),ret);
167                 }
168
169                 // don't call atexit and stuff
170                 _exit(0);
171             }
172
173             default:
174             // parent
175             {
176                 socket_server ss("./socket");
177                 command_server cs(ss);
178
179                 global_server=&cs;
180
181                 // max 10 sec
182                 long long maxtime=5000000;
183                 while(maxtime > 0)
184                     cs.handle(maxtime,&maxtime);
185             }
186
187             // we are still alive, everything is ok
188             CPPUNIT_ASSERT_EQUAL(1,1);
189         }
190     }
191
192 };
193
194
195 CPPUNIT_TEST_SUITE_REGISTRATION(test_reentrant);