diff options
Diffstat (limited to 'tests/test-utils.c')
-rw-r--r-- | tests/test-utils.c | 405 |
1 files changed, 312 insertions, 93 deletions
diff --git a/tests/test-utils.c b/tests/test-utils.c index f040b738..bc160aea 100644 --- a/tests/test-utils.c +++ b/tests/test-utils.c @@ -12,8 +12,9 @@ static gboolean apache_running; #endif static SoupLogger *logger; +static SoupBuffer *index_buffer; -int debug_level, errors; +int debug_level; gboolean expect_warning, tls_available; static int http_debug_level; @@ -37,7 +38,7 @@ static GOptionEntry debug_entry[] = { { "debug", 'd', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, increment_debug_level, "Enable (or increase) test-specific debugging", NULL }, - { "http-debug", 'h', G_OPTION_FLAG_NO_ARG, + { "http-debug", 'H', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, increment_http_debug_level, "Enable (or increase) HTTP-level debugging", NULL }, { NULL } @@ -54,21 +55,6 @@ quit (int sig) exit (1); } -static void -test_log_handler (const char *log_domain, GLogLevelFlags log_level, - const char *message, gpointer user_data) -{ - if (log_level & (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL)) { - if (expect_warning) { - expect_warning = FALSE; - debug_printf (2, "Got expected warning: %s\n", message); - return; - } else - errors++; - } - g_log_default_handler (log_domain, log_level, message, user_data); -} - void test_init (int argc, char **argv, GOptionEntry *entries) { @@ -78,7 +64,8 @@ test_init (int argc, char **argv, GOptionEntry *entries) GTlsBackend *tls_backend; setlocale (LC_ALL, ""); - g_type_init (); + g_setenv ("GSETTINGS_BACKEND", "memory", TRUE); + g_setenv ("GIO_USE_PROXY_RESOLVER", "dummy", TRUE); name = strrchr (argv[0], '/'); if (!name++) @@ -87,6 +74,10 @@ test_init (int argc, char **argv, GOptionEntry *entries) name += 3; g_set_prgname (name); + g_test_init (&argc, &argv, NULL); + g_test_set_nonfatal_assertions (); + g_test_bug_base ("https://bugzilla.gnome.org/"); + opts = g_option_context_new (NULL); g_option_context_add_main_entries (opts, debug_entry, NULL); if (entries) @@ -104,8 +95,6 @@ test_init (int argc, char **argv, GOptionEntry *entries) /* Exit cleanly on ^C in case we're valgrinding. */ signal (SIGINT, quit); - g_log_set_default_handler (test_log_handler, NULL); - tls_backend = g_tls_backend_get_default (); tls_available = g_tls_backend_supports_tls (tls_backend); } @@ -120,16 +109,12 @@ test_cleanup (void) if (logger) g_object_unref (logger); + if (index_buffer) + soup_buffer_free (index_buffer); g_main_context_unref (g_main_context_default ()); debug_printf (1, "\n"); - if (errors) { - g_print ("%s: %d error(s).%s\n", - g_get_prgname (), errors, - debug_level == 0 ? " Run with '-d' for details" : ""); - } else - g_print ("%s: OK\n", g_get_prgname ()); } void @@ -150,30 +135,52 @@ debug_printf (int level, const char *format, ...) static gboolean apache_cmd (const char *cmd) { - const char *argv[8]; - char *cwd, *conf; + GPtrArray *argv; + char *server_root, *cwd, *pid_file; +#ifdef HAVE_APACHE_2_4 + char *default_runtime_dir; +#endif int status; gboolean ok; + server_root = g_test_build_filename (G_TEST_BUILT, "", NULL); + cwd = g_get_current_dir (); - conf = g_build_filename (cwd, "httpd.conf", NULL); - - argv[0] = APACHE_HTTPD; - argv[1] = "-d"; - argv[2] = cwd; - argv[3] = "-f"; - argv[4] = conf; - argv[5] = "-k"; - argv[6] = cmd; - argv[7] = NULL; - - ok = g_spawn_sync (cwd, (char **)argv, NULL, 0, NULL, NULL, +#ifdef HAVE_APACHE_2_4 + default_runtime_dir = g_strdup_printf ("DefaultRuntimeDir %s", cwd); +#endif + pid_file = g_strdup_printf ("PidFile %s/httpd.pid", cwd); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, APACHE_HTTPD); + g_ptr_array_add (argv, "-d"); + g_ptr_array_add (argv, server_root); + g_ptr_array_add (argv, "-f"); + g_ptr_array_add (argv, "httpd.conf"); + +#ifdef HAVE_APACHE_2_4 + g_ptr_array_add (argv, "-c"); + g_ptr_array_add (argv, default_runtime_dir); +#endif + g_ptr_array_add (argv, "-c"); + g_ptr_array_add (argv, pid_file); + + g_ptr_array_add (argv, "-k"); + g_ptr_array_add (argv, (char *)cmd); + g_ptr_array_add (argv, NULL); + + ok = g_spawn_sync (cwd, (char **)argv->pdata, NULL, 0, NULL, NULL, NULL, NULL, &status, NULL); if (ok) ok = (status == 0); + g_free (server_root); g_free (cwd); - g_free (conf); + g_free (pid_file); +#ifdef HAVE_APACHE_2_4 + g_free (default_runtime_dir); +#endif + g_ptr_array_free (argv, TRUE); return ok; } @@ -181,6 +188,9 @@ apache_cmd (const char *cmd) void apache_init (void) { + if (g_getenv ("SOUP_TESTS_IN_MAKE_CHECK")) + return; + if (!apache_cmd ("start")) { g_printerr ("Could not start apache\n"); exit (1); @@ -218,15 +228,18 @@ soup_test_session_new (GType type, ...) va_list args; const char *propname; SoupSession *session; + char *cafile; va_start (args, type); propname = va_arg (args, const char *); session = (SoupSession *)g_object_new_valist (type, propname, args); va_end (args); + cafile = g_test_build_filename (G_TEST_DIST, "test-cert.pem", NULL); g_object_set (G_OBJECT (session), - SOUP_SESSION_SSL_CA_FILE, SRCDIR "/test-cert.pem", + SOUP_SESSION_SSL_CA_FILE, cafile, NULL); + g_free (cafile); if (http_debug_level && !logger) { SoupLoggerLogLevel level = MIN ((SoupLoggerLogLevel)http_debug_level, SOUP_LOGGER_LOG_BODY); @@ -243,16 +256,10 @@ soup_test_session_new (GType type, ...) void soup_test_session_abort_unref (SoupSession *session) { - g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session); - soup_session_abort (session); - g_object_unref (session); - if (session) { - errors++; - debug_printf (1, "leaked SoupSession!\n"); - g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session); - } + g_assert_cmpint (G_OBJECT (session)->ref_count, ==, 1); + g_object_unref (session); } static gpointer run_server_thread (gpointer user_data); @@ -262,14 +269,14 @@ test_server_new (gboolean in_own_thread, gboolean ssl) { SoupServer *server; GMainContext *async_context; - const char *ssl_cert_file, *ssl_key_file; + char *ssl_cert_file, *ssl_key_file; SoupAddress *addr; async_context = in_own_thread ? g_main_context_new () : NULL; if (ssl) { - ssl_cert_file = SRCDIR "/test-cert.pem"; - ssl_key_file = SRCDIR "/test-key.pem"; + ssl_cert_file = g_test_build_filename (G_TEST_DIST, "test-cert.pem", NULL); + ssl_key_file = g_test_build_filename (G_TEST_DIST, "test-key.pem", NULL); } else ssl_cert_file = ssl_key_file = NULL; @@ -284,6 +291,8 @@ test_server_new (gboolean in_own_thread, gboolean ssl) g_object_unref (addr); if (async_context) g_main_context_unref (async_context); + g_free (ssl_cert_file); + g_free (ssl_key_file); if (!server) { g_printerr ("Unable to create server\n"); @@ -334,9 +343,6 @@ soup_test_server_quit_unref (SoupServer *server) { GThread *thread; - g_object_add_weak_pointer (G_OBJECT (server), - (gpointer *)&server); - thread = g_object_get_data (G_OBJECT (server), "thread"); if (thread) { soup_add_completion (soup_server_get_async_context (server), @@ -344,19 +350,14 @@ soup_test_server_quit_unref (SoupServer *server) g_thread_join (thread); } else soup_server_quit (server); - g_object_unref (server); - if (server) { - errors++; - debug_printf (1, "leaked SoupServer!\n"); - g_object_remove_weak_pointer (G_OBJECT (server), - (gpointer *)&server); - } + g_assert_cmpint (G_OBJECT (server)->ref_count, ==, 1); + g_object_unref (server); } typedef struct { - GMainLoop *loop; - GAsyncResult *result; + GMainLoop *loop; + GAsyncResult *result; } AsyncAsSyncData; static void @@ -364,51 +365,269 @@ async_as_sync_callback (GObject *object, GAsyncResult *result, gpointer user_data) { - AsyncAsSyncData *data = 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; +} - data->result = g_object_ref (result); - g_main_loop_quit (data->loop); +static void inline +cancel_message_or_cancellable (CancelData *cancel_data) +{ + if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_MESSAGE) { + SoupRequest *req = cancel_data->req; + SoupMessage *msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (req)); + soup_session_cancel_message (soup_request_get_session (req), msg, + SOUP_STATUS_CANCELLED); + g_object_unref (msg); + 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_async_as_sync (SoupRequest *req, - GCancellable *cancellable, - GError **error) +soup_test_request_send (SoupRequest *req, + GCancellable *cancellable, + guint flags, + GError **error) { - AsyncAsSyncData data; - GInputStream *stream; + AsyncAsSyncData data; + GInputStream *stream; + CancelData *cancel_data = create_cancel_data (req, cancellable, flags); - data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) { + GThread *thread; - soup_request_send_async (req, cancellable, async_as_sync_callback, &data); - g_main_loop_run (data.loop); + 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 && + (flags & SOUP_TEST_REQUEST_CANCEL_SOON || flags & SOUP_TEST_REQUEST_CANCEL_IMMEDIATE)) { + guint interval = flags & SOUP_TEST_REQUEST_CANCEL_SOON ? 100 : 0; + g_timeout_add_full (G_PRIORITY_HIGH, interval, cancel_request_timeout, cancel_data, NULL); + } + if (cancel_data && (flags & SOUP_TEST_REQUEST_CANCEL_PREEMPTIVE)) + g_cancellable_cancel (cancellable); + soup_request_send_async (req, cancellable, async_as_sync_callback, &data); + g_main_loop_run (data.loop); - stream = soup_request_send_finish (req, data.result, error); + stream = soup_request_send_finish (req, data.result, error); - g_main_loop_unref (data.loop); - g_object_unref (data.result); + if (cancel_data && (flags & SOUP_TEST_REQUEST_CANCEL_AFTER_SEND_FINISH)) { + GMainContext *context; - return stream; + cancel_message_or_cancellable (cancel_data); + + context = g_main_loop_get_context (data.loop); + while (g_main_context_pending (context)) + g_main_context_iteration (context, FALSE); + } + + g_main_loop_unref (data.loop); + g_object_unref (data.result); + + return stream; +} + +gboolean +soup_test_request_read_all (SoupRequest *req, + GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + char buf[8192]; + AsyncAsSyncData data; + gsize nread; + + if (!SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) + data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + + do { + if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) { + nread = g_input_stream_read (stream, buf, sizeof (buf), + cancellable, error); + } else { + g_input_stream_read_async (stream, buf, sizeof (buf), + G_PRIORITY_DEFAULT, cancellable, + async_as_sync_callback, &data); + g_main_loop_run (data.loop); + nread = g_input_stream_read_finish (stream, data.result, error); + g_object_unref (data.result); + } + } while (nread > 0); + + if (!SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) + g_main_loop_unref (data.loop); + + return nread == 0; } gboolean -soup_test_stream_close_async_as_sync (GInputStream *stream, - GCancellable *cancellable, - GError **error) +soup_test_request_close_stream (SoupRequest *req, + GInputStream *stream, + GCancellable *cancellable, + GError **error) { - AsyncAsSyncData data; - gboolean ok; + AsyncAsSyncData data; + gboolean ok; - data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) + return g_input_stream_close (stream, cancellable, error); - g_input_stream_close_async (stream, G_PRIORITY_DEFAULT, cancellable, - async_as_sync_callback, &data); - g_main_loop_run (data.loop); + data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); - ok = g_input_stream_close_finish (stream, data.result, error); + g_input_stream_close_async (stream, G_PRIORITY_DEFAULT, cancellable, + async_as_sync_callback, &data); + g_main_loop_run (data.loop); - g_main_loop_unref (data.loop); - g_object_unref (data.result); + ok = g_input_stream_close_finish (stream, data.result, error); - return ok; + g_main_loop_unref (data.loop); + g_object_unref (data.result); + + return ok; } + +void +soup_test_register_resources (void) +{ + static gboolean registered = FALSE; + GResource *resource; + char *path; + GError *error = NULL; + + if (registered) + return; + + path = g_test_build_filename (G_TEST_BUILT, "soup-tests.gresource", NULL); + resource = g_resource_load (path, &error); + if (!resource) { + g_printerr ("Could not load resource soup-tests.gresource: %s\n", + error->message); + exit (1); + } + g_free (path); + + g_resources_register (resource); + g_resource_unref (resource); + + registered = TRUE; +} + +SoupBuffer * +soup_test_load_resource (const char *name, + GError **error) +{ + GBytes *bytes; + char *path; + + soup_test_register_resources (); + + path = g_build_path ("/", "/org/gnome/libsoup/tests/resources", name, NULL); + bytes = g_resources_lookup_data (path, G_RESOURCE_LOOKUP_FLAGS_NONE, error); + g_free (path); + + if (!bytes) + return NULL; + + return soup_buffer_new_with_owner (g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes), + bytes, + (GDestroyNotify) g_bytes_unref); +} + +SoupBuffer * +soup_test_get_index (void) +{ + if (!index_buffer) { + char *path, *contents; + gsize length; + GError *error = NULL; + + path = g_test_build_filename (G_TEST_DIST, "index.txt", NULL); + if (!g_file_get_contents (path, &contents, &length, &error)) { + g_printerr ("Could not read index.txt: %s\n", + error->message); + exit (1); + } + g_free (path); + + index_buffer = soup_buffer_new (SOUP_MEMORY_TAKE, contents, length); + } + + return index_buffer; +} + +#ifndef G_HAVE_ISO_VARARGS +void +soup_test_assert (gboolean expr, const char *fmt, ...) +{ + char *message; + va_list args; + + if (G_UNLIKELY (!expr)) { + va_start (args, fmt); + message = g_strdup_vprintf (fmt, args); + va_end (args); + + g_assertion_message (G_LOG_DOMAIN, + "???", 0, "???" + message); + g_free (message); + } +} +#endif |