[libgdata/offline-testing] tests: UNFINISHED additions to the mock server for comparison mode
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata/offline-testing] tests: UNFINISHED additions to the mock server for comparison mode
- Date: Tue, 30 Jul 2013 08:27:27 +0000 (UTC)
commit ecbefe699174d936be0b35a50b9ed87556434ed9
Author: Philip Withnall <philip tecnocode co uk>
Date: Sun Jul 28 13:13:16 2013 +0200
tests: UNFINISHED additions to the mock server for comparison mode
gdata/tests/common.c | 21 ++++++-
gdata/tests/mock-server.c | 135 +++++++++++++++++++++++++++++++++++++++-----
gdata/tests/mock-server.h | 3 +-
3 files changed, 138 insertions(+), 21 deletions(-)
---
diff --git a/gdata/tests/common.c b/gdata/tests/common.c
index 27d96be..d6f51dd 100644
--- a/gdata/tests/common.c
+++ b/gdata/tests/common.c
@@ -48,6 +48,9 @@ static GFile *trace_dir = NULL;
/* TRUE if tests should be run online and a trace file written for each; FALSE if tests should run offline
against existing trace files. */
static gboolean write_traces = FALSE;
+/* TRUE if tests should be run online and the server's responses compared to the existing trace file for
each; FALSE if tests should run offline without comparison. */
+static gboolean compare_traces = FALSE;
+
/* Global mock server instance used by all tests. */
static GDataMockServer *mock_server = NULL;
@@ -82,6 +85,9 @@ gdata_test_init (int argc, char **argv)
} else if (strcmp ("--write-traces", argv[i]) == 0 || strcmp ("-w", argv[i]) == 0) {
write_traces = TRUE;
argv[i] = (char*) "";
+ } else if (strcmp ("--compare-traces", argv[i]) == 0 || strcmp ("-c", argv[i]) == 0) {
+ compare_traces = TRUE;
+ argv[i] = (char*) "";
} else if (strcmp ("-?", argv[i]) == 0 || strcmp ("--help", argv[i]) == 0 || strcmp ("-h" ,
argv[i]) == 0) {
/* We have to override --help in order to document --no-internet and --no-interactive
*/
printf ("Usage:\n"
@@ -100,12 +106,19 @@ gdata_test_init (int argc, char **argv)
" -n, --no-internet Only execute tests which don't require
Internet connectivity\n"
" -i, --no-interactive Only execute tests which don't require
user interaction\n"
" -t, --trace-dir [directory] Read/Write trace files in the specified
directory\n"
- " -w, --write-traces Work online and write trace files to
--trace-dir\n",
+ " -w, --write-traces Work online and write trace files to
--trace-dir\n"
+ " -c, --compare-traces Work online and compare with existing
trace files in --trace-dir\n",
argv[0]);
exit (0);
}
}
+ /* --[write|compare]-traces are mutually exclusive. */
+ if (write_traces == TRUE && compare_traces == TRUE) {
+ fprintf (stderr, "Error: --write-traces and --compare-traces are mutually exclusive.\n");
+ exit (1);
+ }
+
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=");
@@ -121,7 +134,7 @@ gdata_test_init (int argc, char **argv)
mock_server = gdata_mock_server_new ();
gdata_mock_server_set_enable_logging (mock_server, write_traces);
- gdata_mock_server_set_enable_online (mock_server, write_traces);
+ gdata_mock_server_set_enable_online (mock_server, write_traces || compare_traces);
}
/*
@@ -757,8 +770,8 @@ gdata_test_debug_handler (const gchar *log_domain, GLogLevelFlags log_level, con
message_list = g_slist_append (message_list, g_strdup (message));
/* Log to the trace file. */
- if (write_traces == TRUE && message != NULL && (*message == '<' || *message == '>' || *message == '
') && *(message + 1) == ' ') {
- gdata_mock_server_log_message_chunk (mock_server, message);
+ if (message != NULL && (*message == '<' || *message == '>' || *message == ' ') && *(message + 1) == '
') {
+ gdata_mock_server_received_message_chunk (mock_server, message);
}
}
diff --git a/gdata/tests/mock-server.c b/gdata/tests/mock-server.c
index ae1cc39..240bcc6 100644
--- a/gdata/tests/mock-server.c
+++ b/gdata/tests/mock-server.c
@@ -30,6 +30,14 @@
* The mock server currently only operates on a single network interface, on HTTPS only. This may change in
future. A dummy TLS certificate is used
* to authenticate the server. This certificate is not signed by a CA, so the SoupSession:ssl-strict
property must be set to %FALSE in client code
* during (and only during!) testing.
+ *
+ * The server can operate in three modes: logging, testing, and comparing. These are set by
#GDataMockServer:enable-logging and #GDataMockServer:enable-online.
+ * • Logging mode (#GDataMockServer:enable-logging: %TRUE, #GDataMockServer:enable-online: %TRUE): Requests
are sent to the real server online, and the
+ * request–response pairs recorded to a log file.
+ * • Testing mode (#GDataMockServer:enable-logging: %FALSE, #GDataMockServer:enable-online: %FALSE):
Requests are sent to the mock server, which responds
+ * from the trace file.
+ * • Comparing mode (#GDataMockServer:enable-logging: %FALSE, #GDataMockServer:enable-online: %TRUE):
Requests are sent to the real server online, and
+ * the request–response pairs are compared against those in an existing log file to see if the log file
is up-to-date.
*/
#include <glib.h>
@@ -74,6 +82,9 @@ struct _GDataMockServerPrivate {
GFile *trace_directory;
gboolean enable_online;
gboolean enable_logging;
+
+ GString *comparison_message;
+ gboolean comparison_message_seen_request;
};
enum {
@@ -211,6 +222,10 @@ gdata_mock_server_dispose (GObject *object)
g_clear_object (&priv->trace_directory);
g_clear_pointer (&priv->server_thread, g_thread_unref);
+ if (priv->comparison_message != NULL) {
+ g_string_free (priv->comparison_message, TRUE);
+ }
+
/* Chain up to the parent class */
G_OBJECT_CLASS (gdata_mock_server_parent_class)->dispose (object);
}
@@ -284,10 +299,16 @@ load_file_iteration_data_free (LoadFileIterationData *data)
static SoupURI * /* transfer full */
build_base_uri (GDataMockServer *self)
{
+ GDataMockServerPrivate *priv = self->priv;
gchar *base_uri_string;
SoupURI *base_uri;
- base_uri_string = g_strdup_printf ("https://%s:%u", soup_address_get_physical (self->priv->address),
self->priv->port);
+ if (priv->enable_online == FALSE) {
+ base_uri_string = g_strdup_printf ("https://%s:%u", soup_address_get_physical
(self->priv->address), self->priv->port);
+ } else {
+ base_uri_string = g_strdup ("https://localhost"); /* FIXME */
+ }
+
base_uri = soup_uri_new (base_uri_string);
g_free (base_uri_string);
@@ -842,6 +863,28 @@ load_file_iteration_thread_cb (GTask *task, gpointer source_object, gpointer tas
}
/**
+ * gdata_mock_server_unload_trace:
+ * @self: a #GDataMockServer
+ *
+ * Unloads the current trace file of network messages, as loaded by gdata_mock_server_load_trace() or
gdata_mock_server_load_trace_async().
+ */
+void
+gdata_mock_server_unload_trace (GDataMockServer *self)
+{
+ GDataMockServerPrivate *priv = self->priv;
+
+ g_return_if_fail (GDATA_IS_MOCK_SERVER (self));
+
+ g_clear_object (&priv->next_message);
+ g_clear_object (&priv->input_stream);
+ g_clear_object (&priv->trace_file);
+
+ g_string_free (priv->comparison_message, TRUE);
+ priv->comparison_message = NULL;
+ priv->comparison_message_seen_request = FALSE;
+}
+
+/**
* gdata_mock_server_load_trace:
* @self: a #GDataMockServer
* @trace_file: trace file to load
@@ -877,6 +920,8 @@ gdata_mock_server_load_trace (GDataMockServer *self, GFile *trace_file, GCancell
GError *child_error = NULL;
priv->next_message = load_file_iteration (priv->input_stream, base_uri, cancellable,
&child_error);
+ priv->comparison_message = g_string_new (NULL);
+ priv->comparison_message_seen_request = FALSE;
if (child_error != NULL) {
g_clear_object (&priv->trace_file);
@@ -983,6 +1028,8 @@ gdata_mock_server_load_trace_finish (GDataMockServer *self, GAsyncResult *result
g_return_if_fail (g_task_is_valid (result, self));
self->priv->next_message = g_task_propagate_pointer (G_TASK (result), error);
+ self->priv->comparison_message = g_string_new (NULL);
+ self->priv->comparison_message_seen_request = FALSE;
}
static gpointer
@@ -1106,9 +1153,7 @@ gdata_mock_server_stop (GDataMockServer *self)
g_object_thaw_notify (G_OBJECT (self));
/* Reset the trace file. */
- g_clear_object (&priv->next_message);
- g_clear_object (&priv->input_stream);
- g_clear_object (&priv->trace_file);
+ gdata_mock_server_unload_trace (self);
}
/**
@@ -1218,7 +1263,7 @@ gdata_mock_server_start_trace_full (GDataMockServer *self, GFile *trace_file)
}
}
- /* Start reading from a trace file if online testing is disabled. */
+ /* Start reading from a trace file if online testing is disabled or if we need to compare server
responses to the trace file. */
if (priv->enable_online == FALSE) {
gdata_mock_server_run (self);
gdata_mock_server_load_trace (self, trace_file, NULL, &child_error);
@@ -1234,6 +1279,18 @@ gdata_mock_server_start_trace_full (GDataMockServer *self, GFile *trace_file)
return;
}
+ } else if (priv->enable_online == TRUE && priv->enable_logging == FALSE) {
+ gdata_mock_server_load_trace (self, trace_file, NULL, &child_error);
+
+ if (child_error != NULL) {
+ gchar *trace_file_path = g_file_get_path (trace_file);
+ g_error ("Error loading trace file ‘%s’: %s", trace_file_path, child_error->message);
+ g_free (trace_file_path);
+
+ g_error_free (child_error);
+
+ return;
+ }
}
}
@@ -1255,6 +1312,8 @@ gdata_mock_server_end_trace (GDataMockServer *self)
if (priv->enable_online == FALSE) {
gdata_mock_server_stop (self);
+ } else if (priv->enable_online == TRUE && priv->enable_logging == FALSE) {
+ gdata_mock_server_unload_trace (self);
}
if (priv->enable_logging == TRUE) {
@@ -1327,19 +1386,19 @@ gdata_mock_server_set_enable_logging (GDataMockServer *self, gboolean enable_log
}
/**
- * gdata_mock_server_log_message_chunk:
+ * gdata_mock_server_received_message_chunk:
* @self: a #GDataMockServer
- * @message_chunk: single line of a message to log
- *
- * Appends a single new line of a message to the current trace file, adding a newline character at the end.
+ * @message_chunk: single line of a message which was received
*
- * This function is a no-op if the mock server is not in logging mode (i.e. if
#GDataMockServer:enable-logging is %FALSE),
- * or if a trace file has not been specified using gdata_mock_server_start_trace().
+ * Indicates to the mock server that a single new line of a message was received from the real server. The
message line may be
+ * appended to the current trace file if logging is enabled (#GDataMockServer:enable-logging is %TRUE),
adding a newline character
+ * at the end. If logging is disabled but online mode is enabled (#GDataMockServer:enable-online is %TRUE),
the message line will
+ * be compared to the next expected line in the existing trace file. Otherwise, this function is a no-op.
*
* On error, a warning will be printed. FIXME: That's icky.
*/
void
-gdata_mock_server_log_message_chunk (GDataMockServer *self, const gchar *message_chunk)
+gdata_mock_server_received_message_chunk (GDataMockServer *self, const gchar *message_chunk)
{
GDataMockServerPrivate *priv = self->priv;
GError *child_error = NULL;
@@ -1347,14 +1406,15 @@ gdata_mock_server_log_message_chunk (GDataMockServer *self, const gchar *message
g_return_if_fail (GDATA_IS_MOCK_SERVER (self));
g_return_if_fail (message_chunk != NULL);
- /* Silently ignore the call if logging is disabled or if a trace file hasn't been specified. */
- if (priv->enable_logging == FALSE || priv->output_stream == NULL) {
+ /* Silently ignore the call if logging is disabled and we're offline, or if a trace file hasn't been
specified. */
+ if ((priv->enable_logging == FALSE && priv->enable_online == FALSE) || (priv->enable_logging == TRUE
&& priv->output_stream == NULL)) {
return;
}
/* Append to the trace file. */
- if (g_output_stream_write_all (G_OUTPUT_STREAM (priv->output_stream), message_chunk, strlen
(message_chunk), NULL, NULL, &child_error) == FALSE ||
- g_output_stream_write_all (G_OUTPUT_STREAM (priv->output_stream), "\n", 1, NULL, NULL,
&child_error) == FALSE) {
+ if (priv->enable_logging == TRUE &&
+ (g_output_stream_write_all (G_OUTPUT_STREAM (priv->output_stream), message_chunk, strlen
(message_chunk), NULL, NULL, &child_error) == FALSE ||
+ g_output_stream_write_all (G_OUTPUT_STREAM (priv->output_stream), "\n", 1, NULL, NULL,
&child_error) == FALSE)) {
gchar *trace_file_path = g_file_get_path (priv->trace_file);
g_warning ("Error appending to log file ‘%s’: %s", trace_file_path, child_error->message);
g_free (trace_file_path);
@@ -1363,6 +1423,49 @@ gdata_mock_server_log_message_chunk (GDataMockServer *self, const gchar *message
return;
}
+
+ /* Or compare to the existing trace file. */
+ if (priv->enable_logging == FALSE && priv->enable_online == TRUE) {
+ /* Build up the message to compare. */
+ g_string_append (priv->comparison_message, message_chunk);
+ g_string_append_c (priv->comparison_message, '\n');
+
+ if (strcmp (message_chunk, " ") == 0 && priv->comparison_message_seen_request == FALSE) {
+ /* Need to capture both the request and the response before processing; both are
terminated by a single “ ” chunk. */
+ priv->comparison_message_seen_request = TRUE;
+ } else if (strcmp (message_chunk, " ") == 0) {
+ /* Received the last chunk of the response, so compare the message from the trace
file and that from online. */
+ SoupMessage *online_message;
+ SoupURI *base_uri;
+
+ /* End of a message. */
+ base_uri = soup_uri_new ("https://localhost/"); /* FIXME */
+ online_message = trace_to_soup_message (priv->comparison_message->str, base_uri);
+ soup_uri_free (base_uri);
+
+ g_string_truncate (priv->comparison_message, 0);
+ priv->comparison_message_seen_request = FALSE;
+
+ g_assert (priv->next_message != NULL);
+
+ /* Compare the message from the server with the message in the log file. */
+ if (compare_incoming_message (online_message, priv->next_message, NULL) != 0) {
+ gchar *next_uri, *actual_uri;
+
+ next_uri = soup_uri_to_string (soup_message_get_uri (priv->next_message),
TRUE);
+ actual_uri = soup_uri_to_string (soup_message_get_uri (online_message), TRUE);
+ g_warning ("Expected URI ‘%s’, but got ‘%s’.", next_uri, actual_uri);
+ g_free (actual_uri);
+ g_free (next_uri);
+
+ g_object_unref (online_message);
+
+ return;
+ }
+
+ g_object_unref (online_message);
+ }
+ }
}
/**
diff --git a/gdata/tests/mock-server.h b/gdata/tests/mock-server.h
index 1819494..bc175a0 100644
--- a/gdata/tests/mock-server.h
+++ b/gdata/tests/mock-server.h
@@ -60,6 +60,7 @@ GDataMockServer *gdata_mock_server_new (void) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_R
void gdata_mock_server_load_trace (GDataMockServer *self, GFile *trace_file, GCancellable *cancellable,
GError **error);
void gdata_mock_server_load_trace_async (GDataMockServer *self, GFile *trace_file, GCancellable
*cancellable, GAsyncReadyCallback callback, gpointer user_data);
void gdata_mock_server_load_trace_finish (GDataMockServer *self, GAsyncResult *result, GError **error);
+void gdata_mock_server_unload_trace (GDataMockServer *self);
void gdata_mock_server_run (GDataMockServer *self);
void gdata_mock_server_stop (GDataMockServer *self);
@@ -77,7 +78,7 @@ void gdata_mock_server_set_enable_online (GDataMockServer *self, gboolean enable
gboolean gdata_mock_server_get_enable_logging (GDataMockServer *self) G_GNUC_WARN_UNUSED_RESULT;
void gdata_mock_server_set_enable_logging (GDataMockServer *self, gboolean enable_logging);
-void gdata_mock_server_log_message_chunk (GDataMockServer *self, const gchar *message_chunk);
+void gdata_mock_server_received_message_chunk (GDataMockServer *self, const gchar *message_chunk);
SoupAddress *gdata_mock_server_get_address (GDataMockServer *self);
guint gdata_mock_server_get_port (GDataMockServer *self);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]