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 #include <glib-object.h>
21 #include <inttypes.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include <sys/time.h>
27 
28 #include <thrift/c_glib/thrift.h>
29 #include <thrift/c_glib/protocol/thrift_binary_protocol.h>
30 #include <thrift/c_glib/protocol/thrift_compact_protocol.h>
31 #include <thrift/c_glib/protocol/thrift_multiplexed_protocol.h>
32 #include <thrift/c_glib/transport/thrift_buffered_transport.h>
33 #include <thrift/c_glib/transport/thrift_framed_transport.h>
34 #include <thrift/c_glib/transport/thrift_ssl_socket.h>
35 #include <thrift/c_glib/transport/thrift_socket.h>
36 #include <thrift/c_glib/transport/thrift_transport.h>
37 
38 #include "../gen-c_glib/t_test_second_service.h"
39 #include "../gen-c_glib/t_test_thrift_test.h"
40 
41 /* Handle SIGPIPE signals (indicating the server has closed the
42    connection prematurely) by outputting an error message before
43    exiting. */
44 static void
sigpipe_handler(int signal_number)45 sigpipe_handler (int signal_number)
46 {
47   THRIFT_UNUSED_VAR (signal_number);
48 
49   /* Flush standard output to make sure the test results so far are
50      logged */
51   fflush (stdout);
52 
53   fputs ("Broken pipe (server closed connection prematurely)\n", stderr);
54   fflush (stderr);
55 
56   /* Re-raise the signal, this time invoking the default signal
57      handler, to terminate the program */
58   raise (SIGPIPE);
59 }
60 
61 /* Compare two gint32 values. Used for sorting and finding integer
62    values within a GList. */
63 static gint
gint32_compare(gconstpointer a,gconstpointer b)64 gint32_compare (gconstpointer a, gconstpointer b)
65 {
66   gint32 int32_a = *(gint32 *)a;
67   gint32 int32_b = *(gint32 *)b;
68   int result = 0;
69 
70   if (int32_a < int32_b)
71     result = -1;
72   else if (int32_a > int32_b)
73     result = 1;
74 
75   return result;
76 }
77 
78 int
main(int argc,char ** argv)79 main (int argc, char **argv)
80 {
81   static gchar *  host = NULL;
82   static gint     port = 9090;
83   static gchar *  path = NULL;
84   static gboolean ssl  = FALSE;
85   static gchar *  transport_option = NULL;
86   static gchar *  protocol_option = NULL;
87   static gint     num_tests = 1;
88 
89   static
90     GOptionEntry option_entries[] ={
91     { "host",            'h', 0, G_OPTION_ARG_STRING,   &host,
92       "Host to connect (=localhost)", NULL },
93     { "port",            'p', 0, G_OPTION_ARG_INT,      &port,
94       "Port number to connect (=9090)", NULL },
95     { "domain-socket",    0, 0, G_OPTION_ARG_STRING,   &path,
96       "Unix socket domain path to connect", NULL },
97     { "ssl",             's', 0, G_OPTION_ARG_NONE,     &ssl,
98       "Enable SSL", NULL },
99     { "transport",       't', 0, G_OPTION_ARG_STRING,   &transport_option,
100       "Transport: buffered, framed (=buffered)", NULL },
101     { "protocol",        'r', 0, G_OPTION_ARG_STRING,   &protocol_option,
102       "Protocol: binary, compact, multi, multic (=binary)", NULL },
103     { "testloops",       'n', 0, G_OPTION_ARG_INT,      &num_tests,
104       "Number of tests (=1)", NULL },
105     { NULL }
106   };
107 
108   struct sigaction sigpipe_action;
109 
110   GType  socket_type    = THRIFT_TYPE_SOCKET;
111   gchar *socket_name    = "ip";
112   GType  transport_type = THRIFT_TYPE_BUFFERED_TRANSPORT;
113   gchar *transport_name = "buffered";
114   GType  protocol_type  = THRIFT_TYPE_BINARY_PROTOCOL;
115   gchar *protocol_name  = "binary";
116 
117   ThriftSocket    *socket = NULL;
118   ThriftTransport *transport = NULL;
119   ThriftProtocol  *protocol = NULL;
120   ThriftProtocol  *protocol2 = NULL;            // for multiplexed tests
121   ThriftProtocol  *multiplexed_protocol = NULL;
122 
123   TTestThriftTestIf *test_client = NULL;
124   TTestSecondServiceIf *second_service = NULL;  // for multiplexed tests
125 
126   struct timeval time_start, time_stop, time_elapsed;
127   guint64 time_elapsed_usec, time_total_usec = 0;
128   guint64 time_min_usec = G_MAXUINT64, time_max_usec = 0, time_avg_usec;
129 
130   GOptionContext *option_context;
131   gboolean options_valid = TRUE;
132   int test_num = 0;
133   int fail_count = 0;
134   GError *error = NULL;
135 
136 #if (!GLIB_CHECK_VERSION (2, 36, 0))
137   g_type_init ();
138 #endif
139 
140   /* Configure and parse our command-line options */
141   option_context = g_option_context_new (NULL);
142   g_option_context_add_main_entries (option_context,
143                                      option_entries,
144                                      NULL);
145   if (!g_option_context_parse (option_context,
146                                &argc,
147                                &argv,
148                                &error)) {
149     fprintf (stderr, "%s\n", error->message);
150     g_clear_error (&error);
151     g_option_context_free (option_context);
152     return 255;
153   }
154   g_option_context_free (option_context);
155 
156   /* Set remaining default values for unspecified options */
157   if (host == NULL)
158     host = g_strdup ("localhost");
159 
160   /* Validate the parsed options */
161   if (protocol_option != NULL) {
162     if (strncmp (protocol_option, "compact", 8) == 0) {
163       protocol_type = THRIFT_TYPE_COMPACT_PROTOCOL;
164       protocol_name = "compact";
165     }
166     else if (strncmp (protocol_option, "multi", 6) == 0) {
167       protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL;
168       protocol_name = "binary:multi";
169     }
170     else if (strncmp (protocol_option, "multic", 7) == 0) {
171       protocol_type = THRIFT_TYPE_MULTIPLEXED_PROTOCOL;
172       protocol_name = "compact:multic";
173     }
174     else if (strncmp (protocol_option, "binary", 7) == 0) {
175       printf("We are going with default protocol\n");
176     }
177     else {
178       fprintf (stderr, "Unknown protocol type %s\n", protocol_option);
179       options_valid = FALSE;
180     }
181   }
182 
183   if (transport_option != NULL) {
184     if (strncmp (transport_option, "framed", 7) == 0) {
185       transport_type = THRIFT_TYPE_FRAMED_TRANSPORT;
186       transport_name = "framed";
187     }
188     else if (strncmp (transport_option, "buffered", 9) != 0) {
189       fprintf (stderr, "Unknown transport type %s\n", transport_option);
190       options_valid = FALSE;
191     }
192   }
193 
194   if (ssl) {
195     socket_type = THRIFT_TYPE_SSL_SOCKET;
196     socket_name = "ip-ssl";
197     printf("Type name %s\n", g_type_name (socket_type));
198   }
199 
200   if (!options_valid)
201     return 254;
202 
203   if (path) {
204     printf ("Connecting (%s/%s) to: %s/%s\n",
205             transport_name,
206             protocol_name,
207             socket_name,
208             path);
209   } else {
210     printf ("Connecting (%s/%s) to: %s/%s:%d\n",
211             transport_name,
212             protocol_name,
213             socket_name,
214             host,
215             port);
216   }
217 
218   /* Install our SIGPIPE handler, which outputs an error message to
219      standard error before exiting so testers can know what
220      happened */
221   memset (&sigpipe_action, 0, sizeof (sigpipe_action));
222   sigpipe_action.sa_handler = sigpipe_handler;
223   sigpipe_action.sa_flags = SA_RESETHAND;
224   sigaction (SIGPIPE, &sigpipe_action, NULL);
225 
226   if (ssl) {
227     thrift_ssl_socket_initialize_openssl();
228   }
229 
230   /* Establish all our connection objects */
231   if (path) {
232     socket = g_object_new (socket_type,
233                            "path", path,
234                            NULL);
235   } else {
236     socket = g_object_new (socket_type,
237                            "hostname", host,
238                            "port",     port,
239                            NULL);
240   }
241 
242   if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) {
243     fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n");
244     g_clear_object (&socket);
245     return 253;
246   }
247 
248   transport = g_object_new (transport_type,
249                             "transport", socket,
250                             NULL);
251 
252   if (protocol_type == THRIFT_TYPE_MULTIPLEXED_PROTOCOL) {
253     // TODO: A multiplexed test should also test "Second" (see Java TestServer)
254     // The context comes from the name of the thrift file. If multiple thrift
255     // schemas are used we have to redo the way this is done.
256     if (strncmp(protocol_name, "binary:", 7) == 0) {
257       multiplexed_protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
258                                            "transport", transport,
259                                            NULL);
260     } else if (strncmp(protocol_name, "compact:", 8) == 0) {
261       multiplexed_protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL,
262                                            "transport", transport,
263                                            NULL);
264     } else {
265       fprintf(stderr, "Unknown multiplex protocol name: %s\n", protocol_name);
266       g_clear_object (&transport);
267       g_clear_object (&socket);
268       return 252;
269     }
270     protocol = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL,
271                              "transport",    transport,
272                              "protocol",     multiplexed_protocol,
273                              "service-name", "ThriftTest",
274                              NULL);;
275     if (NULL == protocol) {
276       g_clear_object (&multiplexed_protocol);
277       g_clear_object (&transport);
278       g_clear_object (&socket);
279       return 251;
280     }
281 
282     // Make a second protocol and client running on the same multiplexed transport
283     protocol2 = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROTOCOL,
284                               "transport",    transport,
285                               "protocol",     multiplexed_protocol,
286                               "service-name", "SecondService",
287                               NULL);
288 
289     second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_CLIENT,
290                                    "input_protocol",  protocol2,
291                                    "output_protocol", protocol2,
292                                    NULL);
293   }else{
294     protocol = g_object_new (protocol_type,
295            "transport", transport,
296            NULL);
297   }
298 
299   test_client = g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT,
300                               "input_protocol",  protocol,
301                               "output_protocol", protocol,
302                               NULL);
303 
304   /* Execute the actual tests */
305   for (test_num = 0; test_num < num_tests; ++test_num) {
306     if (thrift_transport_open (transport, &error)) {
307       gchar   *string  = NULL;
308       gboolean boolean = 0;
309       gint8    byte    = 0;
310       gint32   int32   = 0;
311       gint64   int64   = 0;
312       gdouble  dub     = 0;
313 
314       gint byte_thing, i32_thing, inner_byte_thing, inner_i32_thing;
315       gint64 i64_thing, inner_i64_thing;
316 
317       TTestXtruct  *xtruct_out,  *xtruct_out2, *xtruct_in,  *inner_xtruct_in;
318       TTestXtruct2 *xtruct2_out, *xtruct2_in;
319 
320       GHashTable *map_out, *map_in, *inner_map_in;
321       GHashTable *set_out, *set_in;
322       gpointer key, value;
323       gint32 *i32_key_ptr, *i32_value_ptr;
324       GHashTableIter hash_table_iter, inner_hash_table_iter;
325       GList *keys_out, *keys_in, *keys_elem;
326 
327       GArray *list_out, *list_in;
328 
329       TTestNumberz numberz;
330       TTestNumberz numberz2;
331 
332       TTestUserId user_id, *user_id_ptr, *user_id_ptr2;
333 
334       TTestInsanity *insanity_out, *insanity_in;
335       GHashTable *user_map;
336       GHashTableIter user_map_iter;
337       GPtrArray *xtructs;
338 
339       TTestXception  *xception  = NULL;
340       TTestXception2 *xception2 = NULL;
341 
342       gboolean oneway_result;
343       struct timeval oneway_start, oneway_end, oneway_elapsed;
344       gint oneway_elapsed_usec;
345 
346       gboolean first;
347       gint32 i, j;
348 
349       if (path) {
350         printf ("Test #%d, connect %s\n", test_num + 1, path);
351       } else {
352         printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port);
353       }
354       gettimeofday (&time_start, NULL);
355 
356       /* These test routines have been ported from the C++ test
357          client, care being taken to ensure their output remains as
358          close as possible to the original to facilitate diffs.
359 
360          For simplicity comments have been omitted, but every routine
361          has the same basic structure:
362 
363          - Create and populate data structures as necessary.
364 
365          - Format and output (to the console) a representation of the
366            outgoing data.
367 
368          - Issue the remote method call to the server.
369 
370          - Format and output a representation of the returned data.
371 
372          - Verify the returned data matches what was expected.
373 
374          - Deallocate any created data structures.
375 
376          Note the recognized values and expected behaviour of each
377          remote method are described in ThriftTest.thrift, which
378          you'll find in the top-level "test" folder. */
379 
380       /**
381        * VOID TEST
382        */
383       printf ("testVoid()");
384       if (t_test_thrift_test_if_test_void (test_client, &error)) {
385         printf (" = void\n");
386       }
387       else {
388         if(error!=NULL){
389           printf ("%s\n", error->message);
390           g_error_free (error);
391           error = NULL;
392         }
393         fail_count++;
394       }
395 
396       /**
397        * STRING TEST
398        */
399       printf ("testString(\"Test\")");
400       if (t_test_thrift_test_if_test_string (test_client,
401                                              &string,
402                                              "Test",
403                                              &error)) {
404         printf (" = \"%s\"\n", string);
405         if (strncmp (string, "Test", 5) != 0)
406           fail_count++;
407 
408         g_free (string);
409         string = NULL;
410       }
411       else {
412         printf ("%s\n", error->message);
413         g_error_free (error);
414         error = NULL;
415 
416         fail_count++;
417       }
418 
419       /**
420        * Multiplexed Test - do this right in the middle of the normal Test Client run
421        */
422       if (second_service) {
423         printf ("testSecondServiceMultiplexSecondTestString(\"2nd\")");
424         if (t_test_second_service_if_secondtest_string (second_service,
425                                                         &string,
426                                                         "2nd",
427                                                         &error)) {
428           printf (" = \"%s\"\n", string);
429           if (strcmp (string, "testString(\"2nd\")") != 0) {
430             ++fail_count;
431           }
432 
433           g_free (string);
434           string = NULL;
435         } else {
436           printf ("%s\n", error->message);
437           g_error_free (error);
438           error = NULL;
439 
440           ++fail_count;
441         }
442       }
443 
444       /**
445        * BOOL TEST
446        */
447       printf ("testByte(true)");
448       if (t_test_thrift_test_if_test_bool (test_client,
449                                            &boolean,
450                                            1,
451                                            &error)) {
452         printf (" = %s\n", boolean ? "true" : "false");
453         if (boolean != 1)
454           fail_count++;
455       }
456       else {
457         printf ("%s\n", error->message);
458         g_error_free (error);
459         error = NULL;
460 
461         fail_count++;
462       }
463       printf ("testByte(false)");
464       if (t_test_thrift_test_if_test_bool (test_client,
465                                            &boolean,
466                                            0,
467                                            &error)) {
468         printf (" = %s\n", boolean ? "true" : "false");
469         if (boolean != 0)
470           fail_count++;
471       }
472       else {
473         printf ("%s\n", error->message);
474         g_error_free (error);
475         error = NULL;
476 
477         fail_count++;
478       }
479 
480       /**
481        * BYTE TEST
482        */
483       printf ("testByte(1)");
484       if (t_test_thrift_test_if_test_byte (test_client,
485                                            &byte,
486                                            1,
487                                            &error)) {
488         printf (" = %d\n", byte);
489         if (byte != 1)
490           fail_count++;
491       }
492       else {
493         printf ("%s\n", error->message);
494         g_error_free (error);
495         error = NULL;
496 
497         fail_count++;
498       }
499       printf ("testByte(-1)");
500       if (t_test_thrift_test_if_test_byte (test_client,
501                                            &byte,
502                                            -1,
503                                            &error)) {
504         printf (" = %d\n", byte);
505         if (byte != -1)
506           fail_count++;
507       }
508       else {
509         printf ("%s\n", error->message);
510         g_error_free (error);
511         error = NULL;
512 
513         fail_count++;
514       }
515 
516       /**
517        * I32 TEST
518        */
519       printf ("testI32(-1)");
520       if (t_test_thrift_test_if_test_i32 (test_client,
521                                           &int32,
522                                           -1,
523                                           &error)) {
524         printf (" = %d\n", int32);
525         if (int32 != -1)
526           fail_count++;
527       }
528       else {
529         printf ("%s\n", error->message);
530         g_error_free (error);
531         error = NULL;
532 
533         fail_count++;
534       }
535 
536       /**
537        * I64 TEST
538        */
539       printf ("testI64(-34359738368)");
540       if (t_test_thrift_test_if_test_i64 (test_client,
541                                           &int64,
542                                           (gint64)-34359738368,
543                                           &error)) {
544         printf (" = %" PRId64 "\n", int64);
545         if (int64 != (gint64)-34359738368)
546           fail_count++;
547       }
548       else {
549         printf ("%s\n", error->message);
550         g_error_free (error);
551         error = NULL;
552 
553         fail_count++;
554       }
555 
556       /**
557        * DOUBLE TEST
558        */
559       printf("testDouble(-5.2098523)");
560       if (t_test_thrift_test_if_test_double (test_client,
561                                              &dub,
562                                              -5.2098523,
563                                              &error)) {
564         printf (" = %f\n", dub);
565         if ((dub - (-5.2098523)) > 0.001)
566           fail_count++;
567       }
568       else {
569         printf ("%s\n", error->message);
570         g_error_free (error);
571         error = NULL;
572 
573         fail_count++;
574       }
575 
576       /**
577        * BINARY TEST
578        */
579       printf ("testBinary(empty)");
580       GByteArray *emptyArray = g_byte_array_new();
581       GByteArray *result = NULL;
582       if (t_test_thrift_test_if_test_binary (test_client,
583                                              &result,
584                                              emptyArray,
585                                              &error)) {
586         GBytes *response = g_byte_array_free_to_bytes(result);  // frees result
587         result = NULL;
588         gsize siz = g_bytes_get_size(response);
589         if (siz == 0) {
590           printf(" = empty\n");
591         } else {
592           printf(" = not empty (%ld bytes)\n", (long)siz);
593           ++fail_count;
594         }
595         g_bytes_unref(response);
596       } else {
597         printf ("%s\n", error->message);
598         g_error_free (error);
599         error = NULL;
600 
601         fail_count++;
602       }
603       g_byte_array_unref(emptyArray);
604       emptyArray = NULL;
605 
606       // TODO: add testBinary() with data
607       printf ("testBinary([-128..127]) = {");
608       const signed char bin_data[256]
609         = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114,
610            -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
611            -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84,
612            -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,
613            -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,
614            -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39,
615            -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24,
616            -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9,
617            -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6,
618            7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
619            22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
620            37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
621            52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
622            67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
623            82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96,
624            97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
625            112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
626            127};
627       GByteArray *fullArray = g_byte_array_new();
628       g_byte_array_append(fullArray, (guint8 *)(&bin_data[0]), 256);
629       if (t_test_thrift_test_if_test_binary (test_client,
630                                              &result,
631                                              fullArray,
632                                              &error)) {
633         GBytes *response = g_byte_array_free_to_bytes(result);  // frees result
634         result = NULL;
635         gsize siz = g_bytes_get_size(response);
636         gconstpointer ptr = g_bytes_get_data(response, &siz);
637         if (siz == 256) {
638           gboolean first = 1;
639           gboolean failed = 0;
640           int i;
641 
642           for (i = 0; i < 256; ++i) {
643             if (!first)
644               printf(",");
645             else
646               first = 0;
647             int val = ((signed char *)ptr)[i];
648             printf("%d", val);
649             if (!failed && val != i - 128) {
650               failed = 1;
651             }
652           }
653           printf("} ");
654           if (failed) {
655             printf("FAIL (bad content) size %ld OK\n", (long)siz);
656             ++fail_count;
657           } else {
658             printf("OK size %ld OK\n", (long)siz);
659           }
660         } else {
661           printf(" = bad size %ld\n", (long)siz);
662           ++fail_count;
663         }
664         g_bytes_unref(response);
665       } else {
666         printf ("%s\n", error->message);
667         g_error_free (error);
668         error = NULL;
669 
670         fail_count++;
671       }
672       g_byte_array_unref(fullArray);
673       fullArray = NULL;
674 
675       /**
676        * STRUCT TEST
677        */
678       printf ("testStruct({\"Zero\", 1, -3, -5})");
679       xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT,
680                                  "string_thing", "Zero",
681                                  "byte_thing",        1,
682                                  "i32_thing",        -3,
683                                  "i64_thing",      -5LL,
684                                  NULL);
685       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
686 
687       if (t_test_thrift_test_if_test_struct (test_client,
688                                              &xtruct_in,
689                                              xtruct_out,
690                                              &error)) {
691         g_object_get (xtruct_in,
692                       "string_thing", &string,
693                       "byte_thing",   &byte_thing,
694                       "i32_thing",    &i32_thing,
695                       "i64_thing",    &i64_thing,
696                       NULL);
697 
698         printf (" = {\"%s\", %d, %d, %" PRId64 "}\n",
699                 string,
700                 byte_thing,
701                 i32_thing,
702                 i64_thing);
703         if ((string == NULL || strncmp (string, "Zero", 5) != 0) ||
704             byte_thing != 1 ||
705             i32_thing != -3 ||
706             i64_thing != (gint64)-5)
707           fail_count++;
708 
709         if (string) {
710           g_free (string);
711           string = NULL;
712         }
713       }
714       else {
715         printf ("%s\n", error->message);
716         g_error_free (error);
717         error = NULL;
718 
719         fail_count++;
720       }
721       // g_clear_object(&xtruct_out); used below
722       g_clear_object(&xtruct_in);
723 
724       /**
725        * NESTED STRUCT TEST
726        */
727       printf ("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
728       xtruct2_out = g_object_new (T_TEST_TYPE_XTRUCT2,
729                                   "byte_thing",            1,
730                                   "struct_thing", xtruct_out,
731                                   "i32_thing",             5,
732                                   NULL);
733       xtruct2_in = g_object_new (T_TEST_TYPE_XTRUCT2, NULL);
734 
735       if (t_test_thrift_test_if_test_nest (test_client,
736                                            &xtruct2_in,
737                                            xtruct2_out,
738                                            &error)) {
739         g_object_get (xtruct2_in,
740                       "byte_thing",   &byte_thing,
741                       "struct_thing", &xtruct_in,
742                       "i32_thing",    &i32_thing,
743                       NULL);
744         g_object_get (xtruct_in,
745                       "string_thing", &string,
746                       "byte_thing",   &inner_byte_thing,
747                       "i32_thing",    &inner_i32_thing,
748                       "i64_thing",    &inner_i64_thing,
749                       NULL);
750 
751         printf (" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n",
752                 byte_thing,
753                 string,
754                 inner_byte_thing,
755                 inner_i32_thing,
756                 inner_i64_thing,
757                 i32_thing);
758         if (byte_thing != 1 ||
759             (string == NULL || strncmp (string, "Zero", 5) != 0) ||
760             inner_byte_thing != 1 ||
761             inner_i32_thing != -3 ||
762             inner_i64_thing != (gint64)-5 ||
763             i32_thing != 5)
764           fail_count++;
765 
766         if (string) {
767           g_free(string);
768           string = NULL;
769         }
770       }
771       else {
772         printf ("%s\n", error->message);
773         g_error_free (error);
774         error = NULL;
775 
776         fail_count++;
777       }
778 
779       g_clear_object(&xtruct_in);
780       g_clear_object(&xtruct2_in);
781       g_clear_object(&xtruct2_out);
782       g_clear_object(&xtruct_out);
783 
784       /**
785        * MAP TEST
786        */
787       map_out = g_hash_table_new_full (g_int_hash,
788                                        g_int_equal,
789                                        g_free,
790                                        g_free);
791       for (i = 0; i < 5; ++i) {
792         i32_key_ptr   = g_malloc (sizeof *i32_key_ptr);
793         i32_value_ptr = g_malloc (sizeof *i32_value_ptr);
794 
795         *i32_key_ptr   = i;
796         *i32_value_ptr = i - 10;
797 
798         g_hash_table_insert (map_out, i32_key_ptr, i32_value_ptr);
799       }
800       printf ("testMap({");
801       first = TRUE;
802       g_hash_table_iter_init (&hash_table_iter, map_out);
803       while (g_hash_table_iter_next (&hash_table_iter,
804                                      &key,
805                                      &value)) {
806         if (first)
807           first = FALSE;
808         else
809           printf (", ");
810 
811         printf ("%d => %d", *(gint32 *)key, *(gint32 *)value);
812       }
813       printf ("})");
814 
815       map_in = g_hash_table_new_full (g_int_hash,
816                                       g_int_equal,
817                                       g_free,
818                                       g_free);
819 
820       if (t_test_thrift_test_if_test_map (test_client,
821                                           &map_in,
822                                           map_out,
823                                           &error)) {
824         printf (" = {");
825         first = TRUE;
826         g_hash_table_iter_init (&hash_table_iter, map_in);
827         while (g_hash_table_iter_next (&hash_table_iter,
828                                        &key,
829                                        &value)) {
830           if (first)
831             first = FALSE;
832           else
833             printf (", ");
834 
835           printf ("%d => %d", *(gint32 *)key, *(gint32 *)value);
836         }
837         printf ("}\n");
838 
839         if (g_hash_table_size (map_in) != g_hash_table_size (map_out))
840           fail_count++;
841         else {
842           g_hash_table_iter_init (&hash_table_iter, map_out);
843           while (g_hash_table_iter_next (&hash_table_iter,
844                                          &key,
845                                          &value)) {
846             gpointer in_value = g_hash_table_lookup (map_in, key);
847             if (in_value == NULL ||
848                 *(gint32 *)in_value != *(gint32 *)value) {
849               fail_count++;
850               break;
851             }
852           }
853         }
854       }
855       else {
856         printf ("%s\n", error->message);
857         g_error_free (error);
858         error = NULL;
859 
860         fail_count++;
861       }
862 
863       g_hash_table_unref (map_in);
864       g_hash_table_unref (map_out);
865 
866       /**
867        * STRING MAP TEST
868        */
869       map_out = g_hash_table_new_full (g_str_hash,
870                                        g_str_equal,
871                                        NULL,
872                                        NULL);
873       g_hash_table_insert (map_out, "a",    "2");
874       g_hash_table_insert (map_out, "b",    "blah");
875       g_hash_table_insert (map_out, "some", "thing");
876       printf ("testStringMap({");
877       first = TRUE;
878       g_hash_table_iter_init (&hash_table_iter, map_out);
879       while (g_hash_table_iter_next (&hash_table_iter,
880                                      &key,
881                                      &value)) {
882         if (first)
883           first = FALSE;
884         else
885           printf (", ");
886 
887         printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value);
888       }
889       printf (")}");
890 
891       map_in = g_hash_table_new_full (g_str_hash,
892                                       g_str_equal,
893                                       g_free,
894                                       g_free);
895 
896       if (t_test_thrift_test_if_test_string_map (test_client,
897                                                  &map_in,
898                                                  map_out,
899                                                  &error)) {
900         printf (" = {");
901         first = TRUE;
902         g_hash_table_iter_init (&hash_table_iter, map_in);
903         while (g_hash_table_iter_next (&hash_table_iter,
904                                        &key,
905                                        &value)) {
906           if (first)
907             first = FALSE;
908           else
909             printf (", ");
910 
911           printf ("\"%s\" => \"%s\"", (gchar *)key, (gchar *)value);
912         }
913         printf ("}\n");
914 
915         if (g_hash_table_size (map_in) != g_hash_table_size (map_out))
916           fail_count++;
917         else {
918           g_hash_table_iter_init (&hash_table_iter, map_out);
919           while (g_hash_table_iter_next (&hash_table_iter,
920                                          &key,
921                                          &value)) {
922             gpointer in_value = g_hash_table_lookup (map_in, key);
923             if (in_value == NULL ||
924                 strcmp ((gchar *)in_value, (gchar *)value) != 0) {
925               fail_count++;
926               break;
927             }
928           }
929         }
930       }
931       else {
932         printf ("%s\n", error->message);
933         g_error_free (error);
934         error = NULL;
935 
936         fail_count++;
937       }
938 
939       g_hash_table_unref (map_in);
940       g_hash_table_unref (map_out);
941 
942       /**
943        * SET TEST
944        */
945       set_out = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
946       for (i = -2; i < 3; ++i) {
947         i32_key_ptr = g_malloc (sizeof *i32_key_ptr);
948         *i32_key_ptr = i;
949 
950         g_hash_table_insert (set_out, i32_key_ptr, NULL);
951       }
952       printf ("testSet({");
953       first = TRUE;
954       keys_out = g_hash_table_get_keys (set_out);
955       keys_elem = keys_out;
956       while (keys_elem != NULL) {
957         if (first)
958           first = FALSE;
959         else
960           printf (", ");
961 
962         printf ("%d", *(gint32 *)keys_elem->data);
963 
964         keys_elem = keys_elem->next;
965       }
966       printf ("})");
967 
968       set_in = g_hash_table_new_full (g_int_hash, g_int_equal, g_free, NULL);
969 
970       if (t_test_thrift_test_if_test_set (test_client,
971                                           &set_in,
972                                           set_out,
973                                           &error)) {
974         printf(" = {");
975         first = TRUE;
976         keys_in = g_hash_table_get_keys (set_in);
977         keys_elem = keys_in;
978         while (keys_elem != NULL) {
979           if (first)
980             first = FALSE;
981           else
982             printf (", ");
983 
984           printf ("%d", *(gint32 *)keys_elem->data);
985 
986           keys_elem = keys_elem->next;
987         }
988         printf ("}\n");
989 
990         if (g_list_length (keys_in) != g_list_length (keys_out))
991           fail_count++;
992         else {
993           keys_elem = keys_out;
994           while (keys_elem != NULL) {
995             if (g_list_find_custom (keys_in,
996                                     keys_elem->data,
997                                     gint32_compare) == NULL) {
998               fail_count++;
999               break;
1000             }
1001 
1002             keys_elem = keys_elem->next;
1003           }
1004         }
1005 
1006         g_list_free (keys_in);
1007       }
1008       else {
1009         printf ("%s\n", error->message);
1010         g_error_free (error);
1011         error = NULL;
1012 
1013         fail_count++;
1014       }
1015 
1016       g_hash_table_unref (set_in);
1017       g_list_free (keys_out);
1018       g_hash_table_unref (set_out);
1019 
1020       /**
1021        * LIST TEST
1022        */
1023       list_out = g_array_new (FALSE, TRUE, sizeof (gint32));
1024       for (i = -2; i < 3; ++i) {
1025         g_array_append_val (list_out, i);
1026       }
1027       printf ("testList({");
1028       first = TRUE;
1029       for (i = 0; i < (gint32)list_out->len; ++i) {
1030         if (first)
1031           first = FALSE;
1032         else
1033           printf (", ");
1034 
1035         printf ("%d", g_array_index (list_out, gint32, i));
1036       }
1037       printf ("})");
1038 
1039       list_in = g_array_new (FALSE, TRUE, sizeof (gint32));
1040 
1041       if (t_test_thrift_test_if_test_list (test_client,
1042                                            &list_in,
1043                                            list_out,
1044                                            &error)) {
1045         printf (" = {");
1046         first = TRUE;
1047         for (i = 0; i < (gint32)list_in->len; ++i) {
1048           if (first)
1049             first = FALSE;
1050           else
1051             printf (", ");
1052 
1053           printf ("%d", g_array_index (list_in, gint32, i));
1054         }
1055         printf ("}\n");
1056 
1057         if (list_in->len != list_out->len ||
1058             memcmp (list_in->data,
1059                     list_out->data,
1060                     list_in->len * sizeof (gint32)) != 0)
1061           fail_count++;
1062       }
1063       else {
1064         printf ("%s\n", error->message);
1065         g_error_free (error);
1066         error = NULL;
1067 
1068         fail_count++;
1069       }
1070 
1071       g_array_unref (list_in);
1072       g_array_unref (list_out);
1073 
1074       /**
1075        * ENUM TEST
1076        */
1077       printf("testEnum(ONE)");
1078       if (t_test_thrift_test_if_test_enum (test_client,
1079                                            &numberz,
1080                                            T_TEST_NUMBERZ_ONE,
1081                                            &error)) {
1082         printf(" = %d\n", numberz);
1083         if (numberz != T_TEST_NUMBERZ_ONE)
1084           fail_count++;
1085       }
1086       else {
1087         printf ("%s\n", error->message);
1088         g_error_free (error);
1089         error = NULL;
1090 
1091         fail_count++;
1092       }
1093 
1094       printf("testEnum(TWO)");
1095       if (t_test_thrift_test_if_test_enum (test_client,
1096                                            &numberz,
1097                                            T_TEST_NUMBERZ_TWO,
1098                                            &error)) {
1099         printf(" = %d\n", numberz);
1100         if (numberz != T_TEST_NUMBERZ_TWO)
1101           fail_count++;
1102       }
1103       else {
1104         printf ("%s\n", error->message);
1105         g_error_free (error);
1106         error = NULL;
1107 
1108         fail_count++;
1109       }
1110 
1111       printf("testEnum(THREE)");
1112       if (t_test_thrift_test_if_test_enum (test_client,
1113                                            &numberz,
1114                                            T_TEST_NUMBERZ_THREE,
1115                                            &error)) {
1116         printf(" = %d\n", numberz);
1117         if (numberz != T_TEST_NUMBERZ_THREE)
1118           fail_count++;
1119       }
1120       else {
1121         printf ("%s\n", error->message);
1122         g_error_free (error);
1123         error = NULL;
1124 
1125         fail_count++;
1126       }
1127 
1128       printf("testEnum(FIVE)");
1129       if (t_test_thrift_test_if_test_enum (test_client,
1130                                            &numberz,
1131                                            T_TEST_NUMBERZ_FIVE,
1132                                            &error)) {
1133         printf(" = %d\n", numberz);
1134         if (numberz != T_TEST_NUMBERZ_FIVE)
1135           fail_count++;
1136       }
1137       else {
1138         printf ("%s\n", error->message);
1139         g_error_free (error);
1140         error = NULL;
1141 
1142         fail_count++;
1143       }
1144 
1145       printf("testEnum(EIGHT)");
1146       if (t_test_thrift_test_if_test_enum (test_client,
1147                                            &numberz,
1148                                            T_TEST_NUMBERZ_EIGHT,
1149                                            &error)) {
1150         printf(" = %d\n", numberz);
1151         if (numberz != T_TEST_NUMBERZ_EIGHT)
1152           fail_count++;
1153       }
1154       else {
1155         printf ("%s\n", error->message);
1156         g_error_free (error);
1157         error = NULL;
1158 
1159         fail_count++;
1160       }
1161 
1162       /**
1163        * TYPEDEF TEST
1164        */
1165       printf ("testTypedef(309858235082523)");
1166       if (t_test_thrift_test_if_test_typedef (test_client,
1167                                               &user_id,
1168                                               309858235082523LL,
1169                                               &error)) {
1170         printf(" = %" PRId64 "\n", user_id);
1171         if (user_id != 309858235082523LL)
1172           fail_count++;
1173       }
1174       else {
1175         printf ("%s\n", error->message);
1176         g_error_free (error);
1177         error = NULL;
1178 
1179         fail_count++;
1180       }
1181 
1182       /**
1183        * NESTED MAP TEST
1184        */
1185       printf ("testMapMap(1)");
1186       map_in = g_hash_table_new_full (g_int_hash,
1187                                       g_int_equal,
1188                                       g_free,
1189                                       (GDestroyNotify)g_hash_table_unref);
1190       if (t_test_thrift_test_if_test_map_map (test_client,
1191                                               &map_in,
1192                                               1,
1193                                               &error)) {
1194         g_hash_table_iter_init (&hash_table_iter, map_in);
1195 
1196         printf (" = {");
1197         while (g_hash_table_iter_next (&hash_table_iter,
1198                                        &key,
1199                                        &value)) {
1200           printf ("%d => {", *(gint32 *)key);
1201 
1202           g_hash_table_iter_init (&inner_hash_table_iter,
1203                                   (GHashTable *)value);
1204           while (g_hash_table_iter_next (&inner_hash_table_iter,
1205                                          &key,
1206                                          &value)) {
1207             printf ("%d => %d, ", *(gint32 *)key, *(gint32 *)value);
1208           }
1209 
1210           printf ("}, ");
1211         }
1212         printf ("}\n");
1213 
1214         if (g_hash_table_size (map_in) != 2)
1215           fail_count++;
1216         else {
1217           gint32 inner_keys[] = {1, 2, 3, 4};
1218           gint32 i32_key;
1219 
1220           i32_key = -4;
1221           inner_map_in = g_hash_table_lookup (map_in, &i32_key);
1222           if (inner_map_in == NULL ||
1223               g_hash_table_size (inner_map_in) != 4)
1224             fail_count++;
1225           else {
1226             keys_in = g_hash_table_get_keys (inner_map_in);
1227             keys_in = g_list_sort (keys_in, gint32_compare);
1228 
1229             for (i = 0; i < 4; i++) {
1230               keys_elem = g_list_nth (keys_in, 3 - i);
1231 
1232               if (*(gint32 *)keys_elem->data != (-1 * inner_keys[i]) ||
1233                   *(gint32 *)g_hash_table_lookup (inner_map_in,
1234                                                   keys_elem->data) !=
1235                   (-1 * inner_keys[i])) {
1236                 fail_count++;
1237                 break;
1238               }
1239             }
1240 
1241             g_list_free (keys_in);
1242           }
1243 
1244           i32_key = 4;
1245           inner_map_in = g_hash_table_lookup (map_in, &i32_key);
1246           if (inner_map_in == NULL ||
1247               g_hash_table_size (inner_map_in) != 4)
1248             fail_count++;
1249           else {
1250             keys_in = g_hash_table_get_keys (inner_map_in);
1251             keys_in = g_list_sort (keys_in, gint32_compare);
1252 
1253             for (i = 0; i < 4; i++) {
1254               keys_elem = g_list_nth (keys_in, i);
1255 
1256               if (*(gint32 *)keys_elem->data != inner_keys[i] ||
1257                   *(gint32 *)g_hash_table_lookup (inner_map_in,
1258                                                   keys_elem->data) !=
1259                   inner_keys[i]) {
1260                 fail_count++;
1261                 break;
1262               }
1263             }
1264 
1265             g_list_free (keys_in);
1266           }
1267         }
1268       }
1269       else {
1270         printf ("%s\n", error->message);
1271         g_error_free (error);
1272         error = NULL;
1273 
1274         fail_count++;
1275       }
1276 
1277       g_hash_table_unref (map_in);
1278 
1279       /**
1280        * INSANITY TEST
1281        */
1282       insanity_out = g_object_new (T_TEST_TYPE_INSANITY, NULL);
1283       g_object_get (insanity_out,
1284                     "userMap", &user_map,
1285                     "xtructs", &xtructs,
1286                     NULL);
1287 
1288       numberz = T_TEST_NUMBERZ_FIVE;
1289       numberz2 = T_TEST_NUMBERZ_EIGHT;
1290       user_id_ptr = g_malloc (sizeof *user_id_ptr);
1291       *user_id_ptr = 5;
1292       user_id_ptr2 = g_malloc (sizeof *user_id_ptr);
1293       *user_id_ptr2 = 8;
1294       g_hash_table_insert (user_map, (gpointer)numberz, user_id_ptr);
1295       g_hash_table_insert (user_map, (gpointer)numberz2, user_id_ptr2);
1296       g_hash_table_unref (user_map);
1297 
1298       xtruct_out = g_object_new (T_TEST_TYPE_XTRUCT,
1299                                  "string_thing", "Hello2",
1300                                  "byte_thing",   2,
1301                                  "i32_thing",    2,
1302                                  "i64_thing",    2LL,
1303                                  NULL);
1304       xtruct_out2 = g_object_new (T_TEST_TYPE_XTRUCT,
1305                                  "string_thing", "Goodbye4",
1306                                  "byte_thing",   4,
1307                                  "i32_thing",    4,
1308                                  "i64_thing",    4LL,
1309                                  NULL);
1310       g_ptr_array_add (xtructs, xtruct_out2);
1311       g_ptr_array_add (xtructs, xtruct_out);
1312       g_ptr_array_unref (xtructs);
1313 
1314       map_in = g_hash_table_new_full (g_int64_hash,
1315                                       g_int64_equal,
1316                                       g_free,
1317                                       (GDestroyNotify)g_hash_table_unref);
1318 
1319       printf("testInsanity()");
1320       if (t_test_thrift_test_if_test_insanity (test_client,
1321                                                &map_in,
1322                                                insanity_out,
1323                                                &error)) {
1324         printf (" = {");
1325         g_hash_table_iter_init (&hash_table_iter, map_in);
1326         while (g_hash_table_iter_next (&hash_table_iter,
1327                                        &key,
1328                                        &value)) {
1329           printf ("%" PRId64 " => {", *(TTestUserId *)key);
1330 
1331           g_hash_table_iter_init (&inner_hash_table_iter,
1332                                   (GHashTable *)value);
1333           while (g_hash_table_iter_next (&inner_hash_table_iter,
1334                                          &key,
1335                                          &value)) {
1336             printf ("%d => {", (TTestNumberz)key);
1337 
1338             g_object_get ((TTestInsanity *)value,
1339                           "userMap", &user_map,
1340                           "xtructs", &xtructs,
1341                           NULL);
1342 
1343             printf ("{");
1344             g_hash_table_iter_init (&user_map_iter, user_map);
1345             while (g_hash_table_iter_next (&user_map_iter,
1346                                            &key,
1347                                            &value)) {
1348               printf ("%d => %" PRId64 ", ",
1349                       (TTestNumberz)key,
1350                       *(TTestUserId *)value);
1351             }
1352             printf ("}, ");
1353             g_hash_table_unref (user_map);
1354 
1355             printf("{");
1356             for (i = 0; i < (gint32)xtructs->len; ++i) {
1357               xtruct_in = g_ptr_array_index (xtructs, i);
1358               g_object_get (xtruct_in,
1359                             "string_thing", &string,
1360                             "byte_thing",   &byte_thing,
1361                             "i32_thing",    &i32_thing,
1362                             "i64_thing",    &i64_thing,
1363                             NULL);
1364 
1365               printf ("{\"%s\", %d, %d, %" PRId64 "}, ",
1366                       string,
1367                       byte_thing,
1368                       i32_thing,
1369                       i64_thing);
1370               if (string != NULL)
1371                 g_free (string);
1372             }
1373             printf ("}");
1374             g_ptr_array_unref (xtructs);
1375 
1376             printf ("}, ");
1377           }
1378           printf("}, ");
1379         }
1380         printf("}\n");
1381 
1382         if (g_hash_table_size (map_in) != 2)
1383           fail_count++;
1384         else {
1385           TTestNumberz numberz_key_values[] = {
1386             T_TEST_NUMBERZ_TWO, T_TEST_NUMBERZ_THREE
1387           };
1388           gint user_map_values[] = { 5, 8 };
1389           TTestUserId user_id_key;
1390 
1391           user_id_key = 1;
1392           inner_map_in = g_hash_table_lookup (map_in, &user_id_key);
1393           if (inner_map_in == NULL ||
1394               g_hash_table_size (inner_map_in) != 2)
1395             fail_count++;
1396           else {
1397             TTestNumberz numberz_key;
1398 
1399             for (i = 0; i < 2; ++i) {
1400               numberz_key = numberz_key_values[i];
1401               insanity_in =
1402                 g_hash_table_lookup (inner_map_in,
1403                                      (gconstpointer)numberz_key);
1404               if (insanity_in == NULL)
1405                 fail_count++;
1406               else {
1407                 g_object_get (insanity_in,
1408                               "userMap", &user_map,
1409                               "xtructs", &xtructs,
1410                               NULL);
1411 
1412                 if (user_map == NULL)
1413                   fail_count++;
1414                 else {
1415                   if (g_hash_table_size (user_map) != 2)
1416                     fail_count++;
1417                   else {
1418                     for (j = 0; j < 2; ++j) {
1419                       numberz_key = (TTestNumberz)user_map_values[j];
1420 
1421                       value =
1422                         g_hash_table_lookup (user_map,
1423                                              (gconstpointer)numberz_key);
1424                       if (value == NULL ||
1425                           *(TTestUserId *)value != (TTestUserId)user_map_values[j])
1426                         fail_count++;
1427                     }
1428                   }
1429 
1430                   g_hash_table_unref (user_map);
1431                 }
1432 
1433                 if (xtructs == NULL)
1434                   fail_count++;
1435                 else {
1436                   if (xtructs->len != 2)
1437                     fail_count++;
1438                   else {
1439                     xtruct_in = g_ptr_array_index (xtructs, 0);
1440                     g_object_get (xtruct_in,
1441                                   "string_thing", &string,
1442                                   "byte_thing",   &byte_thing,
1443                                   "i32_thing",    &i32_thing,
1444                                   "i64_thing",    &i64_thing,
1445                                   NULL);
1446                     if ((string == NULL ||
1447                          strncmp (string, "Goodbye4", 9) != 0) ||
1448                         byte_thing != 4 ||
1449                         i32_thing != 4 ||
1450                         i64_thing != 4)
1451                       fail_count++;
1452 
1453                     if (string != NULL)
1454                       g_free (string);
1455 
1456                     xtruct_in = g_ptr_array_index (xtructs, 1);
1457                     g_object_get (xtruct_in,
1458                                   "string_thing", &string,
1459                                   "byte_thing",   &byte_thing,
1460                                   "i32_thing",    &i32_thing,
1461                                   "i64_thing",    &i64_thing,
1462                                   NULL);
1463                     if ((string == NULL ||
1464                          strncmp (string, "Hello2", 7) != 0) ||
1465                         byte_thing != 2 ||
1466                         i32_thing != 2 ||
1467                         i64_thing != 2)
1468                       fail_count++;
1469 
1470                     if (string != NULL)
1471                       g_free (string);
1472                   }
1473 
1474                   g_ptr_array_unref (xtructs);
1475                 }
1476               }
1477             }
1478           }
1479 
1480           user_id_key = 2;
1481           inner_map_in = g_hash_table_lookup (map_in, &user_id_key);
1482           if (inner_map_in == NULL ||
1483               g_hash_table_size (inner_map_in) != 1)
1484             fail_count++;
1485           else {
1486             insanity_in =
1487               g_hash_table_lookup (inner_map_in,
1488                                    (gconstpointer)T_TEST_NUMBERZ_SIX);
1489             if (insanity_in == NULL)
1490               fail_count++;
1491             else {
1492               g_object_get (insanity_in,
1493                             "userMap", &user_map,
1494                             "xtructs", &xtructs,
1495                             NULL);
1496 
1497               if (user_map == NULL)
1498                 fail_count++;
1499               else {
1500                 if (g_hash_table_size (user_map) != 0)
1501                   fail_count++;
1502 
1503                 g_hash_table_unref (user_map);
1504               }
1505 
1506               if (xtructs == NULL)
1507                 fail_count++;
1508               else {
1509                 if (xtructs->len != 0)
1510                   fail_count++;
1511 
1512                 g_ptr_array_unref (xtructs);
1513               }
1514             }
1515           }
1516         }
1517       }
1518       else {
1519         printf ("%s\n", error->message);
1520         g_error_free (error);
1521         error = NULL;
1522 
1523         fail_count++;
1524       }
1525 
1526       g_hash_table_unref (map_in);
1527       g_clear_object (&insanity_out);
1528 
1529       /* test exception */
1530       printf ("testClient.testException(\"Xception\") =>");
1531       if (!t_test_thrift_test_if_test_exception (test_client,
1532                                                  "Xception",
1533                                                  &xception,
1534                                                  &error) &&
1535           xception != NULL) {
1536         g_object_get (xception,
1537                       "errorCode", &int32,
1538                       "message",   &string,
1539                       NULL);
1540         printf ("  {%u, \"%s\"}\n", int32, string);
1541         g_free (string);
1542 
1543         g_clear_object (&xception);
1544 
1545         g_error_free (error);
1546         error = NULL;
1547       }
1548       else {
1549         printf ("  void\nFAILURE\n");
1550         fail_count++;
1551 
1552         if (xception != NULL) {
1553           g_object_unref (xception);
1554           xception = NULL;
1555         }
1556 
1557         if (error != NULL) {
1558           g_error_free (error);
1559           error = NULL;
1560         }
1561       }
1562 
1563       printf ("testClient.testException(\"TException\") =>");
1564       if (!t_test_thrift_test_if_test_exception (test_client,
1565                                                  "TException",
1566                                                  &xception,
1567                                                  &error) &&
1568           xception == NULL &&
1569           error != NULL) {
1570         printf ("  Caught TException\n");
1571 
1572         g_error_free (error);
1573         error = NULL;
1574       }
1575       else {
1576         printf ("  void\nFAILURE\n");
1577         fail_count++;
1578 
1579         g_clear_object (&xception);
1580 
1581         if (error != NULL) {
1582           g_error_free (error);
1583           error = NULL;
1584         }
1585       }
1586 
1587       printf ("testClient.testException(\"success\") =>");
1588       if (t_test_thrift_test_if_test_exception (test_client,
1589                                                 "success",
1590                                                 &xception,
1591                                                 &error))
1592         printf ("  void\n");
1593       else {
1594         printf ("  void\nFAILURE\n");
1595         fail_count++;
1596 
1597         g_clear_object (&xception);
1598 
1599         g_error_free (error);
1600         error = NULL;
1601       }
1602 
1603       g_assert (error == NULL);
1604 
1605       /* test multi exception */
1606       printf ("testClient.testMultiException(\"Xception\", \"test 1\") =>");
1607       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
1608       if (!t_test_thrift_test_if_test_multi_exception (test_client,
1609                                                        &xtruct_in,
1610                                                        "Xception",
1611                                                        "test 1",
1612                                                        &xception,
1613                                                        &xception2,
1614                                                        &error) &&
1615           xception != NULL &&
1616           xception2 == NULL) {
1617         g_object_get (xception,
1618                       "errorCode", &int32,
1619                       "message",   &string,
1620                       NULL);
1621         printf ("  {%u, \"%s\"}\n", int32, string);
1622         g_free (string);
1623 
1624         g_object_unref (xception);
1625         xception = NULL;
1626 
1627         g_error_free (error);
1628         error = NULL;
1629       }
1630       else {
1631         printf ("  result\nFAILURE\n");
1632         fail_count++;
1633 
1634         g_clear_object (&xception);
1635         g_clear_object (&xception2);
1636 
1637         if (error != NULL) {
1638           g_error_free (error);
1639           error = NULL;
1640         }
1641       }
1642       g_object_unref (xtruct_in);
1643 
1644       printf ("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
1645       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
1646       if (!t_test_thrift_test_if_test_multi_exception (test_client,
1647                                                        &xtruct_in,
1648                                                        "Xception2",
1649                                                        "test 2",
1650                                                        &xception,
1651                                                        &xception2,
1652                                                        &error) &&
1653           xception == NULL &&
1654           xception2 != NULL) {
1655         g_object_get (xception2,
1656                       "errorCode",    &int32,
1657                       "struct_thing", &inner_xtruct_in,
1658                       NULL);
1659         g_object_get (inner_xtruct_in,
1660                       "string_thing", &string,
1661                       NULL);
1662         printf ("  {%u, {\"%s\"}}\n", int32, string);
1663         g_free (string);
1664 
1665         g_clear_object (&inner_xtruct_in);
1666         g_clear_object (&xception2);
1667 
1668         g_error_free (error);
1669         error = NULL;
1670       }
1671       else {
1672         printf ("  result\nFAILURE\n");
1673         fail_count++;
1674 
1675         g_clear_object (&xception);
1676         g_clear_object (&xception2);
1677 
1678         if (error != NULL) {
1679           g_error_free (error);
1680           error = NULL;
1681         }
1682       }
1683       g_clear_object (&xtruct_in);
1684 
1685       printf ("testClient.testMultiException(\"success\", \"test 3\") =>");
1686       xtruct_in = g_object_new (T_TEST_TYPE_XTRUCT, NULL);
1687       if (t_test_thrift_test_if_test_multi_exception (test_client,
1688                                                       &xtruct_in,
1689                                                       "success",
1690                                                       "test 3",
1691                                                       &xception,
1692                                                       &xception2,
1693                                                       &error) &&
1694           xception == NULL &&
1695           xception2 == NULL) {
1696         g_object_get (xtruct_in,
1697                       "string_thing", &string,
1698                       NULL);
1699         printf ("  {{\"%s\"}}\n", string);
1700         g_free (string);
1701       }
1702       else {
1703         printf ("  result\nFAILURE\n");
1704         fail_count++;
1705 
1706         g_clear_object (&xception);
1707         g_clear_object (&xception2);
1708 
1709         if (error != NULL) {
1710           g_error_free (error);
1711           error = NULL;
1712         }
1713       }
1714       g_clear_object (&xtruct_in);
1715 
1716       /* test oneway void */
1717       printf ("testClient.testOneway(1) =>");
1718       gettimeofday (&oneway_start, NULL);
1719       oneway_result = t_test_thrift_test_if_test_oneway (test_client,
1720                                                          1,
1721                                                          &error);
1722       gettimeofday (&oneway_end, NULL);
1723       timersub (&oneway_end, &oneway_start, &oneway_elapsed);
1724       oneway_elapsed_usec =
1725         oneway_elapsed.tv_sec * 1000 * 1000 + oneway_elapsed.tv_usec;
1726 
1727       if (oneway_result) {
1728         if (oneway_elapsed_usec > 200 * 1000) {
1729           printf ("  FAILURE - took %.2f ms\n",
1730                   (double)oneway_elapsed_usec / 1000.0);
1731           fail_count++;
1732         }
1733         else
1734           printf ("  success - took %.2f ms\n",
1735                   (double)oneway_elapsed_usec / 1000.0);
1736       }
1737       else {
1738         printf ("%s\n", error->message);
1739         g_error_free (error);
1740         error = NULL;
1741 
1742         fail_count++;
1743       }
1744 
1745       /**
1746        * redo a simple test after the oneway to make sure we aren't "off by
1747        * one" -- if the server treated oneway void like normal void, this next
1748        * test will fail since it will get the void confirmation rather than
1749        * the correct result. In this circumstance, the client will receive the
1750        * error:
1751        *
1752        *   application error: Wrong method name
1753        */
1754       /**
1755        * I32 TEST
1756        */
1757       printf ("re-test testI32(-1)");
1758       if (t_test_thrift_test_if_test_i32 (test_client,
1759                                           &int32,
1760                                           -1,
1761                                           &error)) {
1762         printf (" = %d\n", int32);
1763         if (int32 != -1)
1764           fail_count++;
1765       }
1766       else {
1767         printf ("%s\n", error->message);
1768         g_error_free (error);
1769         error = NULL;
1770 
1771         fail_count++;
1772       }
1773 
1774       gettimeofday (&time_stop, NULL);
1775       timersub (&time_stop, &time_start, &time_elapsed);
1776       time_elapsed_usec =
1777         time_elapsed.tv_sec * 1000 * 1000 + time_elapsed.tv_usec;
1778 
1779       printf("Total time: %" PRIu64 " us\n", time_elapsed_usec);
1780 
1781       time_total_usec += time_elapsed_usec;
1782       if (time_elapsed_usec < time_min_usec)
1783         time_min_usec = time_elapsed_usec;
1784       if (time_elapsed_usec > time_max_usec)
1785         time_max_usec = time_elapsed_usec;
1786 
1787       thrift_transport_close (transport, &error);
1788     }
1789     else {
1790       printf ("Connect failed: %s\n", error->message);
1791       g_error_free (error);
1792       error = NULL;
1793 
1794       goto out;
1795     }
1796   }
1797 
1798   /* All done---output statistics */
1799   puts ("\nAll tests done.");
1800   printf("Number of failures: %d\n", fail_count);
1801 
1802   time_avg_usec = time_total_usec / num_tests;
1803 
1804   printf ("Min time: %" PRIu64 " us\n", time_min_usec);
1805   printf ("Max time: %" PRIu64 " us\n", time_max_usec);
1806   printf ("Avg time: %" PRIu64 " us\n", time_avg_usec);
1807 
1808 out:
1809   g_clear_object(&second_service);
1810   g_clear_object(&protocol2);
1811   g_clear_object(&test_client);
1812   g_clear_object(&protocol);
1813   g_clear_object(&multiplexed_protocol);
1814   g_clear_object(&transport);
1815   g_clear_object(&socket);
1816 
1817   if (ssl) {
1818     thrift_ssl_socket_finalize_openssl();
1819   }
1820 
1821   return fail_count;
1822 }
1823