Improve GApplication test coverage
[platform/upstream/glib.git] / gio / tests / proxy-test.c
index ff65e2a..af91f38 100644 (file)
@@ -26,7 +26,7 @@
 /* Overview:
  *
  * We have an echo server, two proxy servers, two GProxy
- * implementations, and a GProxyResolver implementation.
+ * implementations, and two GProxyResolver implementations.
  *
  * The echo server runs at @server.server_addr (on
  * @server.server_port).
  * hostname resolution (but it just ignores the hostname and always
  * connects to @server_addr anyway).
  *
- * The GProxyResolver (GTestProxyResolver) looks at its URI and
- * returns [ "direct://" ] for "simple://" URIs, and [ proxy_a.uri,
- * proxy_b.uri ] for other URIs.
+ * The default GProxyResolver (GTestProxyResolver) looks at its URI
+ * and returns [ "direct://" ] for "simple://" URIs, and [
+ * proxy_a.uri, proxy_b.uri ] for other URIs. The other GProxyResolver
+ * (GTestAltProxyResolver) always returns [ proxy_a.uri ].
  */
 
 typedef struct {
@@ -94,6 +95,7 @@ typedef struct {
 
 static void g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface);
 
+static GType _g_test_proxy_resolver_get_type (void);
 #define g_test_proxy_resolver_get_type _g_test_proxy_resolver_get_type
 G_DEFINE_TYPE_WITH_CODE (GTestProxyResolver, g_test_proxy_resolver, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
@@ -159,22 +161,18 @@ g_test_proxy_resolver_lookup_async (GProxyResolver      *resolver,
                                    gpointer             user_data)
 {
   GError *error = NULL;
-  GSimpleAsyncResult *simple;
+  GTask *task;
   gchar **proxies;
 
-  proxies = g_test_proxy_resolver_lookup (resolver, uri, cancellable, &error);
-
-  simple = g_simple_async_result_new (G_OBJECT (resolver),
-                                     callback, user_data,
-                                     g_test_proxy_resolver_lookup_async);
+  proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
 
+  task = g_task_new (resolver, NULL, callback, user_data);
   if (proxies == NULL)
-    g_simple_async_result_take_error (simple, error);
+    g_task_return_error (task, error);
   else
-    g_simple_async_result_set_op_res_gpointer (simple, proxies, (GDestroyNotify) g_strfreev);
+    g_task_return_pointer (task, proxies, (GDestroyNotify) g_strfreev);
 
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
+  g_object_unref (task);
 }
 
 static gchar **
@@ -182,19 +180,7 @@ g_test_proxy_resolver_lookup_finish (GProxyResolver     *resolver,
                                     GAsyncResult       *result,
                                     GError            **error)
 {
-  if (G_IS_SIMPLE_ASYNC_RESULT (result))
-    {
-      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
-      gchar **proxies;
-
-      if (g_simple_async_result_propagate_error (simple, error))
-        return NULL;
-
-      proxies = g_simple_async_result_get_op_res_gpointer (simple);
-      return g_strdupv (proxies);
-    }
-
-  return NULL;
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -211,6 +197,56 @@ g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
   iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
 }
 
+/****************************/
+/* Alternate GProxyResolver */
+/****************************/
+
+typedef GTestProxyResolver GTestAltProxyResolver;
+typedef GTestProxyResolverClass GTestAltProxyResolverClass;
+
+static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface);
+
+static GType _g_test_alt_proxy_resolver_get_type (void);
+#define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type
+G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (),
+                        G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
+                                               g_test_alt_proxy_resolver_iface_init);
+                         )
+
+static void
+g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver)
+{
+}
+
+static gchar **
+g_test_alt_proxy_resolver_lookup (GProxyResolver  *resolver,
+                                  const gchar     *uri,
+                                  GCancellable    *cancellable,
+                                  GError         **error)
+{
+  gchar **proxies;
+
+  proxies = g_new (gchar *, 2);
+
+  proxies[0] = g_strdup (proxy_a.uri);
+  proxies[1] = NULL;
+
+  last_proxies = g_strdupv (proxies);
+
+  return proxies;
+}
+
+static void
+g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
+{
+}
+
+static void
+g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface)
+{
+  iface->lookup = g_test_alt_proxy_resolver_lookup;
+}
+
 
 /****************************************/
 /* Test proxy implementation base class */
@@ -226,6 +262,7 @@ typedef struct {
   GObjectClass parent_class;
 } GProxyBaseClass;
 
+static GType _g_proxy_base_get_type (void);
 #define g_proxy_base_get_type _g_proxy_base_get_type
 G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT)
 
@@ -292,24 +329,18 @@ g_proxy_base_connect_async (GProxy               *proxy,
                            gpointer              user_data)
 {
   GError *error = NULL;
-  GSimpleAsyncResult *simple;
+  GTask *task;
   GIOStream *proxy_io_stream;
 
-  simple = g_simple_async_result_new (G_OBJECT (proxy),
-                                     callback, user_data,
-                                     g_proxy_base_connect_async);
+  task = g_task_new (proxy, NULL, callback, user_data);
 
   proxy_io_stream = g_proxy_connect (proxy, io_stream, proxy_address,
                                     cancellable, &error);
   if (proxy_io_stream)
-    {
-      g_simple_async_result_set_op_res_gpointer (simple, proxy_io_stream,
-                                                g_object_unref);
-    }
+    g_task_return_pointer (task, proxy_io_stream, g_object_unref);
   else
-    g_simple_async_result_take_error (simple, error);
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
+    g_task_return_error (task, error);
+  g_object_unref (task);
 }
 
 static GIOStream *
@@ -317,12 +348,7 @@ g_proxy_base_connect_finish (GProxy        *proxy,
                             GAsyncResult  *result,
                             GError       **error)
 {
-  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
-
-  if (g_simple_async_result_propagate_error (simple, error))
-    return NULL;
-
-  return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -340,6 +366,7 @@ typedef GProxyBaseClass GProxyAClass;
 
 static void g_proxy_a_iface_init (GProxyInterface *proxy_iface);
 
+static GType _g_proxy_a_get_type (void);
 #define g_proxy_a_get_type _g_proxy_a_get_type
 G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (),
                         G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
@@ -384,6 +411,7 @@ typedef GProxyBaseClass GProxyBClass;
 
 static void g_proxy_b_iface_init (GProxyInterface *proxy_iface);
 
+static GType _g_proxy_b_get_type (void);
 #define g_proxy_b_get_type _g_proxy_b_get_type
 G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (),
                         G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
@@ -475,7 +503,7 @@ proxy_thread (gpointer user_data)
   gssize nread, nwrote;
   gchar command[2] = { 0, 0 };
   GMainContext *context;
-  GSource *source;
+  GSource *read_source, *write_source;
 
   context = g_main_context_new ();
   proxy->loop = g_main_loop_new (context, FALSE);
@@ -486,6 +514,7 @@ proxy_thread (gpointer user_data)
       if (!proxy->client_sock)
        {
          g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+          g_error_free (error);
          break;
        }
       else
@@ -516,15 +545,13 @@ proxy_thread (gpointer user_data)
       g_socket_connect (proxy->server_sock, server.server_addr, NULL, &error);
       g_assert_no_error (error);
 
-      source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
-      g_source_set_callback (source, (GSourceFunc)proxy_bytes, proxy, NULL);
-      g_source_attach (source, context);
-      g_source_unref (source);
+      read_source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
+      g_source_set_callback (read_source, (GSourceFunc)proxy_bytes, proxy, NULL);
+      g_source_attach (read_source, context);
 
-      source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
-      g_source_set_callback (source, (GSourceFunc)proxy_bytes, proxy, NULL);
-      g_source_attach (source, context);
-      g_source_unref (source);
+      write_source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
+      g_source_set_callback (write_source, (GSourceFunc)proxy_bytes, proxy, NULL);
+      g_source_attach (write_source, context);
 
       g_main_loop_run (proxy->loop);
 
@@ -535,6 +562,11 @@ proxy_thread (gpointer user_data)
       g_socket_close (proxy->server_sock, &error);
       g_assert_no_error (error);
       g_clear_object (&proxy->server_sock);
+
+      g_source_destroy (read_source);
+      g_source_unref (read_source);
+      g_source_destroy (write_source);
+      g_source_unref (write_source);
     }
 
   g_main_loop_unref (proxy->loop);
@@ -543,6 +575,10 @@ proxy_thread (gpointer user_data)
   g_object_unref (proxy->server);
   g_object_unref (proxy->cancellable);
 
+  g_free (proxy->proxy_command);
+  g_free (proxy->supported_protocol);
+  g_free (proxy->uri);
+
   return NULL;
 }
 
@@ -608,6 +644,7 @@ echo_server_thread (gpointer user_data)
       if (!sock)
        {
          g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+          g_error_free (error);
          break;
        }
       else
@@ -633,6 +670,7 @@ echo_server_thread (gpointer user_data)
     }
 
   g_object_unref (data->server);
+  g_object_unref (data->server_addr);
   g_object_unref (data->cancellable);
 
   return NULL;
@@ -682,6 +720,7 @@ create_server (ServerData *data, GCancellable *cancellable)
 typedef GResolver GFakeResolver;
 typedef GResolverClass GFakeResolverClass;
 
+static GType g_fake_resolver_get_type (void);
 G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
 
 static void
@@ -695,14 +734,17 @@ g_fake_resolver_lookup_by_name (GResolver     *resolver,
                                GCancellable  *cancellable,
                                GError       **error)
 {
-  /* This is only ever called with lookups that are expected to
-   * fail.
-   */
-  g_set_error (error,
-              G_RESOLVER_ERROR,
-              G_RESOLVER_ERROR_NOT_FOUND,
-              "Not found");
-  return NULL;
+  if (!strcmp (hostname, "example.com"))
+    return g_list_prepend (NULL, g_inet_address_new_from_string ("127.0.0.1"));
+  else
+    {
+      /* Anything else is expected to fail. */
+      g_set_error (error,
+                   G_RESOLVER_ERROR,
+                   G_RESOLVER_ERROR_NOT_FOUND,
+                   "Not found");
+      return NULL;
+    }
 }
 
 static void
@@ -712,11 +754,32 @@ g_fake_resolver_lookup_by_name_async (GResolver           *resolver,
                                      GAsyncReadyCallback  callback,
                                      gpointer             user_data)
 {
-  g_simple_async_report_error_in_idle (G_OBJECT (resolver),
-                                      callback, user_data,
-                                      G_RESOLVER_ERROR,
-                                      G_RESOLVER_ERROR_NOT_FOUND,
-                                      "Not found");
+  GTask *task;
+
+  task = g_task_new (resolver, cancellable, callback, user_data);
+
+  if (!strcmp (hostname, "example.com"))
+    {
+      GList *result;
+
+      result = g_list_prepend (NULL, g_inet_address_new_from_string ("127.0.0.1"));
+      g_task_return_pointer (task, result, (GDestroyNotify) g_resolver_free_addresses);
+    }
+  else
+    {
+      g_task_return_new_error (task,
+                               G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
+                               "Not found");
+    }
+  g_object_unref (task);
+}
+
+static GList *
+g_fake_resolver_lookup_by_name_finish (GResolver            *resolver,
+                                      GAsyncResult         *result,
+                                      GError              **error)
+{
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -726,6 +789,7 @@ g_fake_resolver_class_init (GFakeResolverClass *fake_class)
 
   resolver_class->lookup_by_name        = g_fake_resolver_lookup_by_name;
   resolver_class->lookup_by_name_async  = g_fake_resolver_lookup_by_name_async;
+  resolver_class->lookup_by_name_finish = g_fake_resolver_lookup_by_name_finish;
 }
 
 
@@ -825,10 +889,12 @@ assert_direct (GSocketConnection *conn)
 
   addr = g_socket_connection_get_remote_address (conn, &error);
   g_assert_no_error (error);
-  g_assert (!G_IS_PROXY_ADDRESS (addr));
+  g_assert (addr != NULL && !G_IS_PROXY_ADDRESS (addr));
+  g_object_unref (addr);
 
   addr = g_socket_connection_get_local_address (conn, &error);
   g_assert_no_error (error);
+  g_object_unref (addr);
 
   g_assert (g_socket_connection_is_connected (conn));
 }
@@ -895,6 +961,8 @@ assert_single (GSocketConnection *conn)
   g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
   g_assert_cmpint (proxy_port, ==, proxy_a.port);
+
+  g_object_unref (addr);
 }
 
 static void
@@ -959,6 +1027,8 @@ assert_multiple (GSocketConnection *conn)
   g_assert_cmpstr (proxy_uri, ==, proxy_b.uri);
   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
   g_assert_cmpint (proxy_port, ==, proxy_b.port);
+
+  g_object_unref (addr);
 }
 
 static void
@@ -1091,6 +1161,161 @@ test_dns (gpointer fixture,
   teardown_test (NULL, NULL);
 }
 
+static void
+assert_override (GSocketConnection *conn)
+{
+  g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
+  g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
+
+  if (conn)
+    g_assert_no_error (proxy_a.last_error);
+  else
+    g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+}
+
+static void
+test_override (gpointer fixture,
+               gconstpointer user_data)
+{
+  GProxyResolver *alt_resolver;
+  GSocketConnection *conn;
+  GError *error = NULL;
+  gchar *uri;
+
+  g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
+  alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL);
+  g_socket_client_set_proxy_resolver (client, alt_resolver);
+  g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
+
+  /* Alt proxy resolver always returns Proxy A, so alpha:// should
+   * succeed, and simple:// and beta:// should fail.
+   */
+
+  /* simple */
+  uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
+  conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  teardown_test (NULL, NULL);
+
+  g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
+                                       async_got_error, &error);
+  while (error == NULL)
+    g_main_context_iteration (NULL, TRUE);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  g_free (uri);
+  teardown_test (NULL, NULL);
+
+  /* alpha */
+  uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
+  conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
+  g_assert_no_error (error);
+  assert_override (conn);
+  do_echo_test (conn);
+  g_clear_object (&conn);
+  teardown_test (NULL, NULL);
+
+  conn = NULL;
+  g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
+                                       async_got_conn, &conn);
+  while (conn == NULL)
+    g_main_context_iteration (NULL, TRUE);
+  assert_override (conn);
+  do_echo_test (conn);
+  g_clear_object (&conn);
+  g_free (uri);
+  teardown_test (NULL, NULL);
+
+  /* beta */
+  uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
+  conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  teardown_test (NULL, NULL);
+
+  g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
+                                       async_got_error, &error);
+  while (error == NULL)
+    g_main_context_iteration (NULL, TRUE);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  g_free (uri);
+  teardown_test (NULL, NULL);
+
+  g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
+  g_socket_client_set_proxy_resolver (client, NULL);
+  g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
+  g_object_unref (alt_resolver);
+}
+
+static void
+assert_destination_port (GSocketAddressEnumerator *etor,
+                         guint16                   port)
+{
+  GSocketAddress *addr;
+  GProxyAddress *paddr;
+  GError *error = NULL;
+
+  while ((addr = g_socket_address_enumerator_next (etor, NULL, &error)))
+    {
+      g_assert_no_error (error);
+
+      g_assert (G_IS_PROXY_ADDRESS (addr));
+      paddr = G_PROXY_ADDRESS (addr);
+      g_assert_cmpint (g_proxy_address_get_destination_port (paddr), ==, port);
+      g_object_unref (addr);
+    }
+  g_assert_no_error (error);
+}
+
+static void
+test_proxy_enumerator_ports (void)
+{
+  GSocketAddressEnumerator *etor;
+
+  etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
+                       "uri", "http://example.com/",
+                       NULL);
+  assert_destination_port (etor, 0);
+  g_object_unref (etor);
+
+  /* Have to call this to clear last_proxies so the next call to
+   * g_test_proxy_resolver_lookup() won't assert.
+   */
+  teardown_test (NULL, NULL);
+
+  etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
+                       "uri", "http://example.com:8080/",
+                       NULL);
+  assert_destination_port (etor, 8080);
+  g_object_unref (etor);
+
+  teardown_test (NULL, NULL);
+
+  etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
+                       "uri", "http://example.com/",
+                       "default-port", 80,
+                       NULL);
+  assert_destination_port (etor, 80);
+  g_object_unref (etor);
+
+  teardown_test (NULL, NULL);
+
+  etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
+                       "uri", "http://example.com:8080/",
+                       "default-port", 80,
+                       NULL);
+  assert_destination_port (etor, 8080);
+  g_object_unref (etor);
+
+  teardown_test (NULL, NULL);
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -1099,7 +1324,6 @@ main (int   argc,
   GCancellable *cancellable;
   gint result;
 
-  g_type_init ();
   g_test_init (&argc, &argv, NULL);
 
   /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
@@ -1131,6 +1355,8 @@ main (int   argc,
   g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
   g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
   g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
+  g_test_add_vtable ("/proxy/override", 0, NULL, setup_test, test_override, teardown_test);
+  g_test_add_func ("/proxy/enumerator-ports", test_proxy_enumerator_ports);
 
   result = g_test_run();
 
@@ -1141,6 +1367,8 @@ main (int   argc,
   g_thread_join (proxy_b.thread);
   g_thread_join (server.server_thread);
 
+  g_object_unref (cancellable);
+
   return result;
 }