1 /* GLib testing framework examples and tests
3 * Copyright 2012 Red Hat, Inc.
5 * SPDX-License-Identifier: LGPL-2.1-or-later
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 * We have an echo server, two proxy servers, two GProxy
28 * implementations, and two GProxyResolver implementations.
30 * The echo server runs at @server.server_addr (on
31 * @server.server_port).
33 * The two proxy servers, A and B, run on @proxy_a.port and
34 * @proxy_b.port, with @proxy_a.uri and @proxy_b.uri pointing to them.
35 * The "negotiation" with the two proxies is just sending the single
36 * letter "a" or "b" and receiving it back in uppercase; the proxy
37 * then connects to @server_addr.
39 * Proxy A supports "alpha://" URIs, and does not support hostname
40 * resolution, and Proxy B supports "beta://" URIs, and does support
41 * hostname resolution (but it just ignores the hostname and always
42 * connects to @server_addr anyway).
44 * The default GProxyResolver (GTestProxyResolver) looks at its URI
45 * and returns [ "direct://" ] for "simple://" URIs, and
46 * [ proxy_a.uri, proxy_b.uri ] for most other URIs. It can also return
47 * invalid results for other URIs (empty://, invalid://,
48 * invalid-then-simple://, and simple-then-invalid://) to test error
51 * The other GProxyResolver (GTestAltProxyResolver) always returns
57 gchar *supported_protocol;
61 GCancellable *cancellable;
65 GSocket *client_sock, *server_sock;
71 static ProxyData proxy_a, proxy_b;
75 GThread *server_thread;
76 GCancellable *cancellable;
77 GSocketAddress *server_addr;
81 static ServerData server;
83 static gchar **last_proxies;
85 static GSocketClient *client;
88 /**************************************/
89 /* Test GProxyResolver implementation */
90 /**************************************/
93 GObject parent_instance;
97 GObjectClass parent_class;
98 } GTestProxyResolverClass;
100 static void g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface);
102 static GType _g_test_proxy_resolver_get_type (void);
103 #define g_test_proxy_resolver_get_type _g_test_proxy_resolver_get_type
104 G_DEFINE_TYPE_WITH_CODE (GTestProxyResolver, g_test_proxy_resolver, G_TYPE_OBJECT,
105 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
106 g_test_proxy_resolver_iface_init)
107 g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
113 g_test_proxy_resolver_init (GTestProxyResolver *resolver)
118 g_test_proxy_resolver_is_supported (GProxyResolver *resolver)
124 g_test_proxy_resolver_lookup (GProxyResolver *resolver,
126 GCancellable *cancellable,
131 g_assert (last_proxies == NULL);
133 if (g_cancellable_set_error_if_cancelled (cancellable, error))
136 proxies = g_new (gchar *, 3);
138 if (g_str_has_prefix (uri, "simple://"))
140 proxies[0] = g_strdup ("direct://");
143 else if (g_str_has_prefix (uri, "empty://"))
145 proxies[0] = g_strdup ("");
148 else if (g_str_has_prefix (uri, "invalid://"))
150 proxies[0] = g_strdup ("😼");
153 else if (g_str_has_prefix (uri, "invalid-then-simple://"))
155 proxies[0] = g_strdup ("😼");
156 proxies[1] = g_strdup ("direct://");
159 else if (g_str_has_prefix (uri, "simple-then-invalid://"))
161 proxies[0] = g_strdup ("direct://");
162 proxies[1] = g_strdup ("😼");
167 /* Proxy A can only deal with "alpha://" URIs, not
168 * "beta://", but we always return both URIs
169 * anyway so we can test error handling when the first
172 proxies[0] = g_strdup (proxy_a.uri);
173 proxies[1] = g_strdup (proxy_b.uri);
177 last_proxies = g_strdupv (proxies);
183 g_test_proxy_resolver_lookup_async (GProxyResolver *resolver,
185 GCancellable *cancellable,
186 GAsyncReadyCallback callback,
189 GError *error = NULL;
193 proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
195 task = g_task_new (resolver, NULL, callback, user_data);
196 g_task_set_source_tag (task, g_test_proxy_resolver_lookup_async);
198 g_task_return_error (task, error);
200 g_task_return_pointer (task, proxies, (GDestroyNotify) g_strfreev);
202 g_object_unref (task);
206 g_test_proxy_resolver_lookup_finish (GProxyResolver *resolver,
207 GAsyncResult *result,
210 g_assert_true (g_task_is_valid (result, resolver));
211 g_assert_true (g_task_get_source_tag (G_TASK (result)) == g_test_proxy_resolver_lookup_async);
213 return g_task_propagate_pointer (G_TASK (result), error);
217 g_test_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
222 g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
224 iface->is_supported = g_test_proxy_resolver_is_supported;
225 iface->lookup = g_test_proxy_resolver_lookup;
226 iface->lookup_async = g_test_proxy_resolver_lookup_async;
227 iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
230 /****************************/
231 /* Alternate GProxyResolver */
232 /****************************/
234 typedef GTestProxyResolver GTestAltProxyResolver;
235 typedef GTestProxyResolverClass GTestAltProxyResolverClass;
237 static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface);
239 static GType _g_test_alt_proxy_resolver_get_type (void);
240 #define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type
241 G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (),
242 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
243 g_test_alt_proxy_resolver_iface_init);
247 g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver)
252 g_test_alt_proxy_resolver_lookup (GProxyResolver *resolver,
254 GCancellable *cancellable,
259 proxies = g_new (gchar *, 2);
261 proxies[0] = g_strdup (proxy_a.uri);
264 last_proxies = g_strdupv (proxies);
270 g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
275 g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface)
277 iface->lookup = g_test_alt_proxy_resolver_lookup;
281 /****************************************/
282 /* Test proxy implementation base class */
283 /****************************************/
288 ProxyData *proxy_data;
292 GObjectClass parent_class;
295 static GType _g_proxy_base_get_type (void);
296 #define g_proxy_base_get_type _g_proxy_base_get_type
297 G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT)
300 g_proxy_base_init (GProxyBase *proxy)
305 g_proxy_base_connect (GProxy *proxy,
306 GIOStream *io_stream,
307 GProxyAddress *proxy_address,
308 GCancellable *cancellable,
311 ProxyData *data = ((GProxyBase *) proxy)->proxy_data;
312 const gchar *protocol;
313 GOutputStream *ostream;
314 GInputStream *istream;
317 g_assert_no_error (data->last_error);
319 protocol = g_proxy_address_get_destination_protocol (proxy_address);
320 if (strcmp (protocol, data->supported_protocol) != 0)
322 g_set_error_literal (&data->last_error,
323 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
324 "Unsupported protocol");
328 ostream = g_io_stream_get_output_stream (io_stream);
329 if (g_output_stream_write (ostream, data->proxy_command, 1, cancellable,
330 &data->last_error) != 1)
333 istream = g_io_stream_get_input_stream (io_stream);
334 if (g_input_stream_read (istream, &response, 1, cancellable,
335 &data->last_error) != 1)
338 if (response != g_ascii_toupper (*data->proxy_command))
340 g_set_error_literal (&data->last_error,
341 G_IO_ERROR, G_IO_ERROR_FAILED,
346 return g_object_ref (io_stream);
349 g_propagate_error (error, g_error_copy (data->last_error));
354 g_proxy_base_connect_async (GProxy *proxy,
355 GIOStream *io_stream,
356 GProxyAddress *proxy_address,
357 GCancellable *cancellable,
358 GAsyncReadyCallback callback,
361 GError *error = NULL;
363 GIOStream *proxy_io_stream;
365 task = g_task_new (proxy, NULL, callback, user_data);
367 proxy_io_stream = g_proxy_connect (proxy, io_stream, proxy_address,
368 cancellable, &error);
370 g_task_return_pointer (task, proxy_io_stream, g_object_unref);
372 g_task_return_error (task, error);
373 g_object_unref (task);
377 g_proxy_base_connect_finish (GProxy *proxy,
378 GAsyncResult *result,
381 return g_task_propagate_pointer (G_TASK (result), error);
385 g_proxy_base_class_init (GProxyBaseClass *class)
390 /********************************************/
391 /* Test proxy implementation #1 ("Proxy A") */
392 /********************************************/
394 typedef GProxyBase GProxyA;
395 typedef GProxyBaseClass GProxyAClass;
397 static void g_proxy_a_iface_init (GProxyInterface *proxy_iface);
399 static GType _g_proxy_a_get_type (void);
400 #define g_proxy_a_get_type _g_proxy_a_get_type
401 G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (),
402 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
403 g_proxy_a_iface_init)
404 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
410 g_proxy_a_init (GProxyA *proxy)
412 ((GProxyBase *) proxy)->proxy_data = &proxy_a;
416 g_proxy_a_supports_hostname (GProxy *proxy)
422 g_proxy_a_class_init (GProxyAClass *class)
427 g_proxy_a_iface_init (GProxyInterface *proxy_iface)
429 proxy_iface->connect = g_proxy_base_connect;
430 proxy_iface->connect_async = g_proxy_base_connect_async;
431 proxy_iface->connect_finish = g_proxy_base_connect_finish;
432 proxy_iface->supports_hostname = g_proxy_a_supports_hostname;
435 /********************************************/
436 /* Test proxy implementation #2 ("Proxy B") */
437 /********************************************/
439 typedef GProxyBase GProxyB;
440 typedef GProxyBaseClass GProxyBClass;
442 static void g_proxy_b_iface_init (GProxyInterface *proxy_iface);
444 static GType _g_proxy_b_get_type (void);
445 #define g_proxy_b_get_type _g_proxy_b_get_type
446 G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (),
447 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
448 g_proxy_b_iface_init)
449 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
455 g_proxy_b_init (GProxyB *proxy)
457 ((GProxyBase *) proxy)->proxy_data = &proxy_b;
461 g_proxy_b_supports_hostname (GProxy *proxy)
467 g_proxy_b_class_init (GProxyBClass *class)
472 g_proxy_b_iface_init (GProxyInterface *proxy_iface)
474 proxy_iface->connect = g_proxy_base_connect;
475 proxy_iface->connect_async = g_proxy_base_connect_async;
476 proxy_iface->connect_finish = g_proxy_base_connect_finish;
477 proxy_iface->supports_hostname = g_proxy_b_supports_hostname;
481 /***********************************/
482 /* The proxy server implementation */
483 /***********************************/
486 proxy_bytes (GSocket *socket,
487 GIOCondition condition,
490 ProxyData *proxy = user_data;
491 gssize nread, nwrote, total;
494 GError *error = NULL;
496 nread = g_socket_receive_with_blocking (socket, buffer, sizeof (buffer),
500 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
504 g_assert_no_error (error);
508 g_main_loop_quit (proxy->loop);
512 if (socket == proxy->client_sock)
513 out_socket = proxy->server_sock;
515 out_socket = proxy->client_sock;
517 for (total = 0; total < nread; total += nwrote)
519 nwrote = g_socket_send_with_blocking (out_socket,
520 buffer + total, nread - total,
522 g_assert_no_error (error);
529 proxy_thread (gpointer user_data)
531 ProxyData *proxy = user_data;
532 GError *error = NULL;
533 gssize nread, nwrote;
534 gchar command[2] = { 0, 0 };
535 GMainContext *context;
536 GSource *read_source, *write_source;
538 context = g_main_context_new ();
539 proxy->loop = g_main_loop_new (context, FALSE);
543 proxy->client_sock = g_socket_accept (proxy->server, proxy->cancellable, &error);
544 if (!proxy->client_sock)
546 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
547 g_error_free (error);
551 g_assert_no_error (error);
553 nread = g_socket_receive (proxy->client_sock, command, 1, NULL, &error);
554 g_assert_no_error (error);
558 g_clear_object (&proxy->client_sock);
562 g_assert_cmpint (nread, ==, 1);
563 g_assert_cmpstr (command, ==, proxy->proxy_command);
565 *command = g_ascii_toupper (*command);
566 nwrote = g_socket_send (proxy->client_sock, command, 1, NULL, &error);
567 g_assert_no_error (error);
568 g_assert_cmpint (nwrote, ==, 1);
570 proxy->server_sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
571 G_SOCKET_TYPE_STREAM,
572 G_SOCKET_PROTOCOL_DEFAULT,
574 g_assert_no_error (error);
575 g_socket_connect (proxy->server_sock, server.server_addr, NULL, &error);
576 g_assert_no_error (error);
578 read_source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
579 g_source_set_callback (read_source, (GSourceFunc)proxy_bytes, proxy, NULL);
580 g_source_attach (read_source, context);
582 write_source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
583 g_source_set_callback (write_source, (GSourceFunc)proxy_bytes, proxy, NULL);
584 g_source_attach (write_source, context);
586 g_main_loop_run (proxy->loop);
588 g_socket_close (proxy->client_sock, &error);
589 g_assert_no_error (error);
590 g_clear_object (&proxy->client_sock);
592 g_socket_close (proxy->server_sock, &error);
593 g_assert_no_error (error);
594 g_clear_object (&proxy->server_sock);
596 g_source_destroy (read_source);
597 g_source_unref (read_source);
598 g_source_destroy (write_source);
599 g_source_unref (write_source);
602 g_main_loop_unref (proxy->loop);
603 g_main_context_unref (context);
605 g_object_unref (proxy->server);
606 g_object_unref (proxy->cancellable);
608 g_free (proxy->proxy_command);
609 g_free (proxy->supported_protocol);
616 create_proxy (ProxyData *proxy,
617 gchar proxy_protocol,
618 const gchar *destination_protocol,
619 GCancellable *cancellable)
621 GError *error = NULL;
622 GSocketAddress *addr;
625 proxy->proxy_command = g_strdup_printf ("%c", proxy_protocol);
626 proxy->supported_protocol = g_strdup (destination_protocol);
627 proxy->cancellable = g_object_ref (cancellable);
629 proxy->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
630 G_SOCKET_TYPE_STREAM,
631 G_SOCKET_PROTOCOL_DEFAULT,
633 g_assert_no_error (error);
635 iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
636 addr = g_inet_socket_address_new (iaddr, 0);
637 g_object_unref (iaddr);
639 g_socket_bind (proxy->server, addr, TRUE, &error);
640 g_assert_no_error (error);
641 g_object_unref (addr);
643 addr = g_socket_get_local_address (proxy->server, &error);
644 proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
645 proxy->uri = g_strdup_printf ("proxy-%c://127.0.0.1:%u",
646 g_ascii_tolower (proxy_protocol),
648 g_object_unref (addr);
650 g_socket_listen (proxy->server, &error);
651 g_assert_no_error (error);
653 proxy->thread = g_thread_new ("proxy", proxy_thread, proxy);
658 /**************************/
659 /* The actual echo server */
660 /**************************/
663 echo_server_thread (gpointer user_data)
665 ServerData *data = user_data;
667 GError *error = NULL;
668 gssize nread, nwrote;
673 sock = g_socket_accept (data->server, data->cancellable, &error);
676 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
677 g_error_free (error);
681 g_assert_no_error (error);
685 nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
686 g_assert_no_error (error);
687 g_assert_cmpint (nread, >=, 0);
692 nwrote = g_socket_send (sock, buf, nread, NULL, &error);
693 g_assert_no_error (error);
694 g_assert_cmpint (nwrote, ==, nread);
697 g_socket_close (sock, &error);
698 g_assert_no_error (error);
699 g_object_unref (sock);
702 g_object_unref (data->server);
703 g_object_unref (data->server_addr);
704 g_object_unref (data->cancellable);
710 create_server (ServerData *data, GCancellable *cancellable)
712 GError *error = NULL;
713 GSocketAddress *addr;
716 data->cancellable = g_object_ref (cancellable);
718 data->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
719 G_SOCKET_TYPE_STREAM,
720 G_SOCKET_PROTOCOL_DEFAULT,
722 g_assert_no_error (error);
724 g_socket_set_blocking (data->server, TRUE);
725 iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
726 addr = g_inet_socket_address_new (iaddr, 0);
727 g_object_unref (iaddr);
729 g_socket_bind (data->server, addr, TRUE, &error);
730 g_assert_no_error (error);
731 g_object_unref (addr);
733 data->server_addr = g_socket_get_local_address (data->server, &error);
734 g_assert_no_error (error);
736 data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr));
738 g_socket_listen (data->server, &error);
739 g_assert_no_error (error);
741 data->server_thread = g_thread_new ("server", echo_server_thread, data);
745 /******************************************************************/
746 /* Now a GResolver implementation, so the can't-resolve test will */
747 /* pass even if you have an evil DNS-faking ISP. */
748 /******************************************************************/
750 typedef GResolver GFakeResolver;
751 typedef GResolverClass GFakeResolverClass;
753 static GType g_fake_resolver_get_type (void);
754 G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
757 g_fake_resolver_init (GFakeResolver *gtr)
762 g_fake_resolver_lookup_by_name (GResolver *resolver,
763 const gchar *hostname,
764 GCancellable *cancellable,
767 if (!strcmp (hostname, "example.com"))
768 return g_list_prepend (NULL, g_inet_address_new_from_string ("127.0.0.1"));
771 /* Anything else is expected to fail. */
774 G_RESOLVER_ERROR_NOT_FOUND,
781 g_fake_resolver_lookup_by_name_async (GResolver *resolver,
782 const gchar *hostname,
783 GCancellable *cancellable,
784 GAsyncReadyCallback callback,
789 task = g_task_new (resolver, cancellable, callback, user_data);
791 if (!strcmp (hostname, "example.com"))
795 result = g_list_prepend (NULL, g_inet_address_new_from_string ("127.0.0.1"));
796 g_task_return_pointer (task, result, (GDestroyNotify) g_resolver_free_addresses);
800 g_task_return_new_error (task,
801 G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
804 g_object_unref (task);
808 g_fake_resolver_lookup_by_name_with_flags_async (GResolver *resolver,
809 const gchar *hostname,
810 GResolverNameLookupFlags flags,
811 GCancellable *cancellable,
812 GAsyncReadyCallback callback,
815 /* Note this isn't a real implementation as it ignores the flags */
816 g_fake_resolver_lookup_by_name_async (resolver,
824 g_fake_resolver_lookup_by_name_finish (GResolver *resolver,
825 GAsyncResult *result,
828 return g_task_propagate_pointer (G_TASK (result), error);
832 g_fake_resolver_class_init (GFakeResolverClass *fake_class)
834 GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class);
836 resolver_class->lookup_by_name = g_fake_resolver_lookup_by_name;
837 resolver_class->lookup_by_name_async = g_fake_resolver_lookup_by_name_async;
838 resolver_class->lookup_by_name_finish = g_fake_resolver_lookup_by_name_finish;
839 resolver_class->lookup_by_name_with_flags_async = g_fake_resolver_lookup_by_name_with_flags_async;
840 resolver_class->lookup_by_name_with_flags_finish = g_fake_resolver_lookup_by_name_finish;
845 /****************************************/
846 /* We made it! Now for the actual test! */
847 /****************************************/
850 setup_test (gpointer fixture,
851 gconstpointer user_data)
856 teardown_test (gpointer fixture,
857 gconstpointer user_data)
859 g_clear_pointer (&last_proxies, g_strfreev);
861 g_clear_error (&proxy_a.last_error);
862 g_clear_error (&proxy_b.last_error);
866 static const gchar *testbuf = "0123456789abcdef";
869 do_echo_test (GSocketConnection *conn)
871 GIOStream *iostream = G_IO_STREAM (conn);
872 GInputStream *istream = g_io_stream_get_input_stream (iostream);
873 GOutputStream *ostream = g_io_stream_get_output_stream (iostream);
877 GError *error = NULL;
879 g_output_stream_write_all (ostream, testbuf, strlen (testbuf),
880 &nwrote, NULL, &error);
881 g_assert_no_error (error);
882 g_assert_cmpint (nwrote, ==, strlen (testbuf));
884 for (total = 0; total < nwrote; total += nread)
886 nread = g_input_stream_read (istream,
887 buf + total, sizeof (buf) - total,
889 g_assert_no_error (error);
890 g_assert_cmpint (nread, >, 0);
894 g_assert_cmpstr (buf, ==, testbuf);
898 async_got_conn (GObject *source,
899 GAsyncResult *result,
902 GSocketConnection **conn = user_data;
903 GError *error = NULL;
905 *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
907 g_assert_no_error (error);
911 async_got_error (GObject *source,
912 GAsyncResult *result,
915 GError **error = user_data;
917 g_assert (error != NULL && *error == NULL);
918 g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
920 g_assert (*error != NULL);
924 async_resolver_got_error (GObject *source,
925 GAsyncResult *result,
928 GError **error = user_data;
930 g_assert (error != NULL && *error == NULL);
931 g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (source),
933 g_assert (*error != NULL);
937 assert_direct (GSocketConnection *conn)
939 GSocketAddress *addr;
940 GError *error = NULL;
942 g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
943 g_assert_cmpstr (last_proxies[0], ==, "direct://");
944 g_assert_no_error (proxy_a.last_error);
945 g_assert_no_error (proxy_b.last_error);
947 addr = g_socket_connection_get_remote_address (conn, &error);
948 g_assert_no_error (error);
949 g_assert (addr != NULL && !G_IS_PROXY_ADDRESS (addr));
950 g_object_unref (addr);
952 addr = g_socket_connection_get_local_address (conn, &error);
953 g_assert_no_error (error);
954 g_object_unref (addr);
956 g_assert (g_socket_connection_is_connected (conn));
960 test_direct_sync (gpointer fixture,
961 gconstpointer user_data)
963 GSocketConnection *conn;
965 GError *error = NULL;
967 /* The simple:// URI should not require any proxy. */
969 uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
970 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
972 g_assert_no_error (error);
974 assert_direct (conn);
976 g_object_unref (conn);
980 test_direct_async (gpointer fixture,
981 gconstpointer user_data)
983 GSocketConnection *conn;
986 /* The simple:// URI should not require any proxy. */
987 uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
989 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
990 async_got_conn, &conn);
993 g_main_context_iteration (NULL, TRUE);
995 assert_direct (conn);
997 g_object_unref (conn);
1001 assert_single (GSocketConnection *conn)
1003 GSocketAddress *addr;
1004 const gchar *proxy_uri;
1006 GError *error = NULL;
1008 g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
1009 g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1010 g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
1011 g_assert_no_error (proxy_a.last_error);
1012 g_assert_no_error (proxy_b.last_error);
1014 addr = g_socket_connection_get_remote_address (conn, &error);
1015 g_assert_no_error (error);
1016 g_assert (G_IS_PROXY_ADDRESS (addr));
1017 proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
1018 g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
1019 proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1020 g_assert_cmpint (proxy_port, ==, proxy_a.port);
1022 g_object_unref (addr);
1026 test_single_sync (gpointer fixture,
1027 gconstpointer user_data)
1029 GSocketConnection *conn;
1030 GError *error = NULL;
1033 /* The alpha:// URI should be proxied via Proxy A */
1034 uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
1035 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1037 g_assert_no_error (error);
1039 assert_single (conn);
1041 do_echo_test (conn);
1042 g_object_unref (conn);
1046 test_single_async (gpointer fixture,
1047 gconstpointer user_data)
1049 GSocketConnection *conn;
1052 /* The alpha:// URI should be proxied via Proxy A */
1053 uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
1055 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1056 async_got_conn, &conn);
1058 while (conn == NULL)
1059 g_main_context_iteration (NULL, TRUE);
1061 assert_single (conn);
1062 do_echo_test (conn);
1063 g_object_unref (conn);
1067 assert_multiple (GSocketConnection *conn)
1069 GSocketAddress *addr;
1070 const gchar *proxy_uri;
1072 GError *error = NULL;
1074 g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
1075 g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1076 g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
1077 g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1078 g_assert_no_error (proxy_b.last_error);
1080 addr = g_socket_connection_get_remote_address (conn, &error);
1081 g_assert_no_error (error);
1082 g_assert (G_IS_PROXY_ADDRESS (addr));
1083 proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
1084 g_assert_cmpstr (proxy_uri, ==, proxy_b.uri);
1085 proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1086 g_assert_cmpint (proxy_port, ==, proxy_b.port);
1088 g_object_unref (addr);
1092 test_multiple_sync (gpointer fixture,
1093 gconstpointer user_data)
1095 GSocketConnection *conn;
1096 GError *error = NULL;
1099 /* The beta:// URI should be proxied via Proxy B, after failing
1102 uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1103 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1105 g_assert_no_error (error);
1107 assert_multiple (conn);
1108 do_echo_test (conn);
1109 g_object_unref (conn);
1113 test_multiple_async (gpointer fixture,
1114 gconstpointer user_data)
1116 GSocketConnection *conn;
1119 /* The beta:// URI should be proxied via Proxy B, after failing
1122 uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1124 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1125 async_got_conn, &conn);
1127 while (conn == NULL)
1128 g_main_context_iteration (NULL, TRUE);
1130 assert_multiple (conn);
1131 do_echo_test (conn);
1132 g_object_unref (conn);
1136 test_invalid_uris_sync (gpointer fixture,
1137 gconstpointer user_data)
1139 GSocketConnection *conn;
1141 GError *error = NULL;
1143 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2597");
1145 /* The empty:// URI causes the proxy resolver to return an empty string. */
1146 uri = g_strdup_printf ("empty://127.0.0.1:%u", server.server_port);
1147 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1149 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
1150 g_assert_null (conn);
1151 g_clear_error (&error);
1152 g_clear_pointer (&last_proxies, g_strfreev);
1154 /* The invalid:// URI causes the proxy resolver to return a cat emoji. */
1155 uri = g_strdup_printf ("invalid://127.0.0.1:%u", server.server_port);
1156 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1158 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
1159 g_assert_null (conn);
1160 g_clear_error (&error);
1161 g_clear_pointer (&last_proxies, g_strfreev);
1163 /* If the proxy resolver returns an invalid URI before a valid URI,
1164 * we should succeed.
1166 uri = g_strdup_printf ("invalid-then-simple://127.0.0.1:%u", server.server_port);
1167 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1169 g_assert_no_error (error);
1170 do_echo_test (conn);
1171 g_object_unref (conn);
1172 g_clear_pointer (&last_proxies, g_strfreev);
1174 /* If the proxy resolver returns a valid URI before an invalid URI,
1175 * we should succeed.
1177 uri = g_strdup_printf ("simple-then-invalid://127.0.0.1:%u", server.server_port);
1178 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1180 g_assert_no_error (error);
1181 do_echo_test (conn);
1182 g_object_unref (conn);
1183 g_clear_pointer (&last_proxies, g_strfreev);
1185 /* Trying to use something that is not a URI at all should fail. */
1186 conn = g_socket_client_connect_to_uri (client, "asdf", 0, NULL, &error);
1187 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1188 g_clear_error (&error);
1189 g_clear_pointer (&last_proxies, g_strfreev);
1191 /* Should still fail if using GProxyResolver directly. */
1192 g_proxy_resolver_lookup (g_proxy_resolver_get_default (), "asdf", NULL, &error);
1193 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1194 g_clear_error (&error);
1198 test_invalid_uris_async (gpointer fixture,
1199 gconstpointer user_data)
1201 GSocketConnection *conn = NULL;
1202 GError *error = NULL;
1205 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2597");
1207 /* The empty:// URI causes the proxy resolver to return an empty string. */
1208 uri = g_strdup_printf ("empty://127.0.0.1:%u", server.server_port);
1209 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1210 async_got_error, &error);
1212 while (error == NULL)
1213 g_main_context_iteration (NULL, TRUE);
1214 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
1215 g_clear_error (&error);
1216 g_clear_pointer (&last_proxies, g_strfreev);
1218 /* The invalid:// URI causes the proxy resolver to return a cat emoji. */
1219 uri = g_strdup_printf ("invalid://127.0.0.1:%u", server.server_port);
1220 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1221 async_got_error, &error);
1223 while (error == NULL)
1224 g_main_context_iteration (NULL, TRUE);
1225 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
1226 g_clear_error (&error);
1227 g_clear_pointer (&last_proxies, g_strfreev);
1229 /* If the proxy resolver returns an invalid URI before a valid URI,
1230 * we should succeed.
1232 uri = g_strdup_printf ("invalid-then-simple://127.0.0.1:%u", server.server_port);
1233 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1234 async_got_conn, &conn);
1236 while (conn == NULL)
1237 g_main_context_iteration (NULL, TRUE);
1238 do_echo_test (conn);
1239 g_clear_object (&conn);
1240 g_clear_pointer (&last_proxies, g_strfreev);
1242 /* If the proxy resolver returns a valid URI before an invalid URI,
1243 * we should succeed.
1245 uri = g_strdup_printf ("simple-then-invalid://127.0.0.1:%u", server.server_port);
1246 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1247 async_got_conn, &conn);
1249 while (conn == NULL)
1250 g_main_context_iteration (NULL, TRUE);
1251 do_echo_test (conn);
1252 g_clear_object (&conn);
1253 g_clear_pointer (&last_proxies, g_strfreev);
1255 /* Trying to use something that is not a URI at all should fail. */
1256 g_socket_client_connect_to_uri_async (client, "asdf", 0, NULL,
1257 async_got_error, &error);
1258 while (error == NULL)
1259 g_main_context_iteration (NULL, TRUE);
1260 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1261 g_clear_error (&error);
1262 g_clear_pointer (&last_proxies, g_strfreev);
1264 /* Should still fail if using GProxyResolver directly. */
1265 g_proxy_resolver_lookup_async (g_proxy_resolver_get_default (), "asdf", NULL,
1266 async_resolver_got_error, &error);
1267 while (error == NULL)
1268 g_main_context_iteration (NULL, TRUE);
1269 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1270 g_clear_error (&error);
1274 test_dns (gpointer fixture,
1275 gconstpointer user_data)
1277 GSocketConnection *conn;
1278 GError *error = NULL;
1281 /* The simple:// and alpha:// URIs should fail with a DNS error,
1282 * but the beta:// URI should succeed, because we pass it to
1283 * Proxy B without trying to resolve it first
1287 uri = g_strdup_printf ("simple://no-such-host.xx:%u", server.server_port);
1288 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1289 g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1290 g_clear_error (&error);
1292 g_assert_no_error (proxy_a.last_error);
1293 g_assert_no_error (proxy_b.last_error);
1294 teardown_test (NULL, NULL);
1296 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1297 async_got_error, &error);
1298 while (error == NULL)
1299 g_main_context_iteration (NULL, TRUE);
1300 g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1301 g_clear_error (&error);
1304 g_assert_no_error (proxy_a.last_error);
1305 g_assert_no_error (proxy_b.last_error);
1306 teardown_test (NULL, NULL);
1309 uri = g_strdup_printf ("alpha://no-such-host.xx:%u", server.server_port);
1310 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1311 /* Since Proxy A fails, @client will try Proxy B too, which won't
1312 * load an alpha:// URI.
1314 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1315 g_clear_error (&error);
1317 g_assert_no_error (proxy_a.last_error);
1318 g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1319 teardown_test (NULL, NULL);
1321 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1322 async_got_error, &error);
1323 while (error == NULL)
1324 g_main_context_iteration (NULL, TRUE);
1325 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1326 g_clear_error (&error);
1329 g_assert_no_error (proxy_a.last_error);
1330 g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1331 teardown_test (NULL, NULL);
1334 uri = g_strdup_printf ("beta://no-such-host.xx:%u", server.server_port);
1335 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1336 g_assert_no_error (error);
1338 g_assert_no_error (proxy_a.last_error);
1339 g_assert_no_error (proxy_b.last_error);
1341 do_echo_test (conn);
1342 g_clear_object (&conn);
1343 teardown_test (NULL, NULL);
1345 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1346 async_got_conn, &conn);
1347 while (conn == NULL)
1348 g_main_context_iteration (NULL, TRUE);
1351 g_assert_no_error (proxy_a.last_error);
1352 g_assert_no_error (proxy_b.last_error);
1354 do_echo_test (conn);
1355 g_clear_object (&conn);
1356 teardown_test (NULL, NULL);
1360 assert_override (GSocketConnection *conn)
1362 g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
1363 g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1366 g_assert_no_error (proxy_a.last_error);
1368 g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1372 test_override (gpointer fixture,
1373 gconstpointer user_data)
1375 GProxyResolver *alt_resolver;
1376 GSocketConnection *conn;
1377 GError *error = NULL;
1380 g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
1381 alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL);
1382 g_socket_client_set_proxy_resolver (client, alt_resolver);
1383 g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
1385 /* Alt proxy resolver always returns Proxy A, so alpha:// should
1386 * succeed, and simple:// and beta:// should fail.
1390 uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
1391 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1392 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1393 g_clear_error (&error);
1394 assert_override (conn);
1395 teardown_test (NULL, NULL);
1397 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1398 async_got_error, &error);
1399 while (error == NULL)
1400 g_main_context_iteration (NULL, TRUE);
1401 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1402 g_clear_error (&error);
1403 assert_override (conn);
1405 teardown_test (NULL, NULL);
1408 uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
1409 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1410 g_assert_no_error (error);
1411 assert_override (conn);
1412 do_echo_test (conn);
1413 g_clear_object (&conn);
1414 teardown_test (NULL, NULL);
1417 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1418 async_got_conn, &conn);
1419 while (conn == NULL)
1420 g_main_context_iteration (NULL, TRUE);
1421 assert_override (conn);
1422 do_echo_test (conn);
1423 g_clear_object (&conn);
1425 teardown_test (NULL, NULL);
1428 uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1429 conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1430 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1431 g_clear_error (&error);
1432 assert_override (conn);
1433 teardown_test (NULL, NULL);
1435 g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1436 async_got_error, &error);
1437 while (error == NULL)
1438 g_main_context_iteration (NULL, TRUE);
1439 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1440 g_clear_error (&error);
1441 assert_override (conn);
1443 teardown_test (NULL, NULL);
1445 g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
1446 g_socket_client_set_proxy_resolver (client, NULL);
1447 g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
1448 g_object_unref (alt_resolver);
1452 assert_destination_port (GSocketAddressEnumerator *etor,
1455 GSocketAddress *addr;
1456 GProxyAddress *paddr;
1457 GError *error = NULL;
1459 while ((addr = g_socket_address_enumerator_next (etor, NULL, &error)))
1461 g_assert_no_error (error);
1463 g_assert (G_IS_PROXY_ADDRESS (addr));
1464 paddr = G_PROXY_ADDRESS (addr);
1465 g_assert_cmpint (g_proxy_address_get_destination_port (paddr), ==, port);
1466 g_object_unref (addr);
1468 g_assert_no_error (error);
1472 test_proxy_enumerator_ports (void)
1474 GSocketAddressEnumerator *etor;
1476 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1477 "uri", "http://example.com/",
1479 assert_destination_port (etor, 0);
1480 g_object_unref (etor);
1482 /* Have to call this to clear last_proxies so the next call to
1483 * g_test_proxy_resolver_lookup() won't assert.
1485 teardown_test (NULL, NULL);
1487 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1488 "uri", "http://example.com:8080/",
1490 assert_destination_port (etor, 8080);
1491 g_object_unref (etor);
1493 teardown_test (NULL, NULL);
1495 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1496 "uri", "http://example.com/",
1499 assert_destination_port (etor, 80);
1500 g_object_unref (etor);
1502 teardown_test (NULL, NULL);
1504 etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1505 "uri", "http://example.com:8080/",
1508 assert_destination_port (etor, 8080);
1509 g_object_unref (etor);
1511 teardown_test (NULL, NULL);
1518 GResolver *fake_resolver;
1519 GCancellable *cancellable;
1522 g_test_init (&argc, &argv, NULL);
1524 /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
1525 * is to force _g_io_modules_ensure_extension_points_registered() to
1526 * get called, so we can then register a proxy resolver extension
1529 g_proxy_get_default_for_protocol ("foo");
1530 g_test_proxy_resolver_get_type ();
1531 g_proxy_a_get_type ();
1532 g_proxy_b_get_type ();
1533 g_setenv ("GIO_USE_PROXY_RESOLVER", "test", TRUE);
1535 fake_resolver = g_object_new (g_fake_resolver_get_type (), NULL);
1536 g_resolver_set_default (fake_resolver);
1538 cancellable = g_cancellable_new ();
1539 create_server (&server, cancellable);
1540 create_proxy (&proxy_a, 'a', "alpha", cancellable);
1541 create_proxy (&proxy_b, 'b', "beta", cancellable);
1543 client = g_socket_client_new ();
1544 g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE);
1546 g_test_add_vtable ("/proxy/direct_sync", 0, NULL, setup_test, test_direct_sync, teardown_test);
1547 g_test_add_vtable ("/proxy/direct_async", 0, NULL, setup_test, test_direct_async, teardown_test);
1548 g_test_add_vtable ("/proxy/single_sync", 0, NULL, setup_test, test_single_sync, teardown_test);
1549 g_test_add_vtable ("/proxy/single_async", 0, NULL, setup_test, test_single_async, teardown_test);
1550 g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
1551 g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
1552 g_test_add_vtable ("/proxy/invalid-uris-sync", 0, NULL, setup_test, test_invalid_uris_sync, teardown_test);
1553 g_test_add_vtable ("/proxy/invalid-uris-async", 0, NULL, setup_test, test_invalid_uris_async, teardown_test);
1554 g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
1555 g_test_add_vtable ("/proxy/override", 0, NULL, setup_test, test_override, teardown_test);
1556 g_test_add_func ("/proxy/enumerator-ports", test_proxy_enumerator_ports);
1558 result = g_test_run();
1560 g_object_unref (client);
1562 g_cancellable_cancel (cancellable);
1563 g_thread_join (proxy_a.thread);
1564 g_thread_join (proxy_b.thread);
1565 g_thread_join (server.server_thread);
1567 g_object_unref (cancellable);