#include "test-utils.h"
#include "soup-session-private.h"
static GUri *base_uri;
static gboolean server_processed_message;
static gboolean timeout;
static GMainLoop *loop;
static SoupMessagePriority expected_priorities[3];
static GBytes *index_bytes;
static gboolean
timeout_cb (gpointer user_data)
{
gboolean *timeout = user_data;
*timeout = TRUE;
return FALSE;
}
static void
server_handler (SoupServer *server,
SoupServerMessage *msg,
const char *path,
GHashTable *query,
gpointer user_data)
{
if (!strcmp (path, "/request-timeout")) {
GMainContext *context = g_main_context_get_thread_default ();
GSource *timer;
timer = g_timeout_source_new (100);
g_source_set_callback (timer, timeout_cb, &timeout, NULL);
g_source_attach (timer, context);
g_source_unref (timer);
} else if (!strcmp (path, "/index.txt")) {
soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
soup_server_message_set_response (msg, "text/plain",
SOUP_MEMORY_STATIC,
g_bytes_get_data (index_bytes, NULL),
g_bytes_get_size (index_bytes));
return;
} else
server_processed_message = TRUE;
soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
soup_server_message_set_response (msg, "text/plain",
SOUP_MEMORY_STATIC,
"ok\r\n", 4);
}
static void
finished_cb (SoupMessage *msg,
gboolean *finished)
{
*finished = TRUE;
}
static void
cancel_message_cb (SoupMessage *msg,
GCancellable *cancellable)
{
g_cancellable_cancel (cancellable);
}
static void
cancel_message_send_done (SoupSession *session,
GAsyncResult *result,
GError **error)
{
g_assert_null (soup_session_send_finish (session, result, error));
g_main_loop_quit (loop);
}
static void
do_test_for_session (SoupSession *session,
gboolean queue_is_async,
gboolean send_is_blocking)
{
SoupMessage *msg;
gboolean finished, local_timeout;
guint timeout_id;
GUri *timeout_uri;
GBytes *body;
GCancellable *cancellable;
GError *error = NULL;
debug_printf (1, " queue_message\n");
debug_printf (2, " requesting timeout\n");
timeout_uri = g_uri_parse_relative (base_uri, "/request-timeout", SOUP_HTTP_URI_FLAGS, NULL);
msg = soup_message_new_from_uri ("GET", timeout_uri);
body = soup_session_send_and_read (session, msg, NULL, NULL);
g_bytes_unref (body);
g_uri_unref (timeout_uri);
msg = soup_message_new_from_uri ("GET", base_uri);
server_processed_message = timeout = finished = FALSE;
g_signal_connect (msg, "finished",
G_CALLBACK (finished_cb), &finished);
soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
g_object_unref (msg);
while (!timeout)
g_usleep (100);
debug_printf (2, " got timeout\n");
if (queue_is_async) {
g_assert_false (server_processed_message);
debug_printf (2, " waiting for finished\n");
while (!finished)
g_main_context_iteration (NULL, TRUE);
g_assert_true (server_processed_message);
} else {
g_assert_true (server_processed_message);
g_assert_false (finished);
debug_printf (2, " waiting for finished\n");
while (!finished)
g_main_context_iteration (NULL, TRUE);
}
debug_printf (1, " send_message\n");
msg = soup_message_new_from_uri ("GET", base_uri);
server_processed_message = local_timeout = FALSE;
timeout_id = g_idle_add_full (G_PRIORITY_HIGH, timeout_cb, &local_timeout, NULL);
body = soup_session_send_and_read (session, msg, NULL, NULL);
g_bytes_unref (body);
g_object_unref (msg);
g_assert_true (server_processed_message);
if (send_is_blocking) {
soup_test_assert (!local_timeout,
"send_message ran main loop");
} else {
soup_test_assert (local_timeout,
"send_message didn't run main loop");
}
if (!local_timeout)
g_source_remove (timeout_id);
if (!queue_is_async)
return;
debug_printf (1, " cancel_message\n");
msg = soup_message_new_from_uri ("GET", base_uri);
cancellable = g_cancellable_new ();
soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, cancellable,
(GAsyncReadyCallback)cancel_message_send_done,
&error);
g_signal_connect (msg, "wrote-headers",
G_CALLBACK (cancel_message_cb), cancellable);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_main_loop_unref (loop);
g_clear_error (&error);
g_object_unref (cancellable);
g_object_unref (msg);
}
static void
do_plain_tests (void)
{
SoupSession *session;
session = soup_test_session_new (NULL);
do_test_for_session (session, TRUE, TRUE);
soup_test_session_abort_unref (session);
}
static void
priority_test_finished_cb (SoupMessage *msg,
guint *finished_count)
{
SoupMessagePriority priority = soup_message_get_priority (msg);
debug_printf (1, " received message %d with priority %d\n",
*finished_count, priority);
soup_test_assert (priority == expected_priorities[*finished_count],
"message %d should have priority %d (%d found)",
*finished_count, expected_priorities[*finished_count], priority);
(*finished_count)++;
}
static void
do_priority_tests (void)
{
SoupSession *session;
int i, finished_count = 0;
SoupMessagePriority priorities[] =
{ SOUP_MESSAGE_PRIORITY_LOW,
SOUP_MESSAGE_PRIORITY_HIGH,
SOUP_MESSAGE_PRIORITY_NORMAL };
g_test_bug ("696277");
session = soup_test_session_new ("max-conns", 1, NULL);
expected_priorities[0] = SOUP_MESSAGE_PRIORITY_HIGH;
expected_priorities[1] = SOUP_MESSAGE_PRIORITY_NORMAL;
expected_priorities[2] = SOUP_MESSAGE_PRIORITY_LOW;
for (i = 0; i < 3; i++) {
GUri *msg_uri;
SoupMessage *msg;
char buf[5];
g_snprintf (buf, sizeof (buf), "%d", i);
msg_uri = g_uri_parse_relative (base_uri, buf, SOUP_HTTP_URI_FLAGS, NULL);
msg = soup_message_new_from_uri ("GET", msg_uri);
g_uri_unref (msg_uri);
soup_message_set_priority (msg, priorities[i]);
g_signal_connect (msg, "finished",
G_CALLBACK (priority_test_finished_cb), &finished_count);
soup_session_send_async (session, msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
g_object_unref (msg);
}
debug_printf (2, " waiting for finished\n");
while (finished_count != 3)
g_main_context_iteration (NULL, TRUE);
soup_test_session_abort_unref (session);
}
static void
do_priority_change_test (void)
{
SoupSession *session;
SoupMessage *msgs[3];
int i, finished_count = 0;
SoupMessagePriority priorities[] =
{ SOUP_MESSAGE_PRIORITY_LOW,
SOUP_MESSAGE_PRIORITY_HIGH,
SOUP_MESSAGE_PRIORITY_NORMAL };
session = soup_test_session_new ("max-conns", 1, NULL);
expected_priorities[0] = SOUP_MESSAGE_PRIORITY_HIGH;
expected_priorities[1] = SOUP_MESSAGE_PRIORITY_LOW;
expected_priorities[2] = SOUP_MESSAGE_PRIORITY_VERY_LOW;
for (i = 0; i < 3; i++) {
GUri *msg_uri;
char buf[5];
g_snprintf (buf, sizeof (buf), "%d", i);
msg_uri = g_uri_parse_relative (base_uri, buf, SOUP_HTTP_URI_FLAGS, NULL);
msgs[i] = soup_message_new_from_uri ("GET", msg_uri);
g_uri_unref (msg_uri);
soup_message_set_priority (msgs[i], priorities[i]);
g_signal_connect (msgs[i], "finished",
G_CALLBACK (priority_test_finished_cb), &finished_count);
soup_session_send_async (session, msgs[i], G_PRIORITY_DEFAULT, NULL, NULL, NULL);
}
soup_message_set_priority (msgs[2], SOUP_MESSAGE_PRIORITY_VERY_LOW);
debug_printf (2, " waiting for finished\n");
while (finished_count != 3)
g_main_context_iteration (NULL, TRUE);
for (i = 0; i < 3; i++)
g_object_unref (msgs[i]);
soup_test_session_abort_unref (session);
}
static void
test_session_properties (const char *name,
SoupSession *session,
GProxyResolver *expected_proxy_resolver,
GTlsDatabase *expected_tls_database)
{
GProxyResolver *proxy_resolver = soup_session_get_proxy_resolver (session);
GTlsDatabase *tlsdb = soup_session_get_tls_database (session);
soup_test_assert (proxy_resolver == expected_proxy_resolver,
"%s has %s proxy resolver",
name, proxy_resolver ? (expected_proxy_resolver ? "wrong" : "a") : "no");
soup_test_assert (tlsdb == expected_tls_database,
"%s has %s TLS database",
name, tlsdb ? (expected_tls_database ? "wrong" : "a") : "no");
}
static void
do_property_tests (void)
{
SoupSession *session;
GProxyResolver *proxy_resolver, *default_proxy_resolver;
GTlsDatabase *tlsdb, *default_tlsdb;
g_test_bug ("708696");
default_proxy_resolver = g_proxy_resolver_get_default ();
default_tlsdb = g_tls_backend_get_default_database (g_tls_backend_get_default ());
session = g_object_new (SOUP_TYPE_SESSION,
NULL);
test_session_properties ("Base plain session", session,
default_proxy_resolver, default_tlsdb);
g_object_unref (session);
session = g_object_new (SOUP_TYPE_SESSION,
"proxy-resolver", NULL,
NULL);
test_session_properties ("Session with NULL :proxy-resolver", session,
NULL, default_tlsdb);
g_object_unref (session);
proxy_resolver = g_simple_proxy_resolver_new (NULL, NULL);
session = g_object_new (SOUP_TYPE_SESSION,
"proxy-resolver", proxy_resolver,
NULL);
test_session_properties ("Session with non-NULL :proxy-resolver", session,
proxy_resolver, default_tlsdb);
g_object_unref (proxy_resolver);
g_object_unref (session);
session = g_object_new (SOUP_TYPE_SESSION,
"tls-database", NULL,
NULL);
test_session_properties ("Session with NULL :tls-database", session,
default_proxy_resolver, NULL);
g_object_unref (session);
* so we can only do this test if we have a real TLS backend.
*/
if (tls_available) {
GError *error = NULL;
char *db_path;
db_path = soup_test_build_filename_abs (G_TEST_DIST, "test-cert.pem", NULL);
tlsdb = g_tls_file_database_new (db_path, &error);
g_assert_no_error (error);
g_free (db_path);
session = g_object_new (SOUP_TYPE_SESSION,
"tls-database", tlsdb,
NULL);
test_session_properties ("Session with non-NULL :tls-database", session,
default_proxy_resolver, tlsdb);
g_object_unref (tlsdb);
g_object_unref (session);
}
}
static gint
compare_by_gtype (gconstpointer a,
gconstpointer b)
{
return G_TYPE_CHECK_INSTANCE_TYPE (a, GPOINTER_TO_SIZE (b)) ? 0 : 1;
}
static void
do_features_test (void)
{
SoupSession *session;
GSList *features;
SoupSessionFeature *feature;
session = soup_test_session_new (NULL);
features = soup_session_get_features (session, SOUP_TYPE_SESSION_FEATURE);
g_assert_cmpuint (g_slist_length (features), >=, 1);
g_assert_nonnull (g_slist_find_custom (features, GSIZE_TO_POINTER (SOUP_TYPE_AUTH_MANAGER), compare_by_gtype));
g_assert_true (soup_session_has_feature (session, SOUP_TYPE_AUTH_MANAGER));
feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
g_assert_true (SOUP_IS_AUTH_MANAGER (feature));
soup_session_remove_feature (session, feature);
g_assert_false (soup_session_has_feature (session, SOUP_TYPE_AUTH_MANAGER));
g_assert_null (soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER));
g_slist_free (features);
soup_test_session_abort_unref (session);
}
static void
queue_order_test_message_finished (SoupMessage *msg,
guint *finished_count)
{
(*finished_count)++;
}
static void
queue_order_test_message_network_event (SoupMessage *msg,
GSocketClientEvent event,
GIOStream *connection,
SoupMessage **queue)
{
int i;
if (event != G_SOCKET_CLIENT_RESOLVING)
return;
for (i = 0; i < 3; i++) {
if (queue[i] == NULL) {
queue[i] = msg;
return;
}
}
g_assert_not_reached ();
}
static void
do_queue_order_test (void)
{
SoupSession *session;
SoupMessage *msg1, *msg2, *msg3;
guint finished_count = 0;
SoupMessage *queue[3] = { NULL, NULL, NULL };
session = soup_test_session_new (NULL);
msg1 = soup_message_new_from_uri ("GET", base_uri);
g_signal_connect (msg1, "network-event",
G_CALLBACK (queue_order_test_message_network_event),
queue);
g_signal_connect (msg1, "finished",
G_CALLBACK (queue_order_test_message_finished),
&finished_count);
msg2 = soup_message_new_from_uri ("GET", base_uri);
g_signal_connect (msg2, "network-event",
G_CALLBACK (queue_order_test_message_network_event),
queue);
g_signal_connect (msg2, "finished",
G_CALLBACK (queue_order_test_message_finished),
&finished_count);
msg3 = soup_message_new_from_uri ("GET", base_uri);
g_signal_connect (msg3, "network-event",
G_CALLBACK (queue_order_test_message_network_event),
queue);
g_signal_connect (msg3, "finished",
G_CALLBACK (queue_order_test_message_finished),
&finished_count);
soup_session_send_async (session, msg1, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
soup_session_send_async (session, msg2, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
soup_session_send_async (session, msg3, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
while (queue[2] == NULL)
g_main_context_iteration (NULL, TRUE);
g_assert_true (queue[0] == msg1);
g_assert_true (queue[1] == msg2);
g_assert_true (queue[2] == msg3);
g_object_unref (msg1);
g_object_unref (msg2);
g_object_unref (msg3);
while (finished_count != 3)
g_main_context_iteration (NULL, TRUE);
soup_test_session_abort_unref (session);
}
int
main (int argc, char **argv)
{
SoupServer *server;
int ret;
test_init (argc, argv, NULL);
server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
base_uri = soup_test_server_get_uri (server, "http", NULL);
index_bytes = soup_test_get_index ();
soup_test_register_resources ();
g_test_add_func ("/session/SoupSession", do_plain_tests);
g_test_add_func ("/session/priority", do_priority_tests);
g_test_add_func ("/session/priority-change", do_priority_change_test);
g_test_add_func ("/session/property", do_property_tests);
g_test_add_func ("/session/features", do_features_test);
g_test_add_func ("/session/queue-order", do_queue_order_test);
ret = g_test_run ();
g_uri_unref (base_uri);
soup_test_server_quit_unref (server);
test_cleanup ();
return ret;
}