test-utils: add cancellation support to soup_test_request_send
authorSergio Villar Senin <svillar@igalia.com>
Wed, 30 Jan 2013 16:56:38 +0000 (17:56 +0100)
committerSergio Villar Senin <svillar@igalia.com>
Tue, 12 Feb 2013 09:15:51 +0000 (10:15 +0100)
The function gets a new parametter used to enable request cancellation for
both sync and async sessions. The cancellation could be performed by either
using the GCancellable or by directly cancelling the SoupMessage.

Also the GMainContext used to simulate sync operations with async ones will
now try to execute all its pending events before quiting the main loop.

https://bugzilla.gnome.org/show_bug.cgi?id=692310

tests/cache-test.c
tests/coding-test.c
tests/connection-test.c
tests/misc-test.c
tests/proxy-test.c
tests/redirect-test.c
tests/sniffing-test.c
tests/test-utils.c
tests/test-utils.h
tests/timeout-test.c

index ac19bfe..22ca6f8 100644 (file)
@@ -146,7 +146,7 @@ do_request (SoupSession *session,
        }
        g_object_unref (msg);
 
-       stream = soup_test_request_send (SOUP_REQUEST (req), NULL, &error);
+       stream = soup_test_request_send (SOUP_REQUEST (req), NULL, 0, &error);
        if (!stream) {
                debug_printf (1, "    could not send request: %s\n",
                              error->message);
index 5d4f0e3..30417b4 100644 (file)
@@ -337,7 +337,7 @@ do_single_coding_req_test (SoupRequestHTTP *reqh,
 
        data = g_byte_array_new ();
 
-       stream = soup_test_request_send (SOUP_REQUEST (reqh), NULL, &error);
+       stream = soup_test_request_send (SOUP_REQUEST (reqh), NULL, 0, &error);
        if (error) {
                debug_printf (1, "    Error sending request: %s\n",
                              error->message);
index 6b57f24..b721136 100644 (file)
@@ -316,7 +316,7 @@ do_timeout_req_test_for_session (SoupSession *session)
        req = soup_session_request_uri (session, timeout_uri, NULL);
        soup_uri_free (timeout_uri);
 
-       stream = soup_test_request_send (req, NULL, &error);
+       stream = soup_test_request_send (req, NULL, 0, &error);
        if (!stream) {
                debug_printf (1, "      Unexpected error on send: %s\n",
                              error->message);
@@ -343,7 +343,7 @@ do_timeout_req_test_for_session (SoupSession *session)
        debug_printf (1, "    Second request\n");
        req = soup_session_request_uri (session, base_uri, NULL);
 
-       stream = soup_test_request_send (req, NULL, &error);
+       stream = soup_test_request_send (req, NULL, 0, &error);
        if (!stream) {
                debug_printf (1, "      Unexpected error on send: %s\n",
                              error->message);
index b243ce4..d434e9b 100644 (file)
@@ -905,24 +905,9 @@ do_cancel_while_reading_test (void)
        soup_test_session_abort_unref (session);
 }
 
-static gboolean
-cancel_request_timeout (gpointer cancellable)
-{
-       g_cancellable_cancel (cancellable);
-       return FALSE;
-}
-
-static gpointer
-cancel_request_thread (gpointer cancellable)
-{
-       g_usleep (100000); /* .1s */
-       g_cancellable_cancel (cancellable);
-       g_object_unref (cancellable);
-       return NULL;
-}
-
 static void
-do_cancel_while_reading_req_test_for_session (SoupSession *session)
+do_cancel_while_reading_req_test_for_session (SoupSession *session,
+                                             guint flags)
 {
        SoupRequest *req;
        SoupURI *uri;
@@ -934,18 +919,7 @@ do_cancel_while_reading_req_test_for_session (SoupSession *session)
        soup_uri_free (uri);
 
        cancellable = g_cancellable_new ();
-
-       if (SOUP_IS_SESSION_ASYNC (soup_request_get_session (req))) {
-               g_timeout_add (100, cancel_request_timeout, cancellable);
-               soup_test_request_send (req, cancellable, &error);
-       } else {
-               GThread *thread;
-
-               thread = g_thread_new ("cancel_request_thread", cancel_request_thread, g_object_ref (cancellable));
-               soup_test_request_send (req, cancellable, &error);
-               g_thread_unref (thread);
-       }
-
+       soup_test_request_send (req, cancellable, flags, &error);
        if (!error) {
                debug_printf (1, "  Request succeeded?\n");
                errors++;
@@ -964,20 +938,38 @@ static void
 do_cancel_while_reading_req_test (void)
 {
        SoupSession *session;
+       guint flags;
+
+       debug_printf (1, "\nCancelling (immediately) message while reading response (request api)\n");
+       flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE;
+
+       debug_printf (1, "  Async session\n");
+       session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+                                        SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+                                        NULL);
+       do_cancel_while_reading_req_test_for_session (session, flags);
+       soup_test_session_abort_unref (session);
+
+       debug_printf (1, "  Sync session\n");
+       session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
+                                        NULL);
+       do_cancel_while_reading_req_test_for_session (session, flags);
+       soup_test_session_abort_unref (session);
 
-       debug_printf (1, "\nCancelling message while reading response (request api)\n");
+       debug_printf (1, "\nCancelling (after 100ms) message while reading response (request api)\n");
+       flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_SOON;
 
        debug_printf (1, "  Async session\n");
        session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
                                         SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
                                         NULL);
-       do_cancel_while_reading_req_test_for_session (session);
+       do_cancel_while_reading_req_test_for_session (session, flags);
        soup_test_session_abort_unref (session);
 
        debug_printf (1, "  Sync session\n");
        session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
                                         NULL);
-       do_cancel_while_reading_req_test_for_session (session);
+       do_cancel_while_reading_req_test_for_session (session, flags);
        soup_test_session_abort_unref (session);
 }
 
index 048acfa..1ac3855 100644 (file)
@@ -164,7 +164,7 @@ test_url_new_api (const char *url, int proxy, guint expected,
        request = soup_session_request (session, url, NULL);
        msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
 
-       stream = soup_test_request_send (request, NULL, &error);
+       stream = soup_test_request_send (request, NULL, 0, &error);
        if (!stream) {
                debug_printf (1, "  Unexpected error on Request: %s\n",
                              error->message);
index 3307ce6..9bc4621 100644 (file)
@@ -252,7 +252,7 @@ do_request_api_test (SoupSession *session, SoupURI *base_uri, int n)
        g_signal_connect (msg, "restarted",
                          G_CALLBACK (restarted), &treq);
 
-       stream = soup_test_request_send (SOUP_REQUEST (reqh), NULL, &error);
+       stream = soup_test_request_send (SOUP_REQUEST (reqh), NULL, 0, &error);
 
        if (SOUP_STATUS_IS_TRANSPORT_ERROR (final_status)) {
                if (stream) {
index f28ddaf..cbebaba 100644 (file)
@@ -383,7 +383,7 @@ test_sniffing (const char *path, const char *expected_type)
        g_object_unref (msg);
 
        req = soup_session_request_uri (session, uri, NULL);
-       stream = soup_test_request_send (req, NULL, &error);
+       stream = soup_test_request_send (req, NULL, 0, &error);
        if (stream) {
                soup_test_request_close_stream (req, stream, NULL, &error);
                g_object_unref (stream);
@@ -439,7 +439,7 @@ test_disabled (const char *path)
        msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (req));
        soup_message_disable_feature (msg, SOUP_TYPE_CONTENT_SNIFFER);
        g_object_unref (msg);
-       stream = soup_test_request_send (req, NULL, &error);
+       stream = soup_test_request_send (req, NULL, 0, &error);
        if (stream) {
                soup_test_request_close_stream (req, stream, NULL, &error);
                g_object_unref (stream);
index fc5b18d..cc9aa8e 100644 (file)
@@ -371,24 +371,98 @@ async_as_sync_callback (GObject      *object,
                        gpointer      user_data)
 {
        AsyncAsSyncData *data = user_data;
+       GMainContext *context;
 
        data->result = g_object_ref (result);
+       context = g_main_loop_get_context (data->loop);
+       while (g_main_context_pending (context))
+               g_main_context_iteration (context, FALSE);
        g_main_loop_quit (data->loop);
 }
 
+typedef struct {
+       SoupRequest  *req;
+       GCancellable *cancellable;
+       SoupTestRequestFlags flags;
+} CancelData;
+
+static CancelData *
+create_cancel_data (SoupRequest          *req,
+                   GCancellable         *cancellable,
+                   SoupTestRequestFlags  flags)
+{
+       CancelData *cancel_data;
+
+       if (!flags)
+               return NULL;
+
+       cancel_data = g_slice_new0 (CancelData);
+       cancel_data->flags = flags;
+       if (flags & SOUP_TEST_REQUEST_CANCEL_MESSAGE && SOUP_IS_REQUEST_HTTP (req))
+               cancel_data->req = g_object_ref (req);
+       else if (flags & SOUP_TEST_REQUEST_CANCEL_CANCELLABLE)
+               cancel_data->cancellable = g_object_ref (cancellable);
+       return cancel_data;
+}
+
+static void inline
+cancel_message_or_cancellable (CancelData *cancel_data)
+{
+       if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_MESSAGE) {
+               SoupRequest *req = cancel_data->req;
+               soup_session_cancel_message (soup_request_get_session (req),
+                                            soup_request_http_get_message (SOUP_REQUEST_HTTP (req)),
+                                            SOUP_STATUS_CANCELLED);
+               g_object_unref (req);
+       } else if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_CANCELLABLE) {
+               g_cancellable_cancel (cancel_data->cancellable);
+               g_object_unref (cancel_data->cancellable);
+       }
+       g_slice_free (CancelData, cancel_data);
+}
+
+static gboolean
+cancel_request_timeout (gpointer data)
+{
+       cancel_message_or_cancellable ((CancelData *) data);
+       return FALSE;
+}
+
+static gpointer
+cancel_request_thread (gpointer data)
+{
+       g_usleep (100000); /* .1s */
+       cancel_message_or_cancellable ((CancelData *) data);
+       return NULL;
+}
+
 GInputStream *
 soup_test_request_send (SoupRequest   *req,
                        GCancellable  *cancellable,
+                       guint          flags,
                        GError       **error)
 {
        AsyncAsSyncData data;
        GInputStream *stream;
+       CancelData *cancel_data = create_cancel_data (req, cancellable, flags);
 
-       if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req)))
-               return soup_request_send (req, cancellable, error);
+       if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) {
+               GThread *thread;
 
-       data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+               if (cancel_data)
+                       thread = g_thread_new ("cancel_request_thread", cancel_request_thread,
+                                              cancel_data);
+               stream = soup_request_send (req, cancellable, error);
+               if (cancel_data)
+                       g_thread_unref (thread);
+               return stream;
+       }
 
+       data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+       if (cancel_data) {
+               guint interval = flags & SOUP_TEST_REQUEST_CANCEL_SOON ? 100 : 0;
+               g_timeout_add_full (G_PRIORITY_HIGH, interval, cancel_request_timeout, cancel_data, NULL);
+       }
        soup_request_send_async (req, cancellable, async_as_sync_callback, &data);
        g_main_loop_run (data.loop);
 
index ca1003f..22a4a16 100644 (file)
@@ -23,6 +23,13 @@ void apache_init    (void);
 void apache_cleanup (void);
 #endif
 
+typedef enum {
+  SOUP_TEST_REQUEST_NONE = 0,
+  SOUP_TEST_REQUEST_CANCEL_MESSAGE = (1 << 0),
+  SOUP_TEST_REQUEST_CANCEL_CANCELLABLE = (1 << 1),
+  SOUP_TEST_REQUEST_CANCEL_SOON = (1 << 2)
+} SoupTestRequestFlags;
+
 SoupSession *soup_test_session_new         (GType type, ...);
 void         soup_test_session_abort_unref (SoupSession *session);
 
@@ -30,8 +37,9 @@ SoupServer  *soup_test_server_new        (gboolean in_own_thread);
 SoupServer  *soup_test_server_new_ssl    (gboolean in_own_thread);
 void         soup_test_server_quit_unref (SoupServer *server);
 
-GInputStream *soup_test_request_send         (SoupRequest   *req,
-                                             GCancellable  *cancellable,
+GInputStream *soup_test_request_send         (SoupRequest  *req,
+                                             GCancellable *cancellable,
+                                             guint         flags,
                                              GError       **error);
 gboolean      soup_test_request_close_stream (SoupRequest   *req,
                                              GInputStream  *stream,
index e523f2d..27bcbff 100644 (file)
@@ -127,7 +127,7 @@ do_request_to_session (SoupSession *session, const char *uri,
 
        g_signal_connect (msg, "finished",
                          G_CALLBACK (message_finished), &finished);
-       stream = soup_test_request_send (req, NULL, &error);
+       stream = soup_test_request_send (req, NULL, 0, &error);
 
        if (expect_timeout && !error) {
                debug_printf (1, "      FAILED: request did not time out\n");