libsoup r1056 - in trunk: . libsoup tests



Author: danw
Date: Sun Jan 27 19:21:30 2008
New Revision: 1056
URL: http://svn.gnome.org/viewvc/libsoup?rev=1056&view=rev

Log:
	* libsoup/soup-dns.c (resolver_thread): fix mutex use to avoid a
	race condition

	* libsoup/soup-xmlrpc.c (soup_xmlrpc_build_faultv):
	(soup_xmlrpc_set_response, soup_xmlrpc_set_fault):
	(soup_xmlrpc_parse_method_call): Fix misc server-side stuff
	(soup_xmlrpc_parse_method_response): Fix fault parsing

	* libsoup/soup-xmlrpc.h (SoupXMLRPCFault): add semi-standard fault
	codes from
	http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php

	* tests/xmlrpc-server.php (sum): return a <fault> if the arguments
	are wrong (so that xmlrpc-test can test that case).
	(dateChange): change to take two parameters, a date and a struct,
	instead of putting the date in the struct, since we weren't
	previously testing multiple parameter handling.

	* tests/xmlrpc-test.c (main): Add a -u flag to specify an
	alternate URL.
	(do_xmlrpc): Remove level 3 debug output, which is now redundant
	with the SoupLogger stuff.
	(test_dateChange): update for dateChange prototype change
	(test_fault_malformed, test_fault_method, test_fault_args): test
	handling of faults

	* tests/xmlrpc-server-test.c: Test the server-side XML-RPC API (by
	implementing the same methods as xmlrpc-server.php and then
	using xmlrpc-test)


Added:
   trunk/tests/xmlrpc-server-test.c
Modified:
   trunk/ChangeLog
   trunk/libsoup/soup-dns.c
   trunk/libsoup/soup-xmlrpc.c
   trunk/libsoup/soup-xmlrpc.h
   trunk/tests/   (props changed)
   trunk/tests/Makefile.am
   trunk/tests/libsoup.supp
   trunk/tests/xmlrpc-server.php
   trunk/tests/xmlrpc-test.c

Modified: trunk/libsoup/soup-dns.c
==============================================================================
--- trunk/libsoup/soup-dns.c	(original)
+++ trunk/libsoup/soup-dns.c	Sun Jan 27 19:21:30 2008
@@ -517,9 +517,9 @@
 	else if (entry->sockaddr == NULL)
 		resolve_address (entry);
 
+	g_mutex_lock (soup_dns_lock);
 	entry->resolver_thread = NULL;
 
-	g_mutex_lock (soup_dns_lock);
 	async_lookups = entry->async_lookups;
 	entry->async_lookups = NULL;
 	g_mutex_unlock (soup_dns_lock);

Modified: trunk/libsoup/soup-xmlrpc.c
==============================================================================
--- trunk/libsoup/soup-xmlrpc.c	(original)
+++ trunk/libsoup/soup-xmlrpc.c	Sun Jan 27 19:21:30 2008
@@ -301,23 +301,23 @@
 	node = xmlNewDocNode (doc, NULL,
 			      (const xmlChar *)"methodResponse", NULL);
 	xmlDocSetRootElement (doc, node);
-	node = xmlNewDocNode (doc, NULL, (const xmlChar *)"fault", NULL);
-	node = xmlNewDocNode (doc, NULL, (const xmlChar *)"value", NULL);
-	node = xmlNewDocNode (doc, NULL, (const xmlChar *)"struct", NULL);
+	node = xmlNewChild (node, NULL, (const xmlChar *)"fault", NULL);
+	node = xmlNewChild (node, NULL, (const xmlChar *)"value", NULL);
+	node = xmlNewChild (node, NULL, (const xmlChar *)"struct", NULL);
 
 	memset (&value, 0, sizeof (value));
 
-	member = xmlNewDocNode (doc, NULL, (const xmlChar *)"member", NULL);
-	xmlNewDocNode (doc, NULL,
-		       (const xmlChar *)"name", (const xmlChar *)"faultCode");
+	member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
+	xmlNewChild (member, NULL,
+		     (const xmlChar *)"name", (const xmlChar *)"faultCode");
 	g_value_init (&value, G_TYPE_INT);
 	g_value_set_int (&value, fault_code);
 	insert_value (member, &value);
 	g_value_unset (&value);
 
-	member = xmlNewDocNode (doc, NULL, (const xmlChar *)"member", NULL);
-	xmlNewDocNode (doc, NULL,
-		       (const xmlChar *)"name", (const xmlChar *)"faultString");
+	member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
+	xmlNewChild (member, NULL,
+		     (const xmlChar *)"name", (const xmlChar *)"faultString");
 	g_value_init (&value, G_TYPE_STRING);
 	g_value_take_string (&value, fault_string);
 	insert_value (member, &value);
@@ -373,14 +373,14 @@
 	char *body;
 
 	va_start (args, type);
-	SOUP_VALUE_GETV (&value, type, args);
+	SOUP_VALUE_SETV (&value, type, args);
 	va_end (args);
 
 	body = soup_xmlrpc_build_method_response (&value);
 	g_value_unset (&value);
 	soup_message_set_status (msg, SOUP_STATUS_OK);
-	soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
-				  body, strlen (body));
+	soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
+				   body, strlen (body));
 }
 
 /**
@@ -406,8 +406,8 @@
 	va_end (args);
 
 	soup_message_set_status (msg, SOUP_STATUS_OK);
-	soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
-				  body, strlen (body));
+	soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
+				   body, strlen (body));
 }
 
 
@@ -586,13 +586,15 @@
 	param = find_real_node (node->children);
 	while (param && !strcmp ((const char *)param->name, "param")) {
 		xval = find_real_node (param->children);
-		if (!xval || !strcmp ((const char *)xval->name, "value") ||
+		if (!xval || strcmp ((const char *)xval->name, "value") != 0 ||
 		    !parse_value (xval, &value)) {
 			g_value_array_free (*params);
 			goto fail;
 		}
 		g_value_array_append (*params, &value);
 		g_value_unset (&value);
+
+		param = find_real_node (param->next);
 	}
 
 	success = TRUE;
@@ -685,30 +687,32 @@
 		goto fail;
 
 	if (!strcmp ((const char *)node->name, "fault") && error) {
-		int fault_code = -1;
-		xmlChar *fault_string = NULL;
+		int fault_code;
+		char *fault_string;
+		GValue fault_val;
+		GHashTable *fault_hash;
 
-		for (node = find_real_node (node->children);
-		     node;
-		     node = find_real_node (node->next)) {
-			if (!strcmp ((const char *)node->name, "faultCode")) {
-				xmlChar *content = xmlNodeGetContent (node);
-				fault_code = atoi ((char *)content);
-				xmlFree (content);
-			} else if (!strcmp ((const char *)node->name, "faultString")) {
-				fault_string = xmlNodeGetContent (node);
-			} else {
-				if (fault_string)
-					xmlFree (fault_string);
-				goto fail;
-			}
+		node = find_real_node (node->children);
+		if (!node || strcmp ((const char *)node->name, "value") != 0)
+			goto fail;
+		if (!parse_value (node, &fault_val))
+			goto fail;
+		if (!G_VALUE_HOLDS (&fault_val, G_TYPE_HASH_TABLE)) {
+			g_value_unset (&fault_val);
+			goto fail;
 		}
-		if (fault_code != -1 && fault_string != NULL) {
-			g_set_error (error, SOUP_XMLRPC_FAULT,
-				     fault_code, "%s", fault_string);
+		fault_hash = g_value_get_boxed (&fault_val);
+		if (!soup_value_hash_lookup (fault_hash, "faultCode",
+					     G_TYPE_INT, &fault_code) ||
+		    !soup_value_hash_lookup (fault_hash, "faultString",
+					     G_TYPE_STRING, &fault_string)) {
+			g_value_unset (&fault_val);
+			goto fail;
 		}
-		if (fault_string)
-			xmlFree (fault_string);
+
+		g_set_error (error, SOUP_XMLRPC_FAULT,
+			     fault_code, "%s", fault_string);
+		g_value_unset (&fault_val);
 	} else if (!strcmp ((const char *)node->name, "params")) {
 		node = find_real_node (node->children);
 		if (!node || strcmp ((const char *)node->name, "param") != 0)

Modified: trunk/libsoup/soup-xmlrpc.h
==============================================================================
--- trunk/libsoup/soup-xmlrpc.h	(original)
+++ trunk/libsoup/soup-xmlrpc.h	Sun Jan 27 19:21:30 2008
@@ -61,6 +61,22 @@
 #define SOUP_XMLRPC_FAULT soup_xmlrpc_fault_quark()
 GQuark soup_xmlrpc_fault_quark (void);
 
+/* From http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php.
+ * These are an extension, not part of the XML-RPC spec; you can't
+ * assume servers will use them.
+ */
+typedef enum {
+	SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED = -32700,
+	SOUP_XMLRPC_FAULT_PARSE_ERROR_UNSUPPORTED_ENCODING = -32701,
+	SOUP_XMLRPC_FAULT_PARSE_ERROR_INVALID_CHARACTER_FOR_ENCODING = -32702,
+	SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_XML_RPC = -32600,
+	SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND = -32601,
+	SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS = -32602,
+	SOUP_XMLRPC_FAULT_SERVER_ERROR_INTERNAL_XML_RPC_ERROR = -32603,
+	SOUP_XMLRPC_FAULT_APPLICATION_ERROR = -32500,
+	SOUP_XMLRPC_FAULT_SYSTEM_ERROR = -32400,
+	SOUP_XMLRPC_FAULT_TRANSPORT_ERROR = -32300,
+} SoupXMLRPCFault;
 
 G_END_DECLS
 

Modified: trunk/tests/Makefile.am
==============================================================================
--- trunk/tests/Makefile.am	(original)
+++ trunk/tests/Makefile.am	Sun Jan 27 19:21:30 2008
@@ -44,6 +44,7 @@
 ssl_test_SOURCES = ssl-test.c $(TEST_SRCS)
 uri_parsing_SOURCES = uri-parsing.c $(TEST_SRCS)
 xmlrpc_test_SOURCES = xmlrpc-test.c $(TEST_SRCS)
+xmlrpc_server_test_SOURCES = xmlrpc-server-test.c $(TEST_SRCS)
 
 if HAVE_APACHE
 APACHE_TESTS = auth-test proxy-test pull-api
@@ -55,7 +56,7 @@
 SSL_TESTS = ssl-test
 endif
 if HAVE_XMLRPC_EPI_PHP
-XMLRPC_TESTS = xmlrpc-test
+XMLRPC_TESTS = xmlrpc-test xmlrpc-server-test
 endif
 
 TESTS =			\

Modified: trunk/tests/libsoup.supp
==============================================================================
--- trunk/tests/libsoup.supp	(original)
+++ trunk/tests/libsoup.supp	Sun Jan 27 19:21:30 2008
@@ -817,6 +817,17 @@
    fun:g_child_watch_source_init_multi_threaded
    fun:g_child_watch_source_init
 }
+{
+   glib/childwatch2b
+   Memcheck:Leak
+   fun:calloc
+   fun:_dl_allocate_tls
+   fun:pthread_create@@GLIBC_2.2.5
+   fun:g_thread_create_posix_impl
+   fun:g_thread_create_full
+   fun:g_child_watch_source_init_multi_threaded
+   fun:g_child_watch_source_init
+}
 
 
 {

Added: trunk/tests/xmlrpc-server-test.c
==============================================================================
--- (empty file)
+++ trunk/tests/xmlrpc-server-test.c	Sun Jan 27 19:21:30 2008
@@ -0,0 +1,337 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <libsoup/soup.h>
+
+#include "test-utils.h"
+
+GMainLoop *loop;
+
+static void
+type_error (SoupMessage *msg, GType expected, GValueArray *params, int bad_value)
+{
+	soup_xmlrpc_set_fault (msg,
+			       SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS,
+			       "Bad parameter #%d: expected %s, got %s",
+			       bad_value + 1, g_type_name (expected),
+			       g_type_name (G_VALUE_TYPE (&params->values[bad_value])));
+}
+
+static void
+args_error (SoupMessage *msg, GValueArray *params, int expected)
+{
+	soup_xmlrpc_set_fault (msg,
+			       SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS,
+			       "Wrong number of parameters: expected %d, got %d",
+			       expected, params->n_values);
+}
+
+static void
+do_sum (SoupMessage *msg, GValueArray *params)
+{
+	int sum = 0, i, val;
+	GValueArray *nums;
+
+	if (params->n_values != 1) {
+		args_error (msg, params, 1);
+		return;
+	}
+	if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &nums)) {
+		type_error (msg, G_TYPE_VALUE_ARRAY, params, 0);
+		return;
+	}
+
+	for (i = 0; i < nums->n_values; i++) {
+		if (!soup_value_array_get_nth (nums, i, G_TYPE_INT, &val)) {
+			type_error (msg, G_TYPE_INT, nums, i);
+			return;
+		}
+		sum += val;
+	}
+
+	soup_xmlrpc_set_response (msg, G_TYPE_INT, sum);
+
+}
+
+static void
+do_countBools (SoupMessage *msg, GValueArray *params)
+{
+	int i, trues = 0, falses = 0;
+	GValueArray *bools;
+	GHashTable *ret = soup_value_hash_new ();
+	gboolean val;
+
+	if (params->n_values != 1) {
+		args_error (msg, params, 1);
+		return;
+	}
+	if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &bools)) {
+		type_error (msg, G_TYPE_VALUE_ARRAY, params, 0);
+		return;
+	}
+
+	for (i = 0; i < bools->n_values; i++) {
+		if (!soup_value_array_get_nth (bools, i, G_TYPE_BOOLEAN, &val)) {
+			type_error (msg, G_TYPE_BOOLEAN, params, i);
+			return;
+		}
+		if (val)
+			trues++;
+		else
+			falses++;
+	}
+
+	soup_value_hash_insert (ret, "true", G_TYPE_INT, trues);
+	soup_value_hash_insert (ret, "false", G_TYPE_INT, falses);
+	soup_xmlrpc_set_response (msg, G_TYPE_HASH_TABLE, ret);
+	g_hash_table_destroy (ret);
+
+}
+
+static void
+do_md5sum (SoupMessage *msg, GValueArray *params)
+{
+	GChecksum *checksum;
+	GByteArray *data, *digest;
+	gsize digest_len = 16;
+
+	if (params->n_values != 1) {
+		args_error (msg, params, 1);
+		return;
+	}
+
+	if (!soup_value_array_get_nth (params, 0, SOUP_TYPE_BYTE_ARRAY, &data)) {
+		type_error (msg, SOUP_TYPE_BYTE_ARRAY, params, 0);
+		return;
+	}
+	checksum = g_checksum_new (G_CHECKSUM_MD5);
+	g_checksum_update (checksum, data->data, data->len);
+	digest = g_byte_array_new ();
+	g_byte_array_set_size (digest, digest_len);
+	g_checksum_get_digest (checksum, digest->data, &digest_len);
+	g_checksum_free (checksum);
+
+	soup_xmlrpc_set_response (msg, SOUP_TYPE_BYTE_ARRAY, digest);
+	g_byte_array_free (digest, TRUE);
+}
+
+
+static void
+do_dateChange (SoupMessage *msg, GValueArray *params)
+{
+	GHashTable *arg;
+	SoupDate *date;
+	int val;
+
+	if (params->n_values != 2) {
+		args_error (msg, params, 2);
+		return;
+	}
+
+	if (!soup_value_array_get_nth (params, 0, SOUP_TYPE_DATE, &date)) {
+		type_error (msg, SOUP_TYPE_DATE, params, 0);
+		return;
+	}
+	if (!soup_value_array_get_nth (params, 1, G_TYPE_HASH_TABLE, &arg)) {
+		type_error (msg, G_TYPE_HASH_TABLE, params, 1);
+		return;
+	}
+
+	if (soup_value_hash_lookup (arg, "tm_year", G_TYPE_INT, &val))
+		date->year = val + 1900;
+	if (soup_value_hash_lookup (arg, "tm_mon", G_TYPE_INT, &val))
+		date->month = val + 1;
+	if (soup_value_hash_lookup (arg, "tm_mday", G_TYPE_INT, &val))
+		date->day = val;
+	if (soup_value_hash_lookup (arg, "tm_hour", G_TYPE_INT, &val))
+		date->hour = val;
+	if (soup_value_hash_lookup (arg, "tm_min", G_TYPE_INT, &val))
+		date->minute = val;
+	if (soup_value_hash_lookup (arg, "tm_sec", G_TYPE_INT, &val))
+		date->second = val;
+
+	soup_xmlrpc_set_response (msg, SOUP_TYPE_DATE, date);
+}
+
+static void
+do_echo (SoupMessage *msg, GValueArray *params)
+{
+	int i;
+	const char *val;
+	GValueArray *in, *out;
+
+	if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &in)) {
+		type_error (msg, G_TYPE_VALUE_ARRAY, params, 0);
+		return;
+	}
+
+	out = g_value_array_new (in->n_values);
+	for (i = 0; i < in->n_values; i++) {
+		if (!soup_value_array_get_nth (in, i, G_TYPE_STRING, &val)) {
+			type_error (msg, G_TYPE_STRING, in, i);
+			return;
+		}
+		soup_value_array_append (out, G_TYPE_STRING, val);
+	}
+
+	soup_xmlrpc_set_response (msg, G_TYPE_VALUE_ARRAY, out);
+	g_value_array_free (out);
+
+}
+
+static void
+server_callback (SoupServer *server, SoupMessage *msg,
+		 const char *path, GHashTable *query,
+		 SoupClientContext *context, gpointer data)
+{
+	char *method_name;
+	GValueArray *params;
+
+	if (msg->method != SOUP_METHOD_POST) {
+		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+		return;
+	}
+
+	soup_message_set_status (msg, SOUP_STATUS_OK);
+
+	if (!soup_xmlrpc_parse_method_call (msg->request_body->data,
+					    msg->request_body->length,
+					    &method_name, &params)) {
+		soup_xmlrpc_set_fault (msg, SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED,
+				       "Could not parse method call");
+		return;
+	}
+
+	if (!strcmp (method_name, "sum"))
+		do_sum (msg, params);
+	else if (!strcmp (method_name, "countBools"))
+		do_countBools (msg, params);
+	else if (!strcmp (method_name, "md5sum"))
+		do_md5sum (msg, params);
+	else if (!strcmp (method_name, "dateChange"))
+		do_dateChange (msg, params);
+	else if (!strcmp (method_name, "echo"))
+		do_echo (msg, params);
+	else {
+		soup_xmlrpc_set_fault (msg, SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND,
+				       "Unknown method %s", method_name);
+	}
+
+	g_free (method_name);
+	g_value_array_free (params);
+}
+
+static void
+xmlrpc_test_exited (GPid pid, int status, gpointer data)
+{
+	errors = WIFEXITED (status) ? WEXITSTATUS (status) : 1;
+	g_main_loop_quit (loop);
+}
+
+static gboolean
+xmlrpc_test_print (GIOChannel *io, GIOCondition cond, gpointer data)
+{
+	char *line;
+	gsize len;
+	GIOStatus status;
+
+	if (!(cond & G_IO_IN))
+		return FALSE;
+
+	status = g_io_channel_read_line (io, &line, &len, NULL, NULL);
+	if (status == G_IO_STATUS_NORMAL) {
+		/* Don't print the exit status, just the debug stuff */
+		if (strncmp (line, "xmlrpc-test:", strlen ("xmlrpc-test:")) != 0)
+			printf ("%s", line);
+		g_free (line);
+		return TRUE;
+	} else if (status == G_IO_STATUS_AGAIN)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static void
+do_xmlrpc_tests (SoupURI *uri)
+{
+	char *argv[7];
+	int arg, out;
+	gboolean ok;
+	GPid pid;
+	GError *error = NULL;
+	GIOChannel *child_out;
+
+	argv[0] = "./xmlrpc-test";
+	argv[1] = "-u";
+	argv[2] = soup_uri_to_string (uri, FALSE);
+
+	for (arg = 0; arg < debug_level && arg < 3; arg++)
+		argv[arg + 3] = "-d";
+	argv[arg + 3] = NULL;
+
+	ok = g_spawn_async_with_pipes (NULL, argv, NULL,
+				       G_SPAWN_DO_NOT_REAP_CHILD,
+				       NULL, NULL, &pid,
+				       NULL, &out, NULL,
+				       &error);
+	g_free (argv[2]);
+
+	if (!ok) {
+		printf ("Could not run xmlrpc-test: %s\n", error->message);
+		errors++;
+		return;
+	}
+
+	g_child_watch_add (pid, xmlrpc_test_exited, NULL);
+	child_out = g_io_channel_unix_new (out);
+	g_io_add_watch (child_out, G_IO_IN | G_IO_ERR | G_IO_HUP,
+			xmlrpc_test_print, NULL);
+	g_io_channel_unref (child_out);
+}
+
+gboolean run_tests = TRUE;
+
+static GOptionEntry no_test_entry[] = {
+        { "no-tests", 'n', G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_REVERSE,
+          G_OPTION_ARG_NONE, &run_tests,
+          "Don't run tests, just run the test server", NULL },
+        { NULL }
+};
+
+int
+main (int argc, char **argv)
+{
+	SoupServer *server;
+	SoupURI *uri;
+
+	test_init (argc, argv, no_test_entry);
+
+	server = soup_test_server_new (FALSE);
+	soup_server_add_handler (server, "/xmlrpc-server.php",
+				 server_callback, NULL, NULL);
+
+	loop = g_main_loop_new (NULL, TRUE);
+
+	if (run_tests) {
+		uri = soup_uri_new ("http://localhost/xmlrpc-server.php";);
+		soup_uri_set_port (uri, soup_server_get_port (server));
+		do_xmlrpc_tests (uri);
+		soup_uri_free (uri);
+	} else
+		printf ("Listening on port %d\n", soup_server_get_port (server));
+
+	g_main_loop_run (loop);
+	g_main_loop_unref (loop);
+
+	if (run_tests)
+		test_cleanup ();
+	return errors != 0;
+}

Modified: trunk/tests/xmlrpc-server.php
==============================================================================
Binary files. No diff available.

Modified: trunk/tests/xmlrpc-test.c
==============================================================================
--- trunk/tests/xmlrpc-test.c	(original)
+++ trunk/tests/xmlrpc-test.c	Sun Jan 27 19:21:30 2008
@@ -13,7 +13,8 @@
 #include "test-utils.h"
 
 SoupSession *session;
-static const char *uri = "http://localhost:47524/xmlrpc-server.php";;
+static const char *default_uri = "http://localhost:47524/xmlrpc-server.php";;
+const char *uri = NULL;
 
 static const char *const value_type[] = {
 	"BAD",
@@ -51,13 +52,6 @@
 				  body, strlen (body));
 	soup_session_send_message (session, msg);
 
-	if (debug_level >= 3) {
-		debug_printf (3, "\n%s\n%d %s\n%s\n",
-			      msg->request_body->data,
-			      msg->status_code, msg->reason_phrase,
-			      msg->response_body->data);
-	}
-
 	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
 		debug_printf (1, "ERROR: %d %s\n", msg->status_code,
 			      msg->reason_phrase);
@@ -231,9 +225,7 @@
 	GValue retval;
 	gboolean ok;
 
-	debug_printf (1, "dateChange (struct of time and ints -> time): ");
-
-	structval = soup_value_hash_new ();
+	debug_printf (1, "dateChange (date, struct of ints -> time): ");
 
 	date = soup_date_new (1970 + (rand () % 50),
 			      1 + rand () % 12,
@@ -241,54 +233,55 @@
 			      rand () % 24,
 			      rand () % 60,
 			      rand () % 60);
-	soup_value_hash_insert (structval, "date", SOUP_TYPE_DATE, date);
-
 	if (debug_level >= 2) {
 		timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
-		debug_printf (2, "{ date: %s", timestamp);
+		debug_printf (2, "date: %s, {", timestamp);
 		g_free (timestamp);
 	}
 
+	structval = soup_value_hash_new ();
+
 	if (rand () % 3) {
 		date->year = 1970 + (rand () % 50);
-		debug_printf (2, ", tm_year: %d", date->year - 1900);
+		debug_printf (2, "tm_year: %d, ", date->year - 1900);
 		soup_value_hash_insert (structval, "tm_year",
 					G_TYPE_INT, date->year - 1900);
 	}
 	if (rand () % 3) {
 		date->month = 1 + rand () % 12;
-		debug_printf (2, ", tm_mon: %d", date->month - 1);
+		debug_printf (2, "tm_mon: %d, ", date->month - 1);
 		soup_value_hash_insert (structval, "tm_mon",
 					G_TYPE_INT, date->month - 1);
 	}
 	if (rand () % 3) {
 		date->day = 1 + rand () % 28;
-		debug_printf (2, ", tm_mday: %d", date->day);
+		debug_printf (2, "tm_mday: %d, ", date->day);
 		soup_value_hash_insert (structval, "tm_mday",
 					G_TYPE_INT, date->day);
 	}
 	if (rand () % 3) {
 		date->hour = rand () % 24;
-		debug_printf (2, ", tm_hour: %d", date->hour);
+		debug_printf (2, "tm_hour: %d, ", date->hour);
 		soup_value_hash_insert (structval, "tm_hour",
 					G_TYPE_INT, date->hour);
 	}
 	if (rand () % 3) {
 		date->minute = rand () % 60;
-		debug_printf (2, ", tm_min: %d", date->minute);
+		debug_printf (2, "tm_min: %d, ", date->minute);
 		soup_value_hash_insert (structval, "tm_min",
 					G_TYPE_INT, date->minute);
 	}
 	if (rand () % 3) {
 		date->second = rand () % 60;
-		debug_printf (2, ", tm_sec: %d", date->second);
+		debug_printf (2, "tm_sec: %d, ", date->second);
 		soup_value_hash_insert (structval, "tm_sec",
 					G_TYPE_INT, date->second);
 	}
 
-	debug_printf (2, " } -> ");
+	debug_printf (2, "} -> ");
 
 	ok = (do_xmlrpc ("dateChange", &retval,
+			 SOUP_TYPE_DATE, date,
 			 G_TYPE_HASH_TABLE, structval,
 			 G_TYPE_INVALID) &&
 	      check_xmlrpc (&retval, SOUP_TYPE_DATE, &result));
@@ -377,11 +370,82 @@
 	return TRUE;
 }
 
+static gboolean
+do_bad_xmlrpc (const char *body)
+{
+	SoupMessage *msg;
+	GError *err = NULL;
+	GValue retval;
+
+	msg = soup_message_new ("POST", uri);
+	soup_message_set_request (msg, "text/xml", SOUP_MEMORY_COPY,
+				  body, strlen (body));
+	soup_session_send_message (session, msg);
+
+	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+		debug_printf (1, "ERROR: %d %s\n", msg->status_code,
+			      msg->reason_phrase);
+		g_object_unref (msg);
+		return FALSE;
+	}
+
+	if (!soup_xmlrpc_parse_method_response (msg->response_body->data,
+						msg->response_body->length,
+						&retval, &err)) {
+		if (err) {
+			debug_printf (1, "FAULT: %d %s (OK!)\n",
+				      err->code, err->message);
+			g_error_free (err);
+			g_object_unref (msg);
+			return TRUE;
+		} else
+			debug_printf (1, "ERROR: could not parse response\n");
+	} else
+		debug_printf (1, "Unexpectedly got successful response!\n");
+
+	g_object_unref (msg);
+	return FALSE;
+}
+
+static gboolean
+test_fault_malformed (void)
+{
+	debug_printf (1, "malformed request: ");
+
+	return do_bad_xmlrpc ("<methodCall/>");
+}
+
+static gboolean
+test_fault_method (void)
+{
+	debug_printf (1, "request to non-existent method: ");
+
+	return do_bad_xmlrpc ("<methodCall><methodName>no_such_method</methodName><params><param><value><int>1</int></value></param></params></methodCall>");
+}
+
+static gboolean
+test_fault_args (void)
+{
+	debug_printf (1, "request with invalid args: ");
+
+	return do_bad_xmlrpc ("<methodCall><methodName>sum</methodName><params><param><value><int>1</int></value></param></params></methodCall>");
+}
+
+static GOptionEntry uri_entry[] = {
+        { "uri", 'u', 0, G_OPTION_ARG_STRING, &uri,
+          "Alternate URI for server", NULL },
+        { NULL }
+};
+
 int
 main (int argc, char **argv)
 {
-	test_init (argc, argv, NULL);
-	apache_init ();
+	test_init (argc, argv, uri_entry);
+
+	if (!uri) {
+		apache_init ();
+		uri = default_uri;
+	}
 
 	srand (time (NULL));
 
@@ -397,10 +461,16 @@
 		errors++;
 	if (!test_echo ())
 		errors++;
+	if (!test_fault_malformed ())
+		errors++;
+	if (!test_fault_method ())
+		errors++;
+	if (!test_fault_args ())
+		errors++;
 
 	soup_session_abort (session);
 	g_object_unref (session);
 
 	test_cleanup ();
-	return errors = 0;
+	return errors != 0;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]