1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /* test a C client with a C++ server  (that makes sense...) */
21 
22 #include <signal.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <thrift/protocol/TBinaryProtocol.h>
26 #include <thrift/protocol/TDebugProtocol.h>
27 #include <thrift/server/TSimpleServer.h>
28 #include <thrift/stdcxx.h>
29 #include <thrift/transport/TServerSocket.h>
30 #include "ThriftTest.h"
31 #include "ThriftTest_types.h"
32 
33 #include <iostream>
34 #include <map>
35 #include <set>
36 #include <string>
37 #include <vector>
38 
39 using namespace apache::thrift;
40 using namespace apache::thrift::concurrency;
41 using namespace apache::thrift::protocol;
42 using namespace apache::thrift::server;
43 using namespace apache::thrift::transport;
44 
45 using namespace thrift::test;
46 
47 using std::cout;
48 using std::endl;
49 using std::fixed;
50 using std::make_pair;
51 using std::map;
52 using std::set;
53 using std::string;
54 using std::vector;
55 
56 #define TEST_PORT 9980
57 
58 // Extra functions required for ThriftTest_types to work
59 namespace thrift { namespace test {
60 
operator <(thrift::test::Insanity const & other) const61 bool Insanity::operator<(thrift::test::Insanity const& other) const {
62   using apache::thrift::ThriftDebugString;
63   return ThriftDebugString(*this) < ThriftDebugString(other);
64 }
65 
66 }}
67 
68 class TestHandler : public ThriftTestIf {
69   public:
TestHandler()70   TestHandler() {}
71 
testVoid()72   void testVoid() {
73     cout << "[C -> C++] testVoid()" << endl;
74   }
75 
testString(string & out,const string & thing)76   void testString(string& out, const string &thing) {
77     cout << "[C -> C++] testString(\"" << thing << "\")" << endl;
78     out = thing;
79   }
80 
testBool(const bool thing)81   bool testBool(const bool thing) {
82     cout << "[C -> C++] testBool(" << (thing ? "true" : "false") << ")" << endl;
83     return thing;
84   }
testByte(const int8_t thing)85   int8_t testByte(const int8_t thing) {
86     cout << "[C -> C++] testByte(" << (int)thing << ")" << endl;
87     return thing;
88   }
testI32(const int32_t thing)89   int32_t testI32(const int32_t thing) {
90     cout << "[C -> C++] testI32(" << thing << ")" << endl;
91     return thing;
92   }
93 
testI64(const int64_t thing)94   int64_t testI64(const int64_t thing) {
95     cout << "[C -> C++] testI64(" << thing << ")" << endl;
96     return thing;
97   }
98 
testDouble(const double thing)99   double testDouble(const double thing) {
100     cout.precision(6);
101     cout << "[C -> C++] testDouble(" << fixed << thing << ")" << endl;
102     return thing;
103   }
104 
testBinary(string & out,const string & thing)105   void testBinary(string& out, const string &thing) {
106     cout << "[C -> C++] testBinary(\"" << thing << "\")" << endl;
107     out = thing;
108   }
109 
testStruct(Xtruct & out,const Xtruct & thing)110   void testStruct(Xtruct& out, const Xtruct &thing) {
111     cout << "[C -> C++] testStruct({\"" << thing.string_thing << "\", " << (int)thing.byte_thing << ", " << thing.i32_thing << ", " << thing.i64_thing << "})" << endl;
112     out = thing;
113   }
114 
testNest(Xtruct2 & out,const Xtruct2 & nest)115   void testNest(Xtruct2& out, const Xtruct2& nest) {
116     const Xtruct &thing = nest.struct_thing;
117     cout << "[C -> C++] testNest({" << (int)nest.byte_thing << ", {\"" << thing.string_thing << "\", " << (int)thing.byte_thing << ", " << thing.i32_thing << ", " << thing.i64_thing << "}, " << nest.i32_thing << "})" << endl;
118     out = nest;
119   }
120 
testMap(map<int32_t,int32_t> & out,const map<int32_t,int32_t> & thing)121   void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) {
122     cout << "[C -> C++] testMap({";
123     map<int32_t, int32_t>::const_iterator m_iter;
124     bool first = true;
125     for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
126       if (first) {
127         first = false;
128       } else {
129         cout << ", ";
130       }
131       cout << m_iter->first << " => " << m_iter->second;
132     }
133     cout << "})" << endl;
134     out = thing;
135   }
136 
testStringMap(map<std::string,std::string> & out,const map<std::string,std::string> & thing)137   void testStringMap(map<std::string, std::string> &out, const map<std::string, std::string> &thing) {
138     cout << "[C -> C++] testStringMap({";
139     map<std::string, std::string>::const_iterator m_iter;
140     bool first = true;
141     for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
142       if (first) {
143         first = false;
144       } else {
145         cout << ", ";
146       }
147       cout << "\"" << m_iter->first << "\" => \"" << m_iter->second << "\"";
148     }
149     cout << "})" << endl;
150     out = thing;
151   }
152 
153 
testSet(set<int32_t> & out,const set<int32_t> & thing)154   void testSet(set<int32_t> &out, const set<int32_t> &thing) {
155     cout << "[C -> C++] testSet({";
156     set<int32_t>::const_iterator s_iter;
157     bool first = true;
158     for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) {
159       if (first) {
160         first = false;
161       } else {
162         cout << ", ";
163       }
164       cout << *s_iter;
165     }
166     cout << "})" << endl;
167     out = thing;
168   }
169 
testList(vector<int32_t> & out,const vector<int32_t> & thing)170   void testList(vector<int32_t> &out, const vector<int32_t> &thing) {
171     cout << "[C -> C++] testList({";
172     vector<int32_t>::const_iterator l_iter;
173     bool first = true;
174     for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) {
175       if (first) {
176         first = false;
177       } else {
178         cout << ", ";
179       }
180       cout << *l_iter;
181     }
182     cout << "})" << endl;
183     out = thing;
184   }
185 
testEnum(const Numberz::type thing)186   Numberz::type testEnum(const Numberz::type thing) {
187     cout << "[C -> C++] testEnum(" << thing << ")" << endl;
188     return thing;
189   }
190 
testTypedef(const UserId thing)191   UserId testTypedef(const UserId thing) {
192     cout << "[C -> C++] testTypedef(" << thing << ")" << endl;
193     return thing;  }
194 
testMapMap(map<int32_t,map<int32_t,int32_t>> & mapmap,const int32_t hello)195   void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) {
196     cout << "[C -> C++] testMapMap(" << hello << ")" << endl;
197 
198     map<int32_t,int32_t> pos;
199     map<int32_t,int32_t> neg;
200     for (int i = 1; i < 5; i++) {
201       pos.insert(make_pair(i,i));
202       neg.insert(make_pair(-i,-i));
203     }
204 
205     mapmap.insert(make_pair(4, pos));
206     mapmap.insert(make_pair(-4, neg));
207 
208   }
209 
testInsanity(map<UserId,map<Numberz::type,Insanity>> & insane,const Insanity & argument)210   void testInsanity(map<UserId, map<Numberz::type,Insanity> > &insane, const Insanity &argument) {
211     THRIFT_UNUSED_VARIABLE (argument);
212 
213     cout << "[C -> C++] testInsanity()" << endl;
214 
215     Xtruct hello;
216     hello.string_thing = "Hello2";
217     hello.byte_thing = 2;
218     hello.i32_thing = 2;
219     hello.i64_thing = 2;
220 
221     Xtruct goodbye;
222     goodbye.string_thing = "Goodbye4";
223     goodbye.byte_thing = 4;
224     goodbye.i32_thing = 4;
225     goodbye.i64_thing = 4;
226 
227     Insanity crazy;
228     crazy.userMap.insert(make_pair(Numberz::EIGHT, 8));
229     crazy.xtructs.push_back(goodbye);
230 
231     Insanity looney;
232     crazy.userMap.insert(make_pair(Numberz::FIVE, 5));
233     crazy.xtructs.push_back(hello);
234 
235     map<Numberz::type, Insanity> first_map;
236     map<Numberz::type, Insanity> second_map;
237 
238     first_map.insert(make_pair(Numberz::TWO, crazy));
239     first_map.insert(make_pair(Numberz::THREE, crazy));
240 
241     second_map.insert(make_pair(Numberz::SIX, looney));
242 
243     insane.insert(make_pair(1, first_map));
244     insane.insert(make_pair(2, second_map));
245 
246     cout << "return = {";
247     map<UserId, map<Numberz::type,Insanity> >::const_iterator i_iter;
248     for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
249       cout << i_iter->first << " => {";
250       map<Numberz::type,Insanity>::const_iterator i2_iter;
251       for (i2_iter = i_iter->second.begin();
252            i2_iter != i_iter->second.end();
253            ++i2_iter) {
254         cout << i2_iter->first << " => {";
255         map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
256         map<Numberz::type, UserId>::const_iterator um;
257         cout << "{";
258         for (um = userMap.begin(); um != userMap.end(); ++um) {
259           cout << um->first << " => " << um->second << ", ";
260         }
261         cout << "}, ";
262 
263         vector<Xtruct> xtructs = i2_iter->second.xtructs;
264         vector<Xtruct>::const_iterator x;
265         cout << "{";
266         for (x = xtructs.begin(); x != xtructs.end(); ++x) {
267           cout << "{\"" << x->string_thing << "\", " << (int)x->byte_thing << ", " << x->i32_thing << ", " << x->i64_thing << "}, ";
268         }
269         cout << "}";
270 
271         cout << "}, ";
272       }
273       cout << "}, ";
274     }
275     cout << "}" << endl;
276 
277 
278   }
279 
testMulti(Xtruct & hello,const int8_t arg0,const int32_t arg1,const int64_t arg2,const std::map<int16_t,std::string> & arg3,const Numberz::type arg4,const UserId arg5)280   void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string>  &arg3, const Numberz::type arg4, const UserId arg5) {
281     THRIFT_UNUSED_VARIABLE (arg3);
282     THRIFT_UNUSED_VARIABLE (arg4);
283     THRIFT_UNUSED_VARIABLE (arg5);
284 
285     cout << "[C -> C++] testMulti()" << endl;
286 
287     hello.string_thing = "Hello2";
288     hello.byte_thing = arg0;
289     hello.i32_thing = arg1;
290     hello.i64_thing = (int64_t)arg2;
291   }
292 
testException(const std::string & arg)293   void testException(const std::string &arg)
294     throw(Xception, apache::thrift::TException)
295   {
296     cout << "[C -> C++] testException(" << arg << ")" << endl;
297     if (arg.compare("Xception") == 0) {
298       Xception e;
299       e.errorCode = 1001;
300       e.message = arg;
301       throw e;
302     } else if (arg.compare("ApplicationException") == 0) {
303       apache::thrift::TException e;
304       throw e;
305     } else {
306       Xtruct result;
307       result.string_thing = arg;
308       return;
309     }
310   }
311 
testMultiException(Xtruct & result,const std::string & arg0,const std::string & arg1)312   void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) {
313 
314     cout << "[C -> C++] testMultiException(" << arg0 << ", " << arg1 << ")" << endl;
315 
316     if (arg0.compare("Xception") == 0) {
317       Xception e;
318       e.errorCode = 1001;
319       e.message = "This is an Xception";
320       throw e;
321     } else if (arg0.compare("Xception2") == 0) {
322       Xception2 e;
323       e.errorCode = 2002;
324       e.struct_thing.string_thing = "This is an Xception2";
325       throw e;
326     } else {
327       result.string_thing = arg1;
328       return;
329     }
330   }
331 
testOneway(int sleepFor)332   void testOneway(int sleepFor) {
333     cout << "testOneway(" << sleepFor << "): Sleeping..." << endl;
334     sleep(sleepFor);
335     cout << "testOneway(" << sleepFor << "): done sleeping!" << endl;
336   }
337 };
338 
339 // C CLIENT
340 extern "C" {
341 
342 #undef THRIFT_SOCKET /* from lib/cpp */
343 
344 #include "t_test_thrift_test.h"
345 #include "t_test_thrift_test_types.h"
346 #include <thrift/c_glib/transport/thrift_socket.h>
347 #include <thrift/c_glib/protocol/thrift_protocol.h>
348 #include <thrift/c_glib/protocol/thrift_binary_protocol.h>
349 
350 static void
test_thrift_client(void)351 test_thrift_client (void)
352 {
353   ThriftSocket *tsocket = NULL;
354   ThriftBinaryProtocol *protocol = NULL;
355   TTestThriftTestClient *client = NULL;
356   TTestThriftTestIf *iface = NULL;
357   GError *error = NULL;
358   gchar *string = NULL;
359   gint8 byte = 0;
360   gint16 i16 = 0;
361   gint32 i32 = 0, another_i32 = 56789;
362   gint64 i64 = 0;
363   double dbl = 0.0;
364   TTestXtruct *xtruct_in, *xtruct_out;
365   TTestXtruct2 *xtruct2_in, *xtruct2_out;
366   GHashTable *map_in = NULL, *map_out = NULL;
367   GHashTable *set_in = NULL, *set_out = NULL;
368   GArray *list_in = NULL, *list_out = NULL;
369   TTestNumberz enum_in, enum_out;
370   TTestUserId user_id_in, user_id_out;
371   GHashTable *insanity_in = NULL;
372   TTestXtruct *xtruct1, *xtruct2;
373   TTestInsanity *insanity_out = NULL;
374   TTestXtruct *multi_in = NULL;
375   GHashTable *multi_map_out = NULL;
376   TTestXception *xception = NULL;
377   TTestXception2 *xception2 = NULL;
378 
379 #if (!GLIB_CHECK_VERSION (2, 36, 0))
380   // initialize gobject
381   g_type_init ();
382 #endif
383 
384   // create a C client
385   tsocket = (ThriftSocket *) g_object_new (THRIFT_TYPE_SOCKET,
386                           "hostname", "localhost",
387                           "port", TEST_PORT, NULL);
388   protocol = (ThriftBinaryProtocol *) g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
389                            "transport",
390                            tsocket, NULL);
391   client = (TTestThriftTestClient *) g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT, "input_protocol", protocol, "output_protocol", protocol, NULL);
392   iface = T_TEST_THRIFT_TEST_IF (client);
393 
394   // open and send
395   thrift_transport_open (THRIFT_TRANSPORT(tsocket), NULL);
396 
397   assert (t_test_thrift_test_client_test_void (iface, &error) == TRUE);
398   assert (error == NULL);
399 
400   assert (t_test_thrift_test_client_test_string (iface, &string, "test123", &error) == TRUE);
401   assert (strcmp (string, "test123") == 0);
402   g_free (string);
403   assert (error == NULL);
404 
405   assert (t_test_thrift_test_client_test_byte (iface, &byte, (gint8) 5, &error) == TRUE);
406   assert (byte == 5);
407   assert (error == NULL);
408 
409   assert (t_test_thrift_test_client_test_i32 (iface, &i32, 123, &error) == TRUE);
410   assert (i32 == 123);
411   assert (error == NULL);
412 
413   assert (t_test_thrift_test_client_test_i64 (iface, &i64, 12345, &error) == TRUE);
414   assert (i64 == 12345);
415   assert (error == NULL);
416 
417   assert (t_test_thrift_test_client_test_double (iface, &dbl, 5.6, &error) == TRUE);
418   assert (dbl == 5.6);
419   assert (error == NULL);
420 
421   xtruct_out = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
422   xtruct_out->byte_thing = 1;
423   xtruct_out->__isset_byte_thing = TRUE;
424   xtruct_out->i32_thing = 15;
425   xtruct_out->__isset_i32_thing = TRUE;
426   xtruct_out->i64_thing = 151;
427   xtruct_out->__isset_i64_thing = TRUE;
428   xtruct_out->string_thing = g_strdup ("abc123");
429   xtruct_out->__isset_string_thing = TRUE;
430   xtruct_in = (TTestXtruct *) g_object_new(T_TEST_TYPE_XTRUCT, NULL);
431   assert (t_test_thrift_test_client_test_struct (iface, &xtruct_in, xtruct_out, &error) == TRUE);
432   assert (error == NULL);
433 
434   xtruct2_out = (TTestXtruct2 *) g_object_new (T_TEST_TYPE_XTRUCT2, NULL);
435   xtruct2_out->byte_thing = 1;
436   xtruct2_out->__isset_byte_thing = TRUE;
437   if (xtruct2_out->struct_thing != NULL)
438     g_object_unref(xtruct2_out->struct_thing);
439   xtruct2_out->struct_thing = xtruct_out;
440   xtruct2_out->__isset_struct_thing = TRUE;
441   xtruct2_out->i32_thing = 123;
442   xtruct2_out->__isset_i32_thing = TRUE;
443   xtruct2_in = (TTestXtruct2 *) g_object_new (T_TEST_TYPE_XTRUCT2, NULL);
444   assert (t_test_thrift_test_client_test_nest (iface, &xtruct2_in, xtruct2_out, &error) == TRUE);
445   assert (error == NULL);
446 
447   g_object_unref (xtruct2_out);
448   g_object_unref (xtruct2_in);
449   g_object_unref (xtruct_in);
450 
451   map_out = g_hash_table_new (NULL, NULL);
452   map_in = g_hash_table_new (NULL, NULL);  g_hash_table_insert (map_out, &i32, &i32);
453   assert (t_test_thrift_test_client_test_map (iface, &map_in, map_out, &error) == TRUE);
454   assert (error == NULL);
455   g_hash_table_destroy (map_out);
456   g_hash_table_destroy (map_in);
457 
458   map_out = g_hash_table_new (NULL, NULL);
459   map_in = g_hash_table_new (NULL, NULL);
460   g_hash_table_insert (map_out, g_strdup ("a"), g_strdup ("123"));
461   g_hash_table_insert (map_out, g_strdup ("a b"), g_strdup ("with spaces "));
462   g_hash_table_insert (map_out, g_strdup ("same"), g_strdup ("same"));
463   g_hash_table_insert (map_out, g_strdup ("0"), g_strdup ("numeric key"));
464   assert (t_test_thrift_test_client_test_string_map (iface, &map_in, map_out, &error) == TRUE);
465   assert (error == NULL);
466   g_hash_table_destroy (map_out);
467   g_hash_table_destroy (map_in);
468 
469   set_out = g_hash_table_new (NULL, NULL);
470   set_in = g_hash_table_new (NULL, NULL);
471   g_hash_table_insert (set_out, &i32, &i32);
472   assert (t_test_thrift_test_client_test_set (iface, &set_in, set_out, &error) == TRUE);
473   assert (error == NULL);
474   g_hash_table_destroy (set_out);
475   g_hash_table_destroy (set_in);
476 
477   list_out = g_array_new(TRUE, TRUE, sizeof(gint32));
478   list_in = g_array_new(TRUE, TRUE, sizeof(gint32));
479   another_i32 = 456;
480   g_array_append_val (list_out, i32);
481   g_array_append_val (list_out, another_i32);
482   assert (t_test_thrift_test_client_test_list (iface, &list_in, list_out, &error) == TRUE);
483   assert (error == NULL);
484   g_array_free (list_out, TRUE);
485   g_array_free (list_in, TRUE);
486 
487   enum_out = T_TEST_NUMBERZ_ONE;
488   assert (t_test_thrift_test_client_test_enum (iface, &enum_in, enum_out, &error) == TRUE);
489   assert (enum_in == enum_out);
490   assert (error == NULL);
491 
492   user_id_out = 12345;
493   assert (t_test_thrift_test_client_test_typedef (iface, &user_id_in, user_id_out, &error) == TRUE);
494   assert (user_id_in == user_id_out);
495   assert (error == NULL);
496 
497   map_in = g_hash_table_new (NULL, NULL);
498   assert (t_test_thrift_test_client_test_map_map (iface, &map_in, i32, &error) == TRUE);
499   assert (error == NULL);
500   g_hash_table_destroy (map_in);
501 
502   // insanity
503   insanity_out = (TTestInsanity *) g_object_new (T_TEST_TYPE_INSANITY, NULL);
504   insanity_out->userMap = g_hash_table_new (NULL, NULL);
505   g_hash_table_insert (insanity_out->userMap, GINT_TO_POINTER (enum_out), &user_id_out);
506 
507   xtruct1 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
508   xtruct1->byte_thing = 1;
509   xtruct1->__isset_byte_thing = TRUE;
510   xtruct1->i32_thing = 15;
511   xtruct1->__isset_i32_thing = TRUE;
512   xtruct1->i64_thing = 151;
513   xtruct1->__isset_i64_thing = TRUE;
514   xtruct1->string_thing = g_strdup ("abc123");
515   xtruct1->__isset_string_thing = TRUE;
516   xtruct2 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
517   xtruct2->byte_thing = 1;
518   xtruct2->__isset_byte_thing = TRUE;
519   xtruct2->i32_thing = 15;
520   xtruct2->__isset_i32_thing = TRUE;
521   xtruct2->i64_thing = 151;
522   xtruct2->__isset_i64_thing = TRUE;
523   xtruct2->string_thing = g_strdup ("abc123");
524   xtruct2->__isset_string_thing = TRUE;
525 
526   insanity_in = g_hash_table_new (NULL, NULL);
527   g_ptr_array_add (insanity_out->xtructs, xtruct1);
528   g_ptr_array_add (insanity_out->xtructs, xtruct2);
529   assert (t_test_thrift_test_client_test_insanity (iface, &insanity_in, insanity_out, &error) == TRUE);
530 
531   g_hash_table_unref (insanity_in);
532   g_ptr_array_free (insanity_out->xtructs, TRUE);
533 
534   multi_map_out = g_hash_table_new (NULL, NULL);
535   string = g_strdup ("abc123");
536   g_hash_table_insert (multi_map_out, &i16, string);
537   multi_in = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
538   assert (t_test_thrift_test_client_test_multi (iface, &multi_in, byte, i32, i64, multi_map_out, enum_out, user_id_out, &error) == TRUE);
539   assert (multi_in->i32_thing == i32);
540   assert (multi_in->i64_thing == i64);
541   g_object_unref (multi_in);
542   g_hash_table_unref (multi_map_out);
543   g_free (string);
544 
545   assert (t_test_thrift_test_client_test_exception (iface, "Xception", &xception, &error) == FALSE);
546   assert (xception->errorCode == 1001);
547   g_error_free (error);
548   error = NULL;
549   g_object_unref (xception);
550   xception = NULL;
551 
552   assert (t_test_thrift_test_client_test_exception (iface, "ApplicationException", &xception, &error) == FALSE);
553   g_error_free (error);
554   error = NULL;
555   assert (xception == NULL);
556 
557   assert (t_test_thrift_test_client_test_exception (iface, "Test", &xception, &error) == TRUE);
558   assert (error == NULL);
559 
560   multi_in = (TTestXtruct*) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
561   assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, "Xception", NULL, &xception, &xception2, &error) == FALSE);
562   assert (xception->errorCode == 1001);
563   assert (xception2 == NULL);
564   g_error_free (error);
565   error = NULL;
566   g_object_unref (xception);
567   g_object_unref (multi_in);
568   xception = NULL;
569   multi_in = NULL;
570 
571   multi_in = (TTestXtruct*) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
572   assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, "Xception2", NULL, &xception, &xception2, &error) == FALSE);
573   assert (xception2->errorCode == 2002);
574   assert (xception == NULL);
575   g_error_free (error);
576   error = NULL;
577   g_object_unref (xception2);
578   g_object_unref (multi_in);
579   xception2 = NULL;
580   multi_in = NULL;
581 
582   multi_in = (TTestXtruct*) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
583   assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, NULL , NULL, &xception, &xception2, &error) == TRUE);
584   assert (error == NULL);
585   g_object_unref(multi_in);
586   multi_in = NULL;
587 
588   assert (t_test_thrift_test_client_test_oneway (iface, 1, &error) == TRUE);
589   assert (error == NULL);
590 
591   /* sleep to let the oneway call go through */
592   sleep (5);
593 
594   thrift_transport_close (THRIFT_TRANSPORT(tsocket), NULL);
595   g_object_unref (client);
596   g_object_unref (protocol);
597   g_object_unref (tsocket);
598 }
599 
600 
601 } /* extern "C" */
602 
603 
604 static void
bailout(int signum)605 bailout (int signum)
606 {
607   THRIFT_UNUSED_VARIABLE (signum);
608 
609   exit (1);
610 }
611 
612 int
main(void)613 main (void)
614 {
615   int status;
616   int pid = fork ();
617   assert (pid >= 0);
618 
619   if (pid == 0) /* child */
620   {
621     stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
622     stdcxx::shared_ptr<TestHandler> testHandler(new TestHandler());
623     stdcxx::shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
624     stdcxx::shared_ptr<TServerSocket> serverSocket(new TServerSocket(TEST_PORT));
625     stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
626     TSimpleServer simpleServer(testProcessor, serverSocket, transportFactory, protocolFactory);
627     signal (SIGALRM, bailout);
628     alarm (60);
629     simpleServer.serve();
630   } else {
631     sleep (1);
632     test_thrift_client ();
633     kill (pid, SIGINT);
634     assert (wait (&status) == pid);
635   }
636 
637   return 0;
638 }
639 
640