1/* GLib testing framework examples and tests
2 *
3 * Copyright 2012 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <string.h>
20
21#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_34
22#include <gio/gio.h>
23
24/* Overview:
25 *
26 * We have an echo server, two proxy servers, two GProxy
27 * implementations, and two GProxyResolver implementations.
28 *
29 * The echo server runs at @server.server_addr (on
30 * @server.server_port).
31 *
32 * The two proxy servers, A and B, run on @proxy_a.port and
33 * @proxy_b.port, with @proxy_a.uri and @proxy_b.uri pointing to them.
34 * The "negotiation" with the two proxies is just sending the single
35 * letter "a" or "b" and receiving it back in uppercase; the proxy
36 * then connects to @server_addr.
37 *
38 * Proxy A supports "alpha://" URIs, and does not support hostname
39 * resolution, and Proxy B supports "beta://" URIs, and does support
40 * hostname resolution (but it just ignores the hostname and always
41 * connects to @server_addr anyway).
42 *
43 * The default GProxyResolver (GTestProxyResolver) looks at its URI
44 * and returns [ "direct://" ] for "simple://" URIs, and [
45 * proxy_a.uri, proxy_b.uri ] for other URIs. The other GProxyResolver
46 * (GTestAltProxyResolver) always returns [ proxy_a.uri ].
47 */
48
49typedef struct {
50 gchar *proxy_command;
51 gchar *supported_protocol;
52
53 GSocket *server;
54 GThread *thread;
55 GCancellable *cancellable;
56 gchar *uri;
57 gushort port;
58
59 GSocket *client_sock, *server_sock;
60 GMainLoop *loop;
61
62 GError *last_error;
63} ProxyData;
64
65static ProxyData proxy_a, proxy_b;
66
67typedef struct {
68 GSocket *server;
69 GThread *server_thread;
70 GCancellable *cancellable;
71 GSocketAddress *server_addr;
72 gushort server_port;
73} ServerData;
74
75static ServerData server;
76
77static gchar **last_proxies;
78
79static GSocketClient *client;
80
81
82/**************************************/
83/* Test GProxyResolver implementation */
84/**************************************/
85
86typedef struct {
87 GObject parent_instance;
88} GTestProxyResolver;
89
90typedef struct {
91 GObjectClass parent_class;
92} GTestProxyResolverClass;
93
94static void g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface);
95
96static GType _g_test_proxy_resolver_get_type (void);
97#define g_test_proxy_resolver_get_type _g_test_proxy_resolver_get_type
98G_DEFINE_TYPE_WITH_CODE (GTestProxyResolver, g_test_proxy_resolver, G_TYPE_OBJECT,
99 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
100 g_test_proxy_resolver_iface_init)
101 g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
102 g_define_type_id,
103 "test",
104 0))
105
106static void
107g_test_proxy_resolver_init (GTestProxyResolver *resolver)
108{
109}
110
111static gboolean
112g_test_proxy_resolver_is_supported (GProxyResolver *resolver)
113{
114 return TRUE;
115}
116
117static gchar **
118g_test_proxy_resolver_lookup (GProxyResolver *resolver,
119 const gchar *uri,
120 GCancellable *cancellable,
121 GError **error)
122{
123 gchar **proxies;
124
125 g_assert (last_proxies == NULL);
126
127 if (g_cancellable_set_error_if_cancelled (cancellable, error))
128 return NULL;
129
130 proxies = g_new (gchar *, 3);
131
132 if (!strncmp (s1: uri, s2: "simple://", n: 4))
133 {
134 proxies[0] = g_strdup (str: "direct://");
135 proxies[1] = NULL;
136 }
137 else
138 {
139 /* Proxy A can only deal with "alpha://" URIs, not
140 * "beta://", but we always return both URIs
141 * anyway so we can test error handling when the first
142 * fails.
143 */
144 proxies[0] = g_strdup (str: proxy_a.uri);
145 proxies[1] = g_strdup (str: proxy_b.uri);
146 proxies[2] = NULL;
147 }
148
149 last_proxies = g_strdupv (str_array: proxies);
150
151 return proxies;
152}
153
154static void
155g_test_proxy_resolver_lookup_async (GProxyResolver *resolver,
156 const gchar *uri,
157 GCancellable *cancellable,
158 GAsyncReadyCallback callback,
159 gpointer user_data)
160{
161 GError *error = NULL;
162 GTask *task;
163 gchar **proxies;
164
165 proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, error: &error);
166
167 task = g_task_new (source_object: resolver, NULL, callback, callback_data: user_data);
168 if (proxies == NULL)
169 g_task_return_error (task, error);
170 else
171 g_task_return_pointer (task, result: proxies, result_destroy: (GDestroyNotify) g_strfreev);
172
173 g_object_unref (object: task);
174}
175
176static gchar **
177g_test_proxy_resolver_lookup_finish (GProxyResolver *resolver,
178 GAsyncResult *result,
179 GError **error)
180{
181 return g_task_propagate_pointer (G_TASK (result), error);
182}
183
184static void
185g_test_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
186{
187}
188
189static void
190g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
191{
192 iface->is_supported = g_test_proxy_resolver_is_supported;
193 iface->lookup = g_test_proxy_resolver_lookup;
194 iface->lookup_async = g_test_proxy_resolver_lookup_async;
195 iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
196}
197
198/****************************/
199/* Alternate GProxyResolver */
200/****************************/
201
202typedef GTestProxyResolver GTestAltProxyResolver;
203typedef GTestProxyResolverClass GTestAltProxyResolverClass;
204
205static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface);
206
207static GType _g_test_alt_proxy_resolver_get_type (void);
208#define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type
209G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (),
210 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
211 g_test_alt_proxy_resolver_iface_init);
212 )
213
214static void
215g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver)
216{
217}
218
219static gchar **
220g_test_alt_proxy_resolver_lookup (GProxyResolver *resolver,
221 const gchar *uri,
222 GCancellable *cancellable,
223 GError **error)
224{
225 gchar **proxies;
226
227 proxies = g_new (gchar *, 2);
228
229 proxies[0] = g_strdup (str: proxy_a.uri);
230 proxies[1] = NULL;
231
232 last_proxies = g_strdupv (str_array: proxies);
233
234 return proxies;
235}
236
237static void
238g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
239{
240}
241
242static void
243g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface)
244{
245 iface->lookup = g_test_alt_proxy_resolver_lookup;
246}
247
248
249/****************************************/
250/* Test proxy implementation base class */
251/****************************************/
252
253typedef struct {
254 GObject parent;
255
256 ProxyData *proxy_data;
257} GProxyBase;
258
259typedef struct {
260 GObjectClass parent_class;
261} GProxyBaseClass;
262
263static GType _g_proxy_base_get_type (void);
264#define g_proxy_base_get_type _g_proxy_base_get_type
265G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT)
266
267static void
268g_proxy_base_init (GProxyBase *proxy)
269{
270}
271
272static GIOStream *
273g_proxy_base_connect (GProxy *proxy,
274 GIOStream *io_stream,
275 GProxyAddress *proxy_address,
276 GCancellable *cancellable,
277 GError **error)
278{
279 ProxyData *data = ((GProxyBase *) proxy)->proxy_data;
280 const gchar *protocol;
281 GOutputStream *ostream;
282 GInputStream *istream;
283 gchar response;
284
285 g_assert_no_error (data->last_error);
286
287 protocol = g_proxy_address_get_destination_protocol (proxy: proxy_address);
288 if (strcmp (s1: protocol, s2: data->supported_protocol) != 0)
289 {
290 g_set_error_literal (err: &data->last_error,
291 G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED,
292 message: "Unsupported protocol");
293 goto fail;
294 }
295
296 ostream = g_io_stream_get_output_stream (stream: io_stream);
297 if (g_output_stream_write (stream: ostream, buffer: data->proxy_command, count: 1, cancellable,
298 error: &data->last_error) != 1)
299 goto fail;
300
301 istream = g_io_stream_get_input_stream (stream: io_stream);
302 if (g_input_stream_read (stream: istream, buffer: &response, count: 1, cancellable,
303 error: &data->last_error) != 1)
304 goto fail;
305
306 if (response != g_ascii_toupper (c: *data->proxy_command))
307 {
308 g_set_error_literal (err: &data->last_error,
309 G_IO_ERROR, code: G_IO_ERROR_FAILED,
310 message: "Failed");
311 goto fail;
312 }
313
314 return g_object_ref (io_stream);
315
316 fail:
317 g_propagate_error (dest: error, src: g_error_copy (error: data->last_error));
318 return NULL;
319}
320
321static void
322g_proxy_base_connect_async (GProxy *proxy,
323 GIOStream *io_stream,
324 GProxyAddress *proxy_address,
325 GCancellable *cancellable,
326 GAsyncReadyCallback callback,
327 gpointer user_data)
328{
329 GError *error = NULL;
330 GTask *task;
331 GIOStream *proxy_io_stream;
332
333 task = g_task_new (source_object: proxy, NULL, callback, callback_data: user_data);
334
335 proxy_io_stream = g_proxy_connect (proxy, connection: io_stream, proxy_address,
336 cancellable, error: &error);
337 if (proxy_io_stream)
338 g_task_return_pointer (task, result: proxy_io_stream, result_destroy: g_object_unref);
339 else
340 g_task_return_error (task, error);
341 g_object_unref (object: task);
342}
343
344static GIOStream *
345g_proxy_base_connect_finish (GProxy *proxy,
346 GAsyncResult *result,
347 GError **error)
348{
349 return g_task_propagate_pointer (G_TASK (result), error);
350}
351
352static void
353g_proxy_base_class_init (GProxyBaseClass *class)
354{
355}
356
357
358/********************************************/
359/* Test proxy implementation #1 ("Proxy A") */
360/********************************************/
361
362typedef GProxyBase GProxyA;
363typedef GProxyBaseClass GProxyAClass;
364
365static void g_proxy_a_iface_init (GProxyInterface *proxy_iface);
366
367static GType _g_proxy_a_get_type (void);
368#define g_proxy_a_get_type _g_proxy_a_get_type
369G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (),
370 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
371 g_proxy_a_iface_init)
372 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
373 g_define_type_id,
374 "proxy-a",
375 0))
376
377static void
378g_proxy_a_init (GProxyA *proxy)
379{
380 ((GProxyBase *) proxy)->proxy_data = &proxy_a;
381}
382
383static gboolean
384g_proxy_a_supports_hostname (GProxy *proxy)
385{
386 return FALSE;
387}
388
389static void
390g_proxy_a_class_init (GProxyAClass *class)
391{
392}
393
394static void
395g_proxy_a_iface_init (GProxyInterface *proxy_iface)
396{
397 proxy_iface->connect = g_proxy_base_connect;
398 proxy_iface->connect_async = g_proxy_base_connect_async;
399 proxy_iface->connect_finish = g_proxy_base_connect_finish;
400 proxy_iface->supports_hostname = g_proxy_a_supports_hostname;
401}
402
403/********************************************/
404/* Test proxy implementation #2 ("Proxy B") */
405/********************************************/
406
407typedef GProxyBase GProxyB;
408typedef GProxyBaseClass GProxyBClass;
409
410static void g_proxy_b_iface_init (GProxyInterface *proxy_iface);
411
412static GType _g_proxy_b_get_type (void);
413#define g_proxy_b_get_type _g_proxy_b_get_type
414G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (),
415 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
416 g_proxy_b_iface_init)
417 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
418 g_define_type_id,
419 "proxy-b",
420 0))
421
422static void
423g_proxy_b_init (GProxyB *proxy)
424{
425 ((GProxyBase *) proxy)->proxy_data = &proxy_b;
426}
427
428static gboolean
429g_proxy_b_supports_hostname (GProxy *proxy)
430{
431 return TRUE;
432}
433
434static void
435g_proxy_b_class_init (GProxyBClass *class)
436{
437}
438
439static void
440g_proxy_b_iface_init (GProxyInterface *proxy_iface)
441{
442 proxy_iface->connect = g_proxy_base_connect;
443 proxy_iface->connect_async = g_proxy_base_connect_async;
444 proxy_iface->connect_finish = g_proxy_base_connect_finish;
445 proxy_iface->supports_hostname = g_proxy_b_supports_hostname;
446}
447
448
449/***********************************/
450/* The proxy server implementation */
451/***********************************/
452
453static gboolean
454proxy_bytes (GSocket *socket,
455 GIOCondition condition,
456 gpointer user_data)
457{
458 ProxyData *proxy = user_data;
459 gssize nread, nwrote, total;
460 gchar buffer[8];
461 GSocket *out_socket;
462 GError *error = NULL;
463
464 nread = g_socket_receive_with_blocking (socket, buffer, size: sizeof (buffer),
465 TRUE, NULL, error: &error);
466 if (nread == -1)
467 {
468 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
469 return FALSE;
470 }
471 else
472 g_assert_no_error (error);
473
474 if (nread == 0)
475 {
476 g_main_loop_quit (loop: proxy->loop);
477 return FALSE;
478 }
479
480 if (socket == proxy->client_sock)
481 out_socket = proxy->server_sock;
482 else
483 out_socket = proxy->client_sock;
484
485 for (total = 0; total < nread; total += nwrote)
486 {
487 nwrote = g_socket_send_with_blocking (socket: out_socket,
488 buffer: buffer + total, size: nread - total,
489 TRUE, NULL, error: &error);
490 g_assert_no_error (error);
491 }
492
493 return TRUE;
494}
495
496static gpointer
497proxy_thread (gpointer user_data)
498{
499 ProxyData *proxy = user_data;
500 GError *error = NULL;
501 gssize nread, nwrote;
502 gchar command[2] = { 0, 0 };
503 GMainContext *context;
504 GSource *read_source, *write_source;
505
506 context = g_main_context_new ();
507 proxy->loop = g_main_loop_new (context, FALSE);
508
509 while (TRUE)
510 {
511 proxy->client_sock = g_socket_accept (socket: proxy->server, cancellable: proxy->cancellable, error: &error);
512 if (!proxy->client_sock)
513 {
514 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
515 g_error_free (error);
516 break;
517 }
518 else
519 g_assert_no_error (error);
520
521 nread = g_socket_receive (socket: proxy->client_sock, buffer: command, size: 1, NULL, error: &error);
522 g_assert_no_error (error);
523
524 if (nread == 0)
525 {
526 g_clear_object (&proxy->client_sock);
527 continue;
528 }
529
530 g_assert_cmpint (nread, ==, 1);
531 g_assert_cmpstr (command, ==, proxy->proxy_command);
532
533 *command = g_ascii_toupper (c: *command);
534 nwrote = g_socket_send (socket: proxy->client_sock, buffer: command, size: 1, NULL, error: &error);
535 g_assert_no_error (error);
536 g_assert_cmpint (nwrote, ==, 1);
537
538 proxy->server_sock = g_socket_new (family: G_SOCKET_FAMILY_IPV4,
539 type: G_SOCKET_TYPE_STREAM,
540 protocol: G_SOCKET_PROTOCOL_DEFAULT,
541 error: &error);
542 g_assert_no_error (error);
543 g_socket_connect (socket: proxy->server_sock, address: server.server_addr, NULL, error: &error);
544 g_assert_no_error (error);
545
546 read_source = g_socket_create_source (socket: proxy->client_sock, condition: G_IO_IN, NULL);
547 g_source_set_callback (source: read_source, func: (GSourceFunc)proxy_bytes, data: proxy, NULL);
548 g_source_attach (source: read_source, context);
549
550 write_source = g_socket_create_source (socket: proxy->server_sock, condition: G_IO_IN, NULL);
551 g_source_set_callback (source: write_source, func: (GSourceFunc)proxy_bytes, data: proxy, NULL);
552 g_source_attach (source: write_source, context);
553
554 g_main_loop_run (loop: proxy->loop);
555
556 g_socket_close (socket: proxy->client_sock, error: &error);
557 g_assert_no_error (error);
558 g_clear_object (&proxy->client_sock);
559
560 g_socket_close (socket: proxy->server_sock, error: &error);
561 g_assert_no_error (error);
562 g_clear_object (&proxy->server_sock);
563
564 g_source_destroy (source: read_source);
565 g_source_unref (source: read_source);
566 g_source_destroy (source: write_source);
567 g_source_unref (source: write_source);
568 }
569
570 g_main_loop_unref (loop: proxy->loop);
571 g_main_context_unref (context);
572
573 g_object_unref (object: proxy->server);
574 g_object_unref (object: proxy->cancellable);
575
576 g_free (mem: proxy->proxy_command);
577 g_free (mem: proxy->supported_protocol);
578 g_free (mem: proxy->uri);
579
580 return NULL;
581}
582
583static void
584create_proxy (ProxyData *proxy,
585 gchar proxy_protocol,
586 const gchar *destination_protocol,
587 GCancellable *cancellable)
588{
589 GError *error = NULL;
590 GSocketAddress *addr;
591 GInetAddress *iaddr;
592
593 proxy->proxy_command = g_strdup_printf (format: "%c", proxy_protocol);
594 proxy->supported_protocol = g_strdup (str: destination_protocol);
595 proxy->cancellable = g_object_ref (cancellable);
596
597 proxy->server = g_socket_new (family: G_SOCKET_FAMILY_IPV4,
598 type: G_SOCKET_TYPE_STREAM,
599 protocol: G_SOCKET_PROTOCOL_DEFAULT,
600 error: &error);
601 g_assert_no_error (error);
602
603 iaddr = g_inet_address_new_loopback (family: G_SOCKET_FAMILY_IPV4);
604 addr = g_inet_socket_address_new (address: iaddr, port: 0);
605 g_object_unref (object: iaddr);
606
607 g_socket_bind (socket: proxy->server, address: addr, TRUE, error: &error);
608 g_assert_no_error (error);
609 g_object_unref (object: addr);
610
611 addr = g_socket_get_local_address (socket: proxy->server, error: &error);
612 proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
613 proxy->uri = g_strdup_printf (format: "proxy-%c://127.0.0.1:%u",
614 g_ascii_tolower (c: proxy_protocol),
615 proxy->port);
616 g_object_unref (object: addr);
617
618 g_socket_listen (socket: proxy->server, error: &error);
619 g_assert_no_error (error);
620
621 proxy->thread = g_thread_new (name: "proxy", func: proxy_thread, data: proxy);
622}
623
624
625
626/**************************/
627/* The actual echo server */
628/**************************/
629
630static gpointer
631echo_server_thread (gpointer user_data)
632{
633 ServerData *data = user_data;
634 GSocket *sock;
635 GError *error = NULL;
636 gssize nread, nwrote;
637 gchar buf[128];
638
639 while (TRUE)
640 {
641 sock = g_socket_accept (socket: data->server, cancellable: data->cancellable, error: &error);
642 if (!sock)
643 {
644 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
645 g_error_free (error);
646 break;
647 }
648 else
649 g_assert_no_error (error);
650
651 while (TRUE)
652 {
653 nread = g_socket_receive (socket: sock, buffer: buf, size: sizeof (buf), NULL, error: &error);
654 g_assert_no_error (error);
655 g_assert_cmpint (nread, >=, 0);
656
657 if (nread == 0)
658 break;
659
660 nwrote = g_socket_send (socket: sock, buffer: buf, size: nread, NULL, error: &error);
661 g_assert_no_error (error);
662 g_assert_cmpint (nwrote, ==, nread);
663 }
664
665 g_socket_close (socket: sock, error: &error);
666 g_assert_no_error (error);
667 g_object_unref (object: sock);
668 }
669
670 g_object_unref (object: data->server);
671 g_object_unref (object: data->server_addr);
672 g_object_unref (object: data->cancellable);
673
674 return NULL;
675}
676
677static void
678create_server (ServerData *data, GCancellable *cancellable)
679{
680 GError *error = NULL;
681 GSocketAddress *addr;
682 GInetAddress *iaddr;
683
684 data->cancellable = g_object_ref (cancellable);
685
686 data->server = g_socket_new (family: G_SOCKET_FAMILY_IPV4,
687 type: G_SOCKET_TYPE_STREAM,
688 protocol: G_SOCKET_PROTOCOL_DEFAULT,
689 error: &error);
690 g_assert_no_error (error);
691
692 g_socket_set_blocking (socket: data->server, TRUE);
693 iaddr = g_inet_address_new_loopback (family: G_SOCKET_FAMILY_IPV4);
694 addr = g_inet_socket_address_new (address: iaddr, port: 0);
695 g_object_unref (object: iaddr);
696
697 g_socket_bind (socket: data->server, address: addr, TRUE, error: &error);
698 g_assert_no_error (error);
699 g_object_unref (object: addr);
700
701 data->server_addr = g_socket_get_local_address (socket: data->server, error: &error);
702 g_assert_no_error (error);
703
704 data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr));
705
706 g_socket_listen (socket: data->server, error: &error);
707 g_assert_no_error (error);
708
709 data->server_thread = g_thread_new (name: "server", func: echo_server_thread, data);
710}
711
712
713/******************************************************************/
714/* Now a GResolver implementation, so the can't-resolve test will */
715/* pass even if you have an evil DNS-faking ISP. */
716/******************************************************************/
717
718typedef GResolver GFakeResolver;
719typedef GResolverClass GFakeResolverClass;
720
721static GType g_fake_resolver_get_type (void);
722G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
723
724static void
725g_fake_resolver_init (GFakeResolver *gtr)
726{
727}
728
729static GList *
730g_fake_resolver_lookup_by_name (GResolver *resolver,
731 const gchar *hostname,
732 GCancellable *cancellable,
733 GError **error)
734{
735 if (!strcmp (s1: hostname, s2: "example.com"))
736 return g_list_prepend (NULL, data: g_inet_address_new_from_string (string: "127.0.0.1"));
737 else
738 {
739 /* Anything else is expected to fail. */
740 g_set_error (err: error,
741 G_RESOLVER_ERROR,
742 code: G_RESOLVER_ERROR_NOT_FOUND,
743 format: "Not found");
744 return NULL;
745 }
746}
747
748static void
749g_fake_resolver_lookup_by_name_async (GResolver *resolver,
750 const gchar *hostname,
751 GCancellable *cancellable,
752 GAsyncReadyCallback callback,
753 gpointer user_data)
754{
755 GTask *task;
756
757 task = g_task_new (source_object: resolver, cancellable, callback, callback_data: user_data);
758
759 if (!strcmp (s1: hostname, s2: "example.com"))
760 {
761 GList *result;
762
763 result = g_list_prepend (NULL, data: g_inet_address_new_from_string (string: "127.0.0.1"));
764 g_task_return_pointer (task, result, result_destroy: (GDestroyNotify) g_resolver_free_addresses);
765 }
766 else
767 {
768 g_task_return_new_error (task,
769 G_RESOLVER_ERROR, code: G_RESOLVER_ERROR_NOT_FOUND,
770 format: "Not found");
771 }
772 g_object_unref (object: task);
773}
774
775static void
776g_fake_resolver_lookup_by_name_with_flags_async (GResolver *resolver,
777 const gchar *hostname,
778 GResolverNameLookupFlags flags,
779 GCancellable *cancellable,
780 GAsyncReadyCallback callback,
781 gpointer user_data)
782{
783 /* Note this isn't a real implementation as it ignores the flags */
784 g_fake_resolver_lookup_by_name_async (resolver,
785 hostname,
786 cancellable,
787 callback,
788 user_data);
789}
790
791static GList *
792g_fake_resolver_lookup_by_name_finish (GResolver *resolver,
793 GAsyncResult *result,
794 GError **error)
795{
796 return g_task_propagate_pointer (G_TASK (result), error);
797}
798
799static void
800g_fake_resolver_class_init (GFakeResolverClass *fake_class)
801{
802 GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class);
803
804 resolver_class->lookup_by_name = g_fake_resolver_lookup_by_name;
805 resolver_class->lookup_by_name_async = g_fake_resolver_lookup_by_name_async;
806 resolver_class->lookup_by_name_finish = g_fake_resolver_lookup_by_name_finish;
807 resolver_class->lookup_by_name_with_flags_async = g_fake_resolver_lookup_by_name_with_flags_async;
808 resolver_class->lookup_by_name_with_flags_finish = g_fake_resolver_lookup_by_name_finish;
809}
810
811
812
813/****************************************/
814/* We made it! Now for the actual test! */
815/****************************************/
816
817static void
818setup_test (gpointer fixture,
819 gconstpointer user_data)
820{
821}
822
823static void
824teardown_test (gpointer fixture,
825 gconstpointer user_data)
826{
827 if (last_proxies)
828 {
829 g_strfreev (str_array: last_proxies);
830 last_proxies = NULL;
831 }
832 g_clear_error (err: &proxy_a.last_error);
833 g_clear_error (err: &proxy_b.last_error);
834}
835
836
837static const gchar *testbuf = "0123456789abcdef";
838
839static void
840do_echo_test (GSocketConnection *conn)
841{
842 GIOStream *iostream = G_IO_STREAM (conn);
843 GInputStream *istream = g_io_stream_get_input_stream (stream: iostream);
844 GOutputStream *ostream = g_io_stream_get_output_stream (stream: iostream);
845 gssize nread, total;
846 gsize nwrote;
847 gchar buf[128];
848 GError *error = NULL;
849
850 g_output_stream_write_all (stream: ostream, buffer: testbuf, count: strlen (s: testbuf),
851 bytes_written: &nwrote, NULL, error: &error);
852 g_assert_no_error (error);
853 g_assert_cmpint (nwrote, ==, strlen (testbuf));
854
855 for (total = 0; total < nwrote; total += nread)
856 {
857 nread = g_input_stream_read (stream: istream,
858 buffer: buf + total, count: sizeof (buf) - total,
859 NULL, error: &error);
860 g_assert_no_error (error);
861 g_assert_cmpint (nread, >, 0);
862 }
863
864 buf[total] = '\0';
865 g_assert_cmpstr (buf, ==, testbuf);
866}
867
868static void
869async_got_conn (GObject *source,
870 GAsyncResult *result,
871 gpointer user_data)
872{
873 GSocketConnection **conn = user_data;
874 GError *error = NULL;
875
876 *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
877 result, error: &error);
878 g_assert_no_error (error);
879}
880
881static void
882async_got_error (GObject *source,
883 GAsyncResult *result,
884 gpointer user_data)
885{
886 GError **error = user_data;
887
888 g_assert (error != NULL && *error == NULL);
889 g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
890 result, error);
891 g_assert (*error != NULL);
892}
893
894
895static void
896assert_direct (GSocketConnection *conn)
897{
898 GSocketAddress *addr;
899 GError *error = NULL;
900
901 g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
902 g_assert_cmpstr (last_proxies[0], ==, "direct://");
903 g_assert_no_error (proxy_a.last_error);
904 g_assert_no_error (proxy_b.last_error);
905
906 addr = g_socket_connection_get_remote_address (connection: conn, error: &error);
907 g_assert_no_error (error);
908 g_assert (addr != NULL && !G_IS_PROXY_ADDRESS (addr));
909 g_object_unref (object: addr);
910
911 addr = g_socket_connection_get_local_address (connection: conn, error: &error);
912 g_assert_no_error (error);
913 g_object_unref (object: addr);
914
915 g_assert (g_socket_connection_is_connected (conn));
916}
917
918static void
919test_direct_sync (gpointer fixture,
920 gconstpointer user_data)
921{
922 GSocketConnection *conn;
923 gchar *uri;
924 GError *error = NULL;
925
926 /* The simple:// URI should not require any proxy. */
927
928 uri = g_strdup_printf (format: "simple://127.0.0.1:%u", server.server_port);
929 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
930 g_free (mem: uri);
931 g_assert_no_error (error);
932
933 assert_direct (conn);
934 do_echo_test (conn);
935 g_object_unref (object: conn);
936}
937
938static void
939test_direct_async (gpointer fixture,
940 gconstpointer user_data)
941{
942 GSocketConnection *conn;
943 gchar *uri;
944
945 /* The simple:// URI should not require any proxy. */
946 uri = g_strdup_printf (format: "simple://127.0.0.1:%u", server.server_port);
947 conn = NULL;
948 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
949 callback: async_got_conn, user_data: &conn);
950 g_free (mem: uri);
951 while (conn == NULL)
952 g_main_context_iteration (NULL, TRUE);
953
954 assert_direct (conn);
955 do_echo_test (conn);
956 g_object_unref (object: conn);
957}
958
959static void
960assert_single (GSocketConnection *conn)
961{
962 GSocketAddress *addr;
963 const gchar *proxy_uri;
964 gushort proxy_port;
965 GError *error = NULL;
966
967 g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
968 g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
969 g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
970 g_assert_no_error (proxy_a.last_error);
971 g_assert_no_error (proxy_b.last_error);
972
973 addr = g_socket_connection_get_remote_address (connection: conn, error: &error);
974 g_assert_no_error (error);
975 g_assert (G_IS_PROXY_ADDRESS (addr));
976 proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
977 g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
978 proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
979 g_assert_cmpint (proxy_port, ==, proxy_a.port);
980
981 g_object_unref (object: addr);
982}
983
984static void
985test_single_sync (gpointer fixture,
986 gconstpointer user_data)
987{
988 GSocketConnection *conn;
989 GError *error = NULL;
990 gchar *uri;
991
992 /* The alpha:// URI should be proxied via Proxy A */
993 uri = g_strdup_printf (format: "alpha://127.0.0.1:%u", server.server_port);
994 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
995 g_free (mem: uri);
996 g_assert_no_error (error);
997
998 assert_single (conn);
999
1000 do_echo_test (conn);
1001 g_object_unref (object: conn);
1002}
1003
1004static void
1005test_single_async (gpointer fixture,
1006 gconstpointer user_data)
1007{
1008 GSocketConnection *conn;
1009 gchar *uri;
1010
1011 /* The alpha:// URI should be proxied via Proxy A */
1012 uri = g_strdup_printf (format: "alpha://127.0.0.1:%u", server.server_port);
1013 conn = NULL;
1014 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1015 callback: async_got_conn, user_data: &conn);
1016 g_free (mem: uri);
1017 while (conn == NULL)
1018 g_main_context_iteration (NULL, TRUE);
1019
1020 assert_single (conn);
1021 do_echo_test (conn);
1022 g_object_unref (object: conn);
1023}
1024
1025static void
1026assert_multiple (GSocketConnection *conn)
1027{
1028 GSocketAddress *addr;
1029 const gchar *proxy_uri;
1030 gushort proxy_port;
1031 GError *error = NULL;
1032
1033 g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
1034 g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1035 g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
1036 g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1037 g_assert_no_error (proxy_b.last_error);
1038
1039 addr = g_socket_connection_get_remote_address (connection: conn, error: &error);
1040 g_assert_no_error (error);
1041 g_assert (G_IS_PROXY_ADDRESS (addr));
1042 proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
1043 g_assert_cmpstr (proxy_uri, ==, proxy_b.uri);
1044 proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1045 g_assert_cmpint (proxy_port, ==, proxy_b.port);
1046
1047 g_object_unref (object: addr);
1048}
1049
1050static void
1051test_multiple_sync (gpointer fixture,
1052 gconstpointer user_data)
1053{
1054 GSocketConnection *conn;
1055 GError *error = NULL;
1056 gchar *uri;
1057
1058 /* The beta:// URI should be proxied via Proxy B, after failing
1059 * via Proxy A.
1060 */
1061 uri = g_strdup_printf (format: "beta://127.0.0.1:%u", server.server_port);
1062 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1063 g_free (mem: uri);
1064 g_assert_no_error (error);
1065
1066 assert_multiple (conn);
1067 do_echo_test (conn);
1068 g_object_unref (object: conn);
1069}
1070
1071static void
1072test_multiple_async (gpointer fixture,
1073 gconstpointer user_data)
1074{
1075 GSocketConnection *conn;
1076 gchar *uri;
1077
1078 /* The beta:// URI should be proxied via Proxy B, after failing
1079 * via Proxy A.
1080 */
1081 uri = g_strdup_printf (format: "beta://127.0.0.1:%u", server.server_port);
1082 conn = NULL;
1083 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1084 callback: async_got_conn, user_data: &conn);
1085 g_free (mem: uri);
1086 while (conn == NULL)
1087 g_main_context_iteration (NULL, TRUE);
1088
1089 assert_multiple (conn);
1090 do_echo_test (conn);
1091 g_object_unref (object: conn);
1092}
1093
1094static void
1095test_dns (gpointer fixture,
1096 gconstpointer user_data)
1097{
1098 GSocketConnection *conn;
1099 GError *error = NULL;
1100 gchar *uri;
1101
1102 /* The simple:// and alpha:// URIs should fail with a DNS error,
1103 * but the beta:// URI should succeed, because we pass it to
1104 * Proxy B without trying to resolve it first
1105 */
1106
1107 /* simple */
1108 uri = g_strdup_printf (format: "simple://no-such-host.xx:%u", server.server_port);
1109 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1110 g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1111 g_clear_error (err: &error);
1112
1113 g_assert_no_error (proxy_a.last_error);
1114 g_assert_no_error (proxy_b.last_error);
1115 teardown_test (NULL, NULL);
1116
1117 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1118 callback: async_got_error, user_data: &error);
1119 while (error == NULL)
1120 g_main_context_iteration (NULL, TRUE);
1121 g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1122 g_clear_error (err: &error);
1123 g_free (mem: uri);
1124
1125 g_assert_no_error (proxy_a.last_error);
1126 g_assert_no_error (proxy_b.last_error);
1127 teardown_test (NULL, NULL);
1128
1129 /* alpha */
1130 uri = g_strdup_printf (format: "alpha://no-such-host.xx:%u", server.server_port);
1131 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1132 /* Since Proxy A fails, @client will try Proxy B too, which won't
1133 * load an alpha:// URI.
1134 */
1135 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1136 g_clear_error (err: &error);
1137
1138 g_assert_no_error (proxy_a.last_error);
1139 g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1140 teardown_test (NULL, NULL);
1141
1142 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1143 callback: async_got_error, user_data: &error);
1144 while (error == NULL)
1145 g_main_context_iteration (NULL, TRUE);
1146 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1147 g_clear_error (err: &error);
1148 g_free (mem: uri);
1149
1150 g_assert_no_error (proxy_a.last_error);
1151 g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1152 teardown_test (NULL, NULL);
1153
1154 /* beta */
1155 uri = g_strdup_printf (format: "beta://no-such-host.xx:%u", server.server_port);
1156 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1157 g_assert_no_error (error);
1158
1159 g_assert_no_error (proxy_a.last_error);
1160 g_assert_no_error (proxy_b.last_error);
1161
1162 do_echo_test (conn);
1163 g_clear_object (&conn);
1164 teardown_test (NULL, NULL);
1165
1166 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1167 callback: async_got_conn, user_data: &conn);
1168 while (conn == NULL)
1169 g_main_context_iteration (NULL, TRUE);
1170 g_free (mem: uri);
1171
1172 g_assert_no_error (proxy_a.last_error);
1173 g_assert_no_error (proxy_b.last_error);
1174
1175 do_echo_test (conn);
1176 g_clear_object (&conn);
1177 teardown_test (NULL, NULL);
1178}
1179
1180static void
1181assert_override (GSocketConnection *conn)
1182{
1183 g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
1184 g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1185
1186 if (conn)
1187 g_assert_no_error (proxy_a.last_error);
1188 else
1189 g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1190}
1191
1192static void
1193test_override (gpointer fixture,
1194 gconstpointer user_data)
1195{
1196 GProxyResolver *alt_resolver;
1197 GSocketConnection *conn;
1198 GError *error = NULL;
1199 gchar *uri;
1200
1201 g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
1202 alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL);
1203 g_socket_client_set_proxy_resolver (client, proxy_resolver: alt_resolver);
1204 g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
1205
1206 /* Alt proxy resolver always returns Proxy A, so alpha:// should
1207 * succeed, and simple:// and beta:// should fail.
1208 */
1209
1210 /* simple */
1211 uri = g_strdup_printf (format: "simple://127.0.0.1:%u", server.server_port);
1212 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1213 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1214 g_clear_error (err: &error);
1215 assert_override (conn);
1216 teardown_test (NULL, NULL);
1217
1218 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1219 callback: async_got_error, user_data: &error);
1220 while (error == NULL)
1221 g_main_context_iteration (NULL, TRUE);
1222 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1223 g_clear_error (err: &error);
1224 assert_override (conn);
1225 g_free (mem: uri);
1226 teardown_test (NULL, NULL);
1227
1228 /* alpha */
1229 uri = g_strdup_printf (format: "alpha://127.0.0.1:%u", server.server_port);
1230 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1231 g_assert_no_error (error);
1232 assert_override (conn);
1233 do_echo_test (conn);
1234 g_clear_object (&conn);
1235 teardown_test (NULL, NULL);
1236
1237 conn = NULL;
1238 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1239 callback: async_got_conn, user_data: &conn);
1240 while (conn == NULL)
1241 g_main_context_iteration (NULL, TRUE);
1242 assert_override (conn);
1243 do_echo_test (conn);
1244 g_clear_object (&conn);
1245 g_free (mem: uri);
1246 teardown_test (NULL, NULL);
1247
1248 /* beta */
1249 uri = g_strdup_printf (format: "beta://127.0.0.1:%u", server.server_port);
1250 conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error);
1251 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1252 g_clear_error (err: &error);
1253 assert_override (conn);
1254 teardown_test (NULL, NULL);
1255
1256 g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL,
1257 callback: async_got_error, user_data: &error);
1258 while (error == NULL)
1259 g_main_context_iteration (NULL, TRUE);
1260 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1261 g_clear_error (err: &error);
1262 assert_override (conn);
1263 g_free (mem: uri);
1264 teardown_test (NULL, NULL);
1265
1266 g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
1267 g_socket_client_set_proxy_resolver (client, NULL);
1268 g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
1269 g_object_unref (object: alt_resolver);
1270}
1271
1272static void
1273assert_destination_port (GSocketAddressEnumerator *etor,
1274 guint16 port)
1275{
1276 GSocketAddress *addr;
1277 GProxyAddress *paddr;
1278 GError *error = NULL;
1279
1280 while ((addr = g_socket_address_enumerator_next (enumerator: etor, NULL, error: &error)))
1281 {
1282 g_assert_no_error (error);
1283
1284 g_assert (G_IS_PROXY_ADDRESS (addr));
1285 paddr = G_PROXY_ADDRESS (addr);
1286 g_assert_cmpint (g_proxy_address_get_destination_port (paddr), ==, port);
1287 g_object_unref (object: addr);
1288 }
1289 g_assert_no_error (error);
1290}
1291
1292static void
1293test_proxy_enumerator_ports (void)
1294{
1295 GSocketAddressEnumerator *etor;
1296
1297 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1298 first_property_name: "uri", "http://example.com/",
1299 NULL);
1300 assert_destination_port (etor, port: 0);
1301 g_object_unref (object: etor);
1302
1303 /* Have to call this to clear last_proxies so the next call to
1304 * g_test_proxy_resolver_lookup() won't assert.
1305 */
1306 teardown_test (NULL, NULL);
1307
1308 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1309 first_property_name: "uri", "http://example.com:8080/",
1310 NULL);
1311 assert_destination_port (etor, port: 8080);
1312 g_object_unref (object: etor);
1313
1314 teardown_test (NULL, NULL);
1315
1316 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1317 first_property_name: "uri", "http://example.com/",
1318 "default-port", 80,
1319 NULL);
1320 assert_destination_port (etor, port: 80);
1321 g_object_unref (object: etor);
1322
1323 teardown_test (NULL, NULL);
1324
1325 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1326 first_property_name: "uri", "http://example.com:8080/",
1327 "default-port", 80,
1328 NULL);
1329 assert_destination_port (etor, port: 8080);
1330 g_object_unref (object: etor);
1331
1332 teardown_test (NULL, NULL);
1333}
1334
1335int
1336main (int argc,
1337 char *argv[])
1338{
1339 GResolver *fake_resolver;
1340 GCancellable *cancellable;
1341 gint result;
1342
1343 g_test_init (argc: &argc, argv: &argv, NULL);
1344
1345 /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
1346 * is to force _g_io_modules_ensure_extension_points_registered() to
1347 * get called, so we can then register a proxy resolver extension
1348 * point.
1349 */
1350 g_proxy_get_default_for_protocol (protocol: "foo");
1351 g_test_proxy_resolver_get_type ();
1352 g_proxy_a_get_type ();
1353 g_proxy_b_get_type ();
1354 g_setenv (variable: "GIO_USE_PROXY_RESOLVER", value: "test", TRUE);
1355
1356 fake_resolver = g_object_new (object_type: g_fake_resolver_get_type (), NULL);
1357 g_resolver_set_default (resolver: fake_resolver);
1358
1359 cancellable = g_cancellable_new ();
1360 create_server (data: &server, cancellable);
1361 create_proxy (proxy: &proxy_a, proxy_protocol: 'a', destination_protocol: "alpha", cancellable);
1362 create_proxy (proxy: &proxy_b, proxy_protocol: 'b', destination_protocol: "beta", cancellable);
1363
1364 client = g_socket_client_new ();
1365 g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE);
1366
1367 g_test_add_vtable (testpath: "/proxy/direct_sync", data_size: 0, NULL, data_setup: setup_test, data_test: test_direct_sync, data_teardown: teardown_test);
1368 g_test_add_vtable (testpath: "/proxy/direct_async", data_size: 0, NULL, data_setup: setup_test, data_test: test_direct_async, data_teardown: teardown_test);
1369 g_test_add_vtable (testpath: "/proxy/single_sync", data_size: 0, NULL, data_setup: setup_test, data_test: test_single_sync, data_teardown: teardown_test);
1370 g_test_add_vtable (testpath: "/proxy/single_async", data_size: 0, NULL, data_setup: setup_test, data_test: test_single_async, data_teardown: teardown_test);
1371 g_test_add_vtable (testpath: "/proxy/multiple_sync", data_size: 0, NULL, data_setup: setup_test, data_test: test_multiple_sync, data_teardown: teardown_test);
1372 g_test_add_vtable (testpath: "/proxy/multiple_async", data_size: 0, NULL, data_setup: setup_test, data_test: test_multiple_async, data_teardown: teardown_test);
1373 g_test_add_vtable (testpath: "/proxy/dns", data_size: 0, NULL, data_setup: setup_test, data_test: test_dns, data_teardown: teardown_test);
1374 g_test_add_vtable (testpath: "/proxy/override", data_size: 0, NULL, data_setup: setup_test, data_test: test_override, data_teardown: teardown_test);
1375 g_test_add_func (testpath: "/proxy/enumerator-ports", test_func: test_proxy_enumerator_ports);
1376
1377 result = g_test_run();
1378
1379 g_object_unref (object: client);
1380
1381 g_cancellable_cancel (cancellable);
1382 g_thread_join (thread: proxy_a.thread);
1383 g_thread_join (thread: proxy_b.thread);
1384 g_thread_join (thread: server.server_thread);
1385
1386 g_object_unref (object: cancellable);
1387
1388 return result;
1389}
1390

source code of gtk/subprojects/glib/gio/tests/proxy-test.c