libt2n: (tomj) added exception handling to every child after fork(). This is needed...
[libt2n] / test / cmdgroup.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 #include <boost/serialization/export.hpp>
28
29 #include <container.hxx>
30 #include <socket_client.hxx>
31 #include <socket_server.hxx>
32 #include <command_client.hxx>
33 #include <command_server.hxx>
34
35 using namespace std;
36 using namespace CppUnit;
37 using namespace libt2n;
38
39 string testfunc4(const string& str)
40 {
41     if (str=="throw")
42         throw libt2n::t2n_runtime_error("throw me around");
43     string ret(str);
44     ret+=", testfunc() was here";
45     return ret;
46 }
47
48 class testfunc4_res : public libt2n::result
49 {
50     private:
51         string res;
52
53         friend class boost::serialization::access;
54         template<class Archive>
55         void serialize(Archive & ar, const unsigned int version)
56         {
57             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
58             ar & BOOST_SERIALIZATION_NVP(res);
59         }
60
61     public:
62         testfunc4_res()
63             { }
64
65         testfunc4_res(const string& str)
66         {
67             res=str;
68         }
69
70         string get_data()
71         {
72             return res;
73         }
74 };
75
76 class cmd_group_a : public command
77 {
78     private:
79         friend class boost::serialization::access;
80         template<class Archive>
81         void serialize(Archive & ar, const unsigned int version)
82         {
83             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
84         }
85 };
86
87 class cmd_group_b : public command
88 {
89     private:
90         friend class boost::serialization::access;
91         template<class Archive>
92         void serialize(Archive & ar, const unsigned int version)
93         {
94             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
95         }
96 };
97
98 class testfunc4a_cmd : public cmd_group_a
99 {
100     private:
101         string param;
102
103         friend class boost::serialization::access;
104         template<class Archive>
105         void serialize(Archive & ar, const unsigned int version)
106         {
107             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(cmd_group_a);
108             ar & BOOST_SERIALIZATION_NVP(param);
109         }
110
111     public:
112         testfunc4a_cmd()
113             { }
114
115         testfunc4a_cmd(const string& str)
116         {
117             param=str;
118         }
119
120         libt2n::result* operator()()
121         {
122             return new testfunc4_res(testfunc4(param));
123         }
124 };
125
126 class testfunc4b_cmd : public cmd_group_b
127 {
128     private:
129         string param;
130
131         friend class boost::serialization::access;
132         template<class Archive>
133         void serialize(Archive & ar, const unsigned int version)
134         {
135             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(cmd_group_b);
136             ar & BOOST_SERIALIZATION_NVP(param);
137         }
138
139     public:
140         testfunc4b_cmd()
141             { }
142
143         testfunc4b_cmd(const string& str)
144         {
145             param=str;
146         }
147
148         libt2n::result* operator()()
149         {
150             return new testfunc4_res(testfunc4(param));
151         }
152 };
153
154
155 BOOST_CLASS_EXPORT(testfunc4_res)
156 BOOST_CLASS_EXPORT(cmd_group_a)
157 BOOST_CLASS_EXPORT(cmd_group_b)
158 BOOST_CLASS_EXPORT(testfunc4a_cmd)
159 BOOST_CLASS_EXPORT(testfunc4b_cmd)
160
161 class test_cmdgroup : public TestFixture
162 {
163     CPPUNIT_TEST_SUITE(test_cmdgroup);
164
165     CPPUNIT_TEST(GroupOk);
166     CPPUNIT_TEST(WrongGroup);
167
168     CPPUNIT_TEST_SUITE_END();
169
170     pid_t child_pid;
171
172     public:
173
174     void setUp()
175     { }
176
177     void tearDown()
178     {
179         // make sure the server-child is dead before the next test runs
180         kill(child_pid,SIGKILL);
181         sleep(1);
182     }
183
184     void GroupOk()
185     {
186         switch(child_pid=fork())
187         {
188             case -1:
189             {
190                 CPPUNIT_FAIL("fork error");
191                 break;
192             }
193             case 0:
194             // child
195             {
196                 try
197                 {
198                     socket_server ss("./socket");
199                     group_command_server<cmd_group_a> cs(ss);
200
201                     // max 10 sec
202                     for (int i=0; i < 10; i++)
203                         cs.handle(1000000);
204                 } catch(...)
205                 {
206                     std::cerr << "exception in child. ignoring\n";
207                 }
208
209                 // don't call atexit and stuff
210                 _exit(0);
211             }
212
213             default:
214             // parent
215             {
216                 // wait till server is up
217                 sleep(1);
218                 socket_client_connection sc("./socket");
219                 command_client cc(&sc);
220
221                 result_container rc;
222                 cc.send_command(new testfunc4a_cmd("hello"),rc);
223
224                 string ret=dynamic_cast<testfunc4_res*>(rc.get_result())->get_data();
225
226                 CPPUNIT_ASSERT_EQUAL(string("hello, testfunc() was here"),ret);
227             }
228         }
229     }
230
231     void WrongGroup()
232     {
233         switch(child_pid=fork())
234         {
235             case -1:
236             {
237                 CPPUNIT_FAIL("fork error");
238                 break;
239             }
240             case 0:
241             // child
242             {
243                 try
244                 {
245                     socket_server ss("./socket");
246                     group_command_server<cmd_group_b> cs(ss);
247
248                     // max 10 sec
249                     for (int i=0; i < 10; i++)
250                         cs.handle(1000000);
251                 } catch(...)
252                 {
253                     std::cerr << "exception in child. ignoring\n";
254                 }
255
256                 // don't call atexit and stuff
257                 _exit(0);
258             }
259
260             default:
261             // parent
262             {
263                 // wait till server is up
264                 sleep(1);
265                 socket_client_connection sc("./socket");
266                 command_client cc(&sc);
267
268                 result_container rc;
269                 cc.send_command(new testfunc4a_cmd("hello"),rc);
270
271                 string ret;
272
273                 try
274                 {
275                     ret=dynamic_cast<testfunc4_res*>(rc.get_result())->get_data();
276                 }
277                 catch(t2n_command_error &e)
278                     { ret=e.what(); }
279                 catch(...)
280                     { throw; }
281
282                 string expected_what="illegal command of type ";
283
284                 CPPUNIT_ASSERT_EQUAL(expected_what,ret.substr(0,expected_what.size()));
285             }
286         }
287     }
288
289 };
290
291 CPPUNIT_TEST_SUITE_REGISTRATION(test_cmdgroup);