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