[libgdata/offline-testing] tests: UNFINISHED additions to allow custom replies
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata/offline-testing] tests: UNFINISHED additions to allow custom replies
- Date: Tue, 30 Jul 2013 08:25:56 +0000 (UTC)
commit 808ee079cf96df48ed43cc04464f6a70aca9bd03
Author: Philip Withnall <philip tecnocode co uk>
Date: Sat Jul 6 18:17:19 2013 +0100
tests: UNFINISHED additions to allow custom replies
including proof-of-concept error unit tests for YouTube
gdata/tests/mock-server.c | 59 ++++++++++++++++++++++++---
gdata/tests/mock-server.h | 5 ++
gdata/tests/youtube.c | 97 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+), 6 deletions(-)
---
diff --git a/gdata/tests/mock-server.c b/gdata/tests/mock-server.c
index 94e147c..e702f4b 100644
--- a/gdata/tests/mock-server.c
+++ b/gdata/tests/mock-server.c
@@ -33,6 +33,8 @@ static void gdata_mock_server_dispose (GObject *object);
static void gdata_mock_server_get_property (GObject *object, guint property_id, GValue *value, GParamSpec
*pspec);
static void gdata_mock_server_set_property (GObject *object, guint property_id, const GValue *value,
GParamSpec *pspec);
+static gboolean real_handle_message (GDataMockServer *self, SoupMessage *message, SoupClientContext *client);
+
static void server_handler_cb (SoupServer *server, SoupMessage *message, const gchar *path, GHashTable
*query, SoupClientContext *client, gpointer user_data);
static void load_file_stream_thread_cb (GTask *task, gpointer source_object, gpointer task_data,
GCancellable *cancellable);
static void load_file_iteration_thread_cb (GTask *task, gpointer source_object, gpointer task_data,
GCancellable *cancellable);
@@ -61,6 +63,13 @@ enum {
PROP_ENABLE_LOGGING,
};
+enum {
+ SIGNAL_HANDLE_MESSAGE = 1,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
G_DEFINE_TYPE (GDataMockServer, gdata_mock_server, G_TYPE_OBJECT)
static void
@@ -74,23 +83,44 @@ gdata_mock_server_class_init (GDataMockServerClass *klass)
gobject_class->set_property = gdata_mock_server_set_property;
gobject_class->dispose = gdata_mock_server_dispose;
+ klass->handle_message = real_handle_message;
+
+ /**
+ * TODO: Document me.
+ */
g_object_class_install_property (gobject_class, PROP_TRACE_DIRECTORY,
g_param_spec_object ("trace-directory",
"Trace Directory", "TODO",
G_TYPE_FILE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * TODO: Document me.
+ */
g_object_class_install_property (gobject_class, PROP_ENABLE_ONLINE,
g_param_spec_boolean ("enable-online",
"Enable Online", "TODO",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * TODO: Document me.
+ */
g_object_class_install_property (gobject_class, PROP_ENABLE_LOGGING,
g_param_spec_boolean ("enable-logging",
"Enable Logging", "TODO",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * TODO: Document me.
+ */
+ signals[SIGNAL_HANDLE_MESSAGE] = g_signal_new ("handle-message", G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDataMockServerClass, handle_message),
+ g_signal_accumulator_true_handled, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_BOOLEAN, 2,
+ SOUP_TYPE_MESSAGE, SOUP_TYPE_CLIENT_CONTEXT);
}
static void
@@ -251,15 +281,27 @@ static void
server_handler_cb (SoupServer *server, SoupMessage *message, const gchar *path, GHashTable *query,
SoupClientContext *client, gpointer user_data)
{
GDataMockServer *self = user_data;
+ gboolean message_handled = FALSE;
+
+ soup_server_pause_message (server, message);
+ g_signal_emit (self, signals[SIGNAL_HANDLE_MESSAGE], 0, message, client, &message_handled);
+ soup_server_unpause_message (server, message);
+
+ /* The message should always be handled by real_handle_message() at least. */
+ g_assert (message_handled == TRUE);
+}
+
+static gboolean
+real_handle_message (GDataMockServer *self, SoupMessage *message, SoupClientContext *client)
+{
GDataMockServerPrivate *priv = self->priv;
-g_message ("%s: %s", __func__, path);
+ gboolean handled = FALSE;
+
/* Asynchronously load the next expected message from the trace file. */
if (priv->next_message == NULL) {
GTask *task;
GError *child_error = NULL;
- soup_server_pause_message (server, message);
-
task = g_task_new (self, NULL, NULL, NULL);
g_task_set_task_data (task, g_object_ref (priv->input_stream), g_object_unref);
g_task_run_in_thread_sync (task, load_file_iteration_thread_cb);
@@ -276,6 +318,7 @@ g_message ("%s: %s", __func__, path);
body = g_strdup_printf ("Error: %s", child_error->message);
soup_message_body_append_take (message->response_body, (guchar *) body, strlen
(body));
+ handled = TRUE;
g_error_free (child_error);
} else if (priv->next_message == NULL) {
@@ -288,15 +331,19 @@ g_message ("%s: %s", __func__, path);
body = g_strdup_printf ("Expected no request, but got ‘%s’.", actual_uri);
g_free (actual_uri);
soup_message_body_append_take (message->response_body, (guchar *) body, strlen
(body));
+ handled = TRUE;
}
-
- soup_server_unpause_message (server, message);
}
/* Process the actual message if we already know the expected message. */
- if (priv->next_message != NULL) {
+ g_assert (priv->next_message != NULL || handled == TRUE);
+ if (handled == FALSE) {
server_process_message (self, message, client);
+ handled = TRUE;
}
+
+ g_assert (handled == TRUE);
+ return handled;
}
/**
diff --git a/gdata/tests/mock-server.h b/gdata/tests/mock-server.h
index d0bbd21..710eaff 100644
--- a/gdata/tests/mock-server.h
+++ b/gdata/tests/mock-server.h
@@ -42,6 +42,11 @@ typedef struct {
typedef struct {
GObjectClass parent;
+
+ /**
+ * TODO: Document me.
+ */
+ gboolean (*handle_message) (GDataMockServer *self, SoupMessage *message, SoupClientContext *client);
} GDataMockServerClass;
GType gdata_mock_server_get_type (void) G_GNUC_CONST;
diff --git a/gdata/tests/youtube.c b/gdata/tests/youtube.c
index 781556a..02f1e27 100644
--- a/gdata/tests/youtube.c
+++ b/gdata/tests/youtube.c
@@ -18,6 +18,7 @@
*/
#include <glib.h>
+#include <string.h>
#include <unistd.h>
#include "gdata.h"
@@ -59,6 +60,101 @@ test_authentication (void)
gdata_mock_server_end_trace (mock_server);
}
+/* TODO: Document me. */
+typedef struct {
+ guint status_code;
+ const gchar *reason_phrase;
+ const gchar *message_body;
+ gboolean client_login_authorizer_error; /* TRUE if error domain is
GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR; FALSE if it's GDATA_SERVICE_ERROR */
+ gint error_code;
+} RequestErrorData;
+
+static const RequestErrorData authentication_errors[] = {
+ { SOUP_STATUS_BAD_REQUEST, "Bad Request", "Invalid parameter ‘foobar’.",
+ FALSE, GDATA_SERVICE_ERROR_PROTOCOL_ERROR },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=BadAuthentication\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=BadAuthentication\nInfo=InvalidSecondFactor\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_INVALID_SECOND_FACTOR },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=NotVerified\nUrl=http://example.com/\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_NOT_VERIFIED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=TermsNotAgreed\nUrl=http://example.com/\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_TERMS_NOT_AGREED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=Unknown\nUrl=http://example.com/\n",
+ FALSE, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=AccountDeleted\nUrl=http://example.com/\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DELETED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=AccountDisabled\nUrl=http://example.com/\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DISABLED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=AccountMigrated\nUrl=http://example.com/\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_MIGRATED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=ServiceDisabled\nUrl=http://example.com/\n",
+ TRUE, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_SERVICE_DISABLED },
+ { SOUP_STATUS_FORBIDDEN, "Access Forbidden", "Error=ServiceUnavailable\nUrl=http://example.com/\n",
+ FALSE, GDATA_SERVICE_ERROR_UNAVAILABLE },
+};
+
+static gboolean
+authentication_error_cb (GDataMockServer *self, SoupMessage *message, SoupClientContext *client, gpointer
user_data)
+{
+ const RequestErrorData *data = user_data;
+
+ soup_message_set_status_full (message, data->status_code, data->reason_phrase);
+ soup_message_body_append (message->response_body, SOUP_MEMORY_STATIC, data->message_body, strlen
(data->message_body));
+
+ return TRUE;
+}
+
+static void
+test_authentication_error (void)
+{
+ gboolean retval;
+ GDataClientLoginAuthorizer *authorizer;
+ GError *error = NULL;
+ gulong handler_id;
+ guint i;
+
+ if (gdata_mock_server_get_enable_logging (mock_server) == TRUE) {
+ g_test_message ("Ignoring test due to logging being enabled.");
+ return;
+ } else if (gdata_mock_server_get_enable_online (mock_server) == TRUE) {
+ g_test_message ("Ignoring test due to running online and test not being reproducible.");
+ return;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (authentication_errors); i++) {
+ const RequestErrorData *data = &authentication_errors[i];
+ GQuark error_domain;
+
+ handler_id = g_signal_connect (mock_server, "handle-message", (GCallback)
authentication_error_cb, (gpointer) data);
+ gdata_mock_server_run (mock_server);
+
+ /* Create an authorizer */
+ authorizer = gdata_client_login_authorizer_new (CLIENT_ID, GDATA_TYPE_YOUTUBE_SERVICE);
+
+ g_assert_cmpstr (gdata_client_login_authorizer_get_client_id (authorizer), ==, CLIENT_ID);
+
+ /* Log in */
+ retval = gdata_client_login_authorizer_authenticate (authorizer, USERNAME, PASSWORD, NULL,
&error);
+ error_domain = (data->client_login_authorizer_error == TRUE) ?
GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR : GDATA_SERVICE_ERROR;
+ g_assert_error (error, error_domain, data->error_code);
+ g_assert (retval == FALSE);
+ g_clear_error (&error);
+
+ /* Check nothing's changed in the authoriser. */
+ g_assert_cmpstr (gdata_client_login_authorizer_get_username (authorizer), ==, NULL);
+ g_assert_cmpstr (gdata_client_login_authorizer_get_password (authorizer), ==, NULL);
+
+ g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer),
+
gdata_youtube_service_get_primary_authorization_domain ()) == FALSE);
+
+ g_object_unref (authorizer);
+
+ gdata_mock_server_stop (mock_server);
+ g_signal_handler_disconnect (mock_server, handler_id);
+ }
+}
+
GDATA_ASYNC_TEST_FUNCTIONS (authentication, void,
G_STMT_START {
GDataClientLoginAuthorizer *authorizer;
@@ -2015,6 +2111,7 @@ main (int argc, char *argv[])
service = GDATA_SERVICE (gdata_youtube_service_new (DEVELOPER_KEY, authorizer));
g_test_add_func ("/youtube/authentication", test_authentication);
+ g_test_add_func ("/youtube/authentication/error", test_authentication_error);
g_test_add ("/youtube/authentication/async", GDataAsyncTestData, NULL, gdata_set_up_async_test_data,
test_authentication_async,
gdata_tear_down_async_test_data);
g_test_add ("/youtube/authentication/async/cancellation", GDataAsyncTestData, NULL,
gdata_set_up_async_test_data,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]