1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Red Hat, Inc.
6 #include "test-utils.h"
17 request_failed (SoupMessage *msg, gpointer data)
21 if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code))
22 g_source_destroy (sd->timeout);
27 add_body_chunk (gpointer data)
31 soup_message_body_append (sd->msg->response_body,
32 SOUP_MEMORY_STATIC, "OK\r\n", 4);
33 soup_message_body_complete (sd->msg->response_body);
34 soup_server_unpause_message (sd->server, sd->msg);
35 g_object_unref (sd->msg);
41 server_callback (SoupServer *server, SoupMessage *msg,
42 const char *path, GHashTable *query,
43 SoupClientContext *context, gpointer data)
47 if (msg->method != SOUP_METHOD_GET) {
48 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
52 soup_message_set_status (msg, SOUP_STATUS_OK);
53 if (!strcmp (path, "/fast")) {
54 soup_message_set_response (msg, "text/plain",
55 SOUP_MEMORY_STATIC, "OK\r\n", 4);
59 soup_message_headers_set_encoding (msg->response_headers,
60 SOUP_ENCODING_CHUNKED);
62 soup_server_pause_message (server, msg);
64 sd = g_new (SlowData, 1);
67 sd->timeout = soup_add_timeout (
68 soup_server_get_async_context (server),
69 200, add_body_chunk, sd);
70 g_signal_connect (msg, "finished",
71 G_CALLBACK (request_failed), sd);
74 /* Test 1: An async session in another thread with its own
75 * async_context can complete a request while the main thread's main
79 static gboolean idle_start_test1_thread (gpointer loop);
80 static gpointer test1_thread (gpointer user_data);
82 static GCond test1_cond;
83 static GMutex test1_mutex;
84 static GMainLoop *test1_loop;
87 do_test1 (int n, gboolean use_thread_context)
89 debug_printf (1, "\nTest %d: blocking the main thread does not block other thread\n", n);
90 if (use_thread_context)
91 debug_printf (1, "(Using g_main_context_push_thread_default())\n");
93 debug_printf (1, "(Using SOUP_SESSION_ASYNC_CONTEXT)\n");
95 test1_loop = g_main_loop_new (NULL, FALSE);
96 g_idle_add (idle_start_test1_thread, GINT_TO_POINTER (use_thread_context));
97 g_main_loop_run (test1_loop);
98 g_main_loop_unref (test1_loop);
102 idle_start_test1_thread (gpointer use_thread_context)
107 g_mutex_lock (&test1_mutex);
108 thread = g_thread_new ("test1_thread", test1_thread, use_thread_context);
110 time = g_get_monotonic_time () + 5000000;
111 if (g_cond_wait_until (&test1_cond, &test1_mutex, time))
112 g_thread_join (thread);
114 debug_printf (1, " timeout!\n");
115 g_thread_unref (thread);
119 g_mutex_unlock (&test1_mutex);
120 g_main_loop_quit (test1_loop);
125 test1_finished (SoupSession *session, SoupMessage *msg, gpointer loop)
127 g_main_loop_quit (loop);
131 test1_thread (gpointer use_thread_context)
133 SoupSession *session;
134 GMainContext *async_context;
139 /* Wait for main thread to be waiting on test1_cond */
140 g_mutex_lock (&test1_mutex);
141 g_mutex_unlock (&test1_mutex);
143 async_context = g_main_context_new ();
144 if (use_thread_context) {
145 g_main_context_push_thread_default (async_context);
146 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
147 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
150 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
151 SOUP_SESSION_ASYNC_CONTEXT, async_context,
154 g_main_context_unref (async_context);
156 uri = g_build_filename (base_uri, "slow", NULL);
158 debug_printf (1, " send_message\n");
159 msg = soup_message_new ("GET", uri);
160 soup_session_send_message (session, msg);
161 if (msg->status_code != SOUP_STATUS_OK) {
162 debug_printf (1, " unexpected status: %d %s\n",
163 msg->status_code, msg->reason_phrase);
166 g_object_unref (msg);
168 debug_printf (1, " queue_message\n");
169 msg = soup_message_new ("GET", uri);
170 loop = g_main_loop_new (async_context, FALSE);
172 soup_session_queue_message (session, msg, test1_finished, loop);
173 g_main_loop_run (loop);
174 g_main_loop_unref (loop);
175 if (msg->status_code != SOUP_STATUS_OK) {
176 debug_printf (1, " unexpected status: %d %s\n",
177 msg->status_code, msg->reason_phrase);
180 g_object_unref (msg);
182 soup_test_session_abort_unref (session);
185 g_cond_signal (&test1_cond);
187 if (use_thread_context)
188 g_main_context_pop_thread_default (async_context);
192 /* Test 2: An async session in the main thread with its own
193 * async_context runs independently of the default main loop.
196 static gboolean idle_test2_fail (gpointer user_data);
199 do_test2 (int n, gboolean use_thread_context)
202 GMainContext *async_context;
203 SoupSession *session;
207 debug_printf (1, "\nTest %d: a session with its own context is independent of the main loop.\n", n);
208 if (use_thread_context)
209 debug_printf (1, "(Using g_main_context_push_thread_default())\n");
211 debug_printf (1, "(Using SOUP_SESSION_ASYNC_CONTEXT)\n");
213 idle = g_idle_add_full (G_PRIORITY_HIGH, idle_test2_fail, NULL, NULL);
215 async_context = g_main_context_new ();
216 if (use_thread_context) {
217 g_main_context_push_thread_default (async_context);
218 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
219 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
222 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
223 SOUP_SESSION_ASYNC_CONTEXT, async_context,
226 g_main_context_unref (async_context);
228 uri = g_build_filename (base_uri, "slow", NULL);
230 debug_printf (1, " send_message\n");
231 msg = soup_message_new ("GET", uri);
232 soup_session_send_message (session, msg);
233 if (msg->status_code != SOUP_STATUS_OK) {
234 debug_printf (1, " unexpected status: %d %s\n",
235 msg->status_code, msg->reason_phrase);
238 g_object_unref (msg);
240 soup_test_session_abort_unref (session);
243 g_source_remove (idle);
245 if (use_thread_context)
246 g_main_context_pop_thread_default (async_context);
250 idle_test2_fail (gpointer user_data)
252 debug_printf (1, " idle ran!\n");
258 multi_request_started (SoupSession *session, SoupMessage *msg,
259 SoupSocket *socket, gpointer user_data)
261 g_object_set_data (G_OBJECT (msg), "started", GUINT_TO_POINTER (TRUE));
265 msg1_got_headers (SoupMessage *msg, gpointer user_data)
267 GMainLoop *loop = user_data;
269 g_main_loop_quit (loop);
273 multi_msg_finished (SoupSession *session, SoupMessage *msg, gpointer user_data)
275 GMainLoop *loop = user_data;
277 g_object_set_data (G_OBJECT (msg), "finished", GUINT_TO_POINTER (TRUE));
278 g_main_loop_quit (loop);
282 do_multicontext_test (int n)
284 SoupSession *session;
285 SoupMessage *msg1, *msg2;
286 GMainContext *context1, *context2;
287 GMainLoop *loop1, *loop2;
289 debug_printf (1, "\nTest %d: Using multiple async contexts\n", n);
291 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
292 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
294 g_signal_connect (session, "request-started",
295 G_CALLBACK (multi_request_started), NULL);
297 context1 = g_main_context_new ();
298 loop1 = g_main_loop_new (context1, FALSE);
299 context2 = g_main_context_new ();
300 loop2 = g_main_loop_new (context2, FALSE);
302 g_main_context_push_thread_default (context1);
303 msg1 = soup_message_new ("GET", base_uri);
305 soup_session_queue_message (session, msg1, multi_msg_finished, loop1);
306 g_signal_connect (msg1, "got-headers",
307 G_CALLBACK (msg1_got_headers), loop1);
308 g_object_set_data (G_OBJECT (msg1), "session", session);
309 g_main_context_pop_thread_default (context1);
311 g_main_context_push_thread_default (context2);
312 msg2 = soup_message_new ("GET", base_uri);
314 soup_session_queue_message (session, msg2, multi_msg_finished, loop2);
315 g_main_context_pop_thread_default (context2);
317 g_main_context_push_thread_default (context1);
318 g_main_loop_run (loop1);
319 g_main_context_pop_thread_default (context1);
321 if (!g_object_get_data (G_OBJECT (msg1), "started")) {
322 debug_printf (1, " msg1 not started??\n");
325 if (g_object_get_data (G_OBJECT (msg2), "started")) {
326 debug_printf (1, " msg2 started while loop1 was running!\n");
330 g_main_context_push_thread_default (context2);
331 g_main_loop_run (loop2);
332 g_main_context_pop_thread_default (context2);
334 if (g_object_get_data (G_OBJECT (msg1), "finished")) {
335 debug_printf (1, " msg1 finished while loop2 was running!\n");
338 if (!g_object_get_data (G_OBJECT (msg2), "finished")) {
339 debug_printf (1, " msg2 not finished??\n");
343 g_main_context_push_thread_default (context1);
344 g_main_loop_run (loop1);
345 g_main_context_pop_thread_default (context1);
347 if (!g_object_get_data (G_OBJECT (msg1), "finished")) {
348 debug_printf (1, " msg1 not finished??\n");
352 g_object_unref (msg1);
353 g_object_unref (msg2);
355 soup_test_session_abort_unref (session);
357 g_main_loop_unref (loop1);
358 g_main_loop_unref (loop2);
359 g_main_context_unref (context1);
360 g_main_context_unref (context2);
364 main (int argc, char **argv)
368 test_init (argc, argv, NULL);
370 server = soup_test_server_new (TRUE);
371 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
372 base_uri = g_strdup_printf ("http://127.0.0.1:%u/",
373 soup_server_get_port (server));
379 do_multicontext_test (5);
382 soup_test_server_quit_unref (server);