c08df62681782611bb14cadcf4950e6ecffafa20
[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 = NULL;
42
43 string testfunc(const string& str)
44 {
45     string ret;
46     ret=str+", testfunc() was here";
47
48     // call handle, eventually reentrant
49     if (global_server)
50         global_server->handle(1000);
51
52     return ret;
53 }
54
55 class testfunc_res : public libt2n::result
56 {
57     private:
58         string res;
59
60         friend class boost::serialization::access;
61         template<class Archive>
62         void serialize(Archive & ar, const unsigned int version)
63         {
64             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
65             ar & BOOST_SERIALIZATION_NVP(res);
66         }
67
68     public:
69         testfunc_res()
70             { }
71
72         testfunc_res(const string& str)
73         {
74             res=str;
75         }
76
77         string get_data()
78         {
79             return res;
80         }
81 };
82
83
84 class testfunc_cmd : public libt2n::command
85 {
86     private:
87         string param;
88
89         friend class boost::serialization::access;
90         template<class Archive>
91         void serialize(Archive & ar, const unsigned int version)
92         {
93             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
94             ar & BOOST_SERIALIZATION_NVP(param);
95         }
96
97     public:
98         testfunc_cmd()
99             { }
100
101         testfunc_cmd(const string& str)
102         {
103             param=str;
104         }
105
106         libt2n::result* operator()()
107         {
108             return new testfunc_res(testfunc(param));
109         }
110 };
111
112 }
113
114 #include <boost/serialization/export.hpp>
115
116 BOOST_CLASS_EXPORT(testfunc_cmd)
117 BOOST_CLASS_EXPORT(testfunc_res)
118
119 class test_reentrant : public TestFixture
120 {
121     CPPUNIT_TEST_SUITE(test_reentrant);
122
123     CPPUNIT_TEST(ReentrantServer);
124
125     CPPUNIT_TEST_SUITE_END();
126
127     pid_t child_pid;
128
129     public:
130
131     void setUp()
132     { }
133
134     void tearDown()
135     { }
136
137     void ReentrantServer()
138     {
139         switch(child_pid=fork())
140         {
141             case -1:
142             {
143                 CPPUNIT_FAIL("fork error");
144                 break;
145             }
146             case 0:
147             // child
148             {
149                 // wait till server is up
150                 sleep(3);
151
152                 // we want 8 identical childs hammering the server
153                 fork();
154                 fork();
155                 fork();
156
157                 for (int i=0; i < 100; i++)
158                 {
159                     socket_client_connection sc("./socket");
160                     command_client cc(&sc);
161
162                     result_container rc;
163                     cc.send_command(new testfunc_cmd("hello"),rc);
164
165                     string ret=dynamic_cast<testfunc_res*>(rc.get_result())->get_data();
166
167                     CPPUNIT_ASSERT_EQUAL(string("hello, testfunc() was here"),ret);
168                 }
169
170                 // don't call atexit and stuff
171                 _exit(0);
172             }
173
174             default:
175             // parent
176             {
177                 socket_server ss("./socket");
178                 command_server cs(ss);
179
180                 global_server=&cs;
181
182                 // max 10 sec
183                 long long maxtime=5000000;
184                 while(maxtime > 0)
185                     cs.handle(maxtime,&maxtime);
186                     
187                 global_server = NULL;
188             }
189
190             // we are still alive, everything is ok
191             CPPUNIT_ASSERT_EQUAL(1,1);
192         }
193     }
194
195 };
196
197
198 CPPUNIT_TEST_SUITE_REGISTRATION(test_reentrant);