From 4b67cc60b82756a86225a2a2268f538f552bf9b2 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 19 Jun 2006 16:57:47 +0000 Subject: [PATCH] add tests for apache mod_php5 and xmlrpc-epi-php * configure.in: add tests for apache mod_php5 and xmlrpc-epi-php * tests/xmlrpc-test.c: XML-RPC regression test * tests/xmlrpc-server.php: PHP server for xmlrpc-test * tests/httpd.conf.in: add php stuff * tests/apache-wrapper.c (apache_cleanup): Use "graceful-stop" rather than "stop", so that it stops listening on the socket before exiting, so that we can immediately start another apache (eg, in "make check"). * libsoup/soup-date.c (soup_mktime_utc): Fix a bug in leap-year counting. * libsoup/soup-xmlrpc-message.c (soup_xmlrpc_message_write_datetime): rename from "..._write_time", to make it consistent with the XML-RPC type name and the corresponding SoupXmlrpcResponse method. Also, fix it to use the same ISO 8601 format as the spec, and use the right value for the seconds field. (soup_xmlrpc_message_write_base64): Change the buf arg to a gconstpointer rather than a const char *. * libsoup/soup-xmlrpc-response.c (soup_xmlrpc_value_get_base64): Return a GByteArray containing the decoded data, rather than the base64-encoded string. (soup_xmlrpc_value_dump_internal): Update for that (and don't leak it). (soup_xmlrpc_value_array_get_iterator, soup_xmlrpc_value_array_iterator_get_value): Make these actually work. --- ChangeLog | 36 ++++ configure.in | 26 +++ libsoup/soup-date.c | 2 +- libsoup/soup-xmlrpc-message.c | 6 +- libsoup/soup-xmlrpc-message.h | 66 +++--- libsoup/soup-xmlrpc-response.c | 47 +++-- libsoup/soup-xmlrpc-response.h | 2 +- tests/.cvsignore | 1 + tests/Makefile.am | 12 +- tests/apache-wrapper.c | 2 +- tests/httpd.conf.in | 6 + tests/xmlrpc-server.php | 75 +++++++ tests/xmlrpc-test.c | 457 +++++++++++++++++++++++++++++++++++++++++ 13 files changed, 676 insertions(+), 62 deletions(-) create mode 100644 tests/xmlrpc-server.php create mode 100644 tests/xmlrpc-test.c diff --git a/ChangeLog b/ChangeLog index 1423e26..c93debc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2006-06-14 Dan Winship + + * configure.in: add tests for apache mod_php5 and xmlrpc-epi-php + + * tests/xmlrpc-test.c: XML-RPC regression test + + * tests/xmlrpc-server.php: PHP server for xmlrpc-test + + * tests/httpd.conf.in: add php stuff + + * tests/apache-wrapper.c (apache_cleanup): Use "graceful-stop" + rather than "stop", so that it stops listening on the socket + before exiting, so that we can immediately start another apache + (eg, in "make check"). + + * libsoup/soup-date.c (soup_mktime_utc): Fix a bug in leap-year + counting. + + * libsoup/soup-xmlrpc-message.c + (soup_xmlrpc_message_write_datetime): rename from + "..._write_time", to make it consistent with the XML-RPC type name + and the corresponding SoupXmlrpcResponse method. Also, fix it to + use the same ISO 8601 format as the spec, and use the right value + for the seconds field. + (soup_xmlrpc_message_write_base64): Change the buf arg to a + gconstpointer rather than a const char *. + + * libsoup/soup-xmlrpc-response.c (soup_xmlrpc_value_get_base64): + Return a GByteArray containing the decoded data, rather than + the base64-encoded string. + (soup_xmlrpc_value_dump_internal): Update for that (and don't + leak it). + (soup_xmlrpc_value_array_get_iterator, + soup_xmlrpc_value_array_iterator_get_value): Make these actually + work. + 2006-06-12 Dan Winship * configure.in: 2.2.94 diff --git a/configure.in b/configure.in index 9ae01f0..4bf8f4a 100644 --- a/configure.in +++ b/configure.in @@ -256,6 +256,32 @@ else fi AM_CONDITIONAL(HAVE_APACHE, test $have_apache = 1) +if test "$have_apache" = 1; then + AC_MSG_CHECKING([for mod_php5]) + if test -f $APACHE_MODULE_DIR/mod_php5.so; then + have_php=yes + IF_HAVE_PHP="" + else + have_php=no + IF_HAVE_PHP="#" + fi + AC_MSG_RESULT($have_php) + + if test "$have_php" = yes; then + AC_MSG_CHECKING([for xmlrpc-epi-php]) + if php5 --rf xmlrpc_server_create | grep -q "does not exist"; then + have_xmlrpc_epi_php=no + else + have_xmlrpc_epi_php=yes + fi + AC_MSG_RESULT($have_xmlrpc_epi_php) + fi +fi + +AC_SUBST(IF_HAVE_PHP) +AM_CONDITIONAL(HAVE_XMLRPC_EPI_PHP, test $have_xmlrpc_epi_php = yes) + + dnl ************************* dnl *** Output Everything *** dnl ************************* diff --git a/libsoup/soup-date.c b/libsoup/soup-date.c index 3085ae6..90c37d8 100644 --- a/libsoup/soup-date.c +++ b/libsoup/soup-date.c @@ -68,7 +68,7 @@ soup_mktime_utc (struct tm *tm) tt = (tm->tm_year - 70) * 365; tt += (tm->tm_year - 68) / 4; tt += days_before[tm->tm_mon] + tm->tm_mday - 1; - if (tm->tm_year % 4 == 2 && tm->tm_mon < 2) + if (tm->tm_year % 4 == 0 && tm->tm_mon < 2) tt--; tt = ((((tt * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec; return tt; diff --git a/libsoup/soup-xmlrpc-message.c b/libsoup/soup-xmlrpc-message.c index 4f37999..d061282 100644 --- a/libsoup/soup-xmlrpc-message.c +++ b/libsoup/soup-xmlrpc-message.c @@ -202,7 +202,7 @@ soup_xmlrpc_message_write_double (SoupXmlrpcMessage *msg, double d) } void -soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, const time_t timeval) +soup_xmlrpc_message_write_datetime (SoupXmlrpcMessage *msg, const time_t timeval) { SoupXmlrpcMessagePrivate *priv; struct tm time; @@ -212,7 +212,7 @@ soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, const time_t timeval) priv = SOUP_XMLRPC_MESSAGE_GET_PRIVATE (msg); soup_gmtime (&timeval, &time); - strftime (str, 128, "%Y%m%dT%H%M%s", &time); + strftime (str, 128, "%Y%m%dT%H:%M:%S", &time); priv->last_node = xmlNewChild (priv->last_node, NULL, (xmlChar *)"value", NULL); xmlNewTextChild (priv->last_node, NULL, (xmlChar *)"dateTime.iso8601", (xmlChar *)str); @@ -220,7 +220,7 @@ soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, const time_t timeval) } void -soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg, const char *buf, int len) +soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg, gconstpointer buf, int len) { SoupXmlrpcMessagePrivate *priv; char *str; diff --git a/libsoup/soup-xmlrpc-message.h b/libsoup/soup-xmlrpc-message.h index a86b2a6..f74c405 100644 --- a/libsoup/soup-xmlrpc-message.h +++ b/libsoup/soup-xmlrpc-message.h @@ -36,39 +36,39 @@ GType soup_xmlrpc_message_get_type (void); SoupXmlrpcMessage *soup_xmlrpc_message_new (const char *uri_string); SoupXmlrpcMessage *soup_xmlrpc_message_new_from_uri (const SoupUri *uri); -void soup_xmlrpc_message_start_call (SoupXmlrpcMessage *msg, - const char *method_name); -void soup_xmlrpc_message_end_call (SoupXmlrpcMessage *msg); - -void soup_xmlrpc_message_start_param (SoupXmlrpcMessage *msg); -void soup_xmlrpc_message_end_param (SoupXmlrpcMessage *msg); - -void soup_xmlrpc_message_write_int (SoupXmlrpcMessage *msg, - long i); -void soup_xmlrpc_message_write_boolean (SoupXmlrpcMessage *msg, - gboolean b); -void soup_xmlrpc_message_write_string (SoupXmlrpcMessage *msg, - const char *str); -void soup_xmlrpc_message_write_double (SoupXmlrpcMessage *msg, - double d); -void soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, - const time_t timeval); -void soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg, - const char *buf, - int len); - -void soup_xmlrpc_message_start_struct (SoupXmlrpcMessage *msg); -void soup_xmlrpc_message_end_struct (SoupXmlrpcMessage *msg); - -void soup_xmlrpc_message_start_member (SoupXmlrpcMessage *msg, - const char *name); -void soup_xmlrpc_message_end_member (SoupXmlrpcMessage *msg); - -void soup_xmlrpc_message_start_array (SoupXmlrpcMessage *msg); -void soup_xmlrpc_message_end_array (SoupXmlrpcMessage *msg); - -xmlChar *soup_xmlrpc_message_to_string (SoupXmlrpcMessage *msg); -void soup_xmlrpc_message_persist (SoupXmlrpcMessage *msg); +void soup_xmlrpc_message_start_call (SoupXmlrpcMessage *msg, + const char *method_name); +void soup_xmlrpc_message_end_call (SoupXmlrpcMessage *msg); + +void soup_xmlrpc_message_start_param (SoupXmlrpcMessage *msg); +void soup_xmlrpc_message_end_param (SoupXmlrpcMessage *msg); + +void soup_xmlrpc_message_write_int (SoupXmlrpcMessage *msg, + long i); +void soup_xmlrpc_message_write_boolean (SoupXmlrpcMessage *msg, + gboolean b); +void soup_xmlrpc_message_write_string (SoupXmlrpcMessage *msg, + const char *str); +void soup_xmlrpc_message_write_double (SoupXmlrpcMessage *msg, + double d); +void soup_xmlrpc_message_write_datetime (SoupXmlrpcMessage *msg, + const time_t timeval); +void soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg, + gconstpointer buf, + int len); + +void soup_xmlrpc_message_start_struct (SoupXmlrpcMessage *msg); +void soup_xmlrpc_message_end_struct (SoupXmlrpcMessage *msg); + +void soup_xmlrpc_message_start_member (SoupXmlrpcMessage *msg, + const char *name); +void soup_xmlrpc_message_end_member (SoupXmlrpcMessage *msg); + +void soup_xmlrpc_message_start_array (SoupXmlrpcMessage *msg); +void soup_xmlrpc_message_end_array (SoupXmlrpcMessage *msg); + +xmlChar *soup_xmlrpc_message_to_string (SoupXmlrpcMessage *msg); +void soup_xmlrpc_message_persist (SoupXmlrpcMessage *msg); SoupXmlrpcResponse *soup_xmlrpc_message_parse_response (SoupXmlrpcMessage *msg); diff --git a/libsoup/soup-xmlrpc-response.c b/libsoup/soup-xmlrpc-response.c index 8153b42..ab7abeb 100644 --- a/libsoup/soup-xmlrpc-response.c +++ b/libsoup/soup-xmlrpc-response.c @@ -356,12 +356,13 @@ soup_xmlrpc_value_get_datetime (SoupXmlrpcValue *value, time_t *timeval) return TRUE; } -/* FIXME: this is broken; it returns the encoded value, not decoded */ gboolean -soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, char **buf) +soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, GByteArray **data) { xmlNode *xml; xmlChar *content; + char *decoded; + int len; xml = (xmlNode *) value; if (strcmp ((char *)xml->name, "value")) @@ -371,9 +372,13 @@ soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, char **buf) return FALSE; content = xmlNodeGetContent (xml); - *buf = content ? g_strdup ((char *)content) : g_strdup (""); + decoded = soup_base64_decode ((const char *)content, &len); xmlFree (content); + *data = g_byte_array_new (); + g_byte_array_append (*data, (guchar *)decoded, len); + g_free (decoded); + return TRUE; } @@ -443,11 +448,13 @@ soup_xmlrpc_value_array_get_iterator (SoupXmlrpcValue *value, SoupXmlrpcValueArr xml = (xmlNode *) value; - if (!xml->children || strcmp((char *)xml->children->name, "data") == 0 || xml->children->next) + if (!xml->children || strcmp((char *)xml->children->name, "array") != 0 || + xml->children->next || !xml->children->children || + strcmp((char *)xml->children->children->name, "data") != 0 || + xml->children->children->next) return FALSE; - *iter = (SoupXmlrpcValueArrayIterator *) xml->children; - + *iter = (SoupXmlrpcValueArrayIterator *) xml->children->children->children; return TRUE; } @@ -476,17 +483,7 @@ gboolean soup_xmlrpc_value_array_iterator_get_value (SoupXmlrpcValueArrayIterator *iter, SoupXmlrpcValue **value) { - xmlNode *xml; - - xml = (xmlNode *) iter; - - if (!xml || strcmp((char *)xml->name, "data")) - return FALSE; - xml = exactly_one_child (xml); - if (!xml) - return FALSE; - - *value = (SoupXmlrpcValue *) xml; + *value = (SoupXmlrpcValue *) iter; return TRUE; } @@ -525,6 +522,7 @@ soup_xmlrpc_value_dump_internal (SoupXmlrpcValue *value, int d) char *str; double f; time_t timeval; + GByteArray *base64; GHashTable *hash; SoupXmlrpcValueArrayIterator *iter; @@ -580,10 +578,19 @@ soup_xmlrpc_value_dump_internal (SoupXmlrpcValue *value, int d) case SOUP_XMLRPC_VALUE_TYPE_BASE64: indent (d); - if (!soup_xmlrpc_value_get_base64 (value, &str)) + if (!soup_xmlrpc_value_get_base64 (value, &base64)) g_printerr ("BAD BASE64\n"); - else - g_printerr ("BASE64: %s\n", str); + else { + GString *hex = g_string_new (NULL); + int i; + + for (i = 0; i < base64->len; i++) + g_string_append_printf (hex, "%02x", base64->data[i]); + + g_printerr ("BASE64: %s\n", hex->str); + g_string_free (hex, TRUE); + g_byte_array_free (base64, TRUE); + } break; diff --git a/libsoup/soup-xmlrpc-response.h b/libsoup/soup-xmlrpc-response.h index 10c2dd7..f2207c7 100644 --- a/libsoup/soup-xmlrpc-response.h +++ b/libsoup/soup-xmlrpc-response.h @@ -65,7 +65,7 @@ gboolean soup_xmlrpc_value_get_string (SoupXmlrpcValue *value, gboolean soup_xmlrpc_value_get_datetime (SoupXmlrpcValue *value, time_t *timeval); gboolean soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, - char **buf); + GByteArray **data); gboolean soup_xmlrpc_value_get_struct (SoupXmlrpcValue *value, GHashTable **table); diff --git a/tests/.cvsignore b/tests/.cvsignore index 35b83c6..e1166ad 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -12,3 +12,4 @@ revserver simple-httpd simple-proxy uri-parsing +xmlrpc-test diff --git a/tests/Makefile.am b/tests/Makefile.am index 8d05c13..41313bf 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,7 +15,8 @@ noinst_PROGRAMS = \ revserver \ simple-httpd \ simple-proxy \ - uri-parsing + uri-parsing \ + xmlrpc-test auth_test_SOURCES = auth-test.c apache-wrapper.c apache-wrapper.h date_SOURCES = date.c @@ -27,12 +28,16 @@ revserver_SOURCES = revserver.c simple_httpd_SOURCES = simple-httpd.c simple_proxy_SOURCES = simple-proxy.c uri_parsing_SOURCES = uri-parsing.c +xmlrpc_test_SOURCES = xmlrpc-test.c apache-wrapper.c apache-wrapper.h if HAVE_APACHE APACHE_TESTS = auth-test endif +if HAVE_XMLRPC_EPI_PHP +XMLRPC_TESTS = xmlrpc-test +endif -TESTS = date uri-parsing $(APACHE_TESTS) +TESTS = date uri-parsing $(APACHE_TESTS) $(XMLRPC_TESTS) EXTRA_DIST = \ libsoup.supp \ @@ -40,4 +45,5 @@ EXTRA_DIST = \ test-key.pem \ htdigest \ htpasswd \ - httpd.conf.in + httpd.conf.in \ + xmlrpc-server.php diff --git a/tests/apache-wrapper.c b/tests/apache-wrapper.c index 2f5cd8c..5c50735 100644 --- a/tests/apache-wrapper.c +++ b/tests/apache-wrapper.c @@ -46,7 +46,7 @@ apache_init (void) void apache_cleanup (void) { - apache_cmd ("stop"); + apache_cmd ("graceful-stop"); } #endif /* HAVE_APACHE */ diff --git a/tests/httpd.conf.in b/tests/httpd.conf.in index eee3a52..80899ac 100644 --- a/tests/httpd.conf.in +++ b/tests/httpd.conf.in @@ -4,6 +4,9 @@ ServerName 127.0.0.1 Listen 127.0.0.1:47524 PidFile @builddir@/httpd.pid +DocumentRoot @srcdir@ + +# Change this to "./error.log" if it's failing and you don't know why ErrorLog /dev/null LoadModule alias_module @APACHE_MODULE_DIR@/mod_alias.so @@ -12,8 +15,11 @@ LoadModule auth_digest_module @APACHE_MODULE_DIR@/mod_auth_digest.so LoadModule authn_file_module @APACHE_MODULE_DIR@/mod_authn_file.so LoadModule authz_user_module @APACHE_MODULE_DIR@/mod_authz_user.so LoadModule dir_module @APACHE_MODULE_DIR@/mod_dir.so +LoadModule mime_module @APACHE_MODULE_DIR@/mod_mime.so +@IF_HAVE_PHP@LoadModule php5_module @APACHE_MODULE_DIR@/mod_php5.so DirectoryIndex httpd.pid +AddType application/x-httpd-php .php Alias /Basic/realm1/realm2/realm1 @builddir@ Alias /Basic/realm1/realm2 @builddir@ diff --git a/tests/xmlrpc-server.php b/tests/xmlrpc-server.php new file mode 100644 index 0000000..cf20948 --- /dev/null +++ b/tests/xmlrpc-server.php @@ -0,0 +1,75 @@ +scalar, true); + xmlrpc_set_type ($val, "base64"); + return $val; +} + +function dateChange ($method_name, $params, $app_data) +{ + $date_str = $params[0]["date"]->scalar; + $date = strptime ($date_str, "%Y%m%dT%H:%M:%S"); + + foreach ($params[0] as $name => $val) { + if ($name == "date") + continue; + $date[$name] = $val; + } + + $ret = sprintf ("%04d%02d%02dT%02d:%02d:%02d", + $date["tm_year"] + 1900, $date["tm_mon"] + 1, + $date["tm_mday"], $date["tm_hour"], + $date["tm_min"], $date["tm_sec"]); + xmlrpc_set_type ($ret, "datetime"); + return $ret; +} + +function echo_ ($method_name, $params, $app_data) +{ + return $params[0]; +} + +# Work around xmlrpc-epi-php lossage; otherwise the datetime values +# we return will sometimes get a DST adjustment we don't want. +putenv ("TZ="); + +$xmlrpc_server = xmlrpc_server_create (); +xmlrpc_server_register_method($xmlrpc_server, "sum", "sum"); +xmlrpc_server_register_method($xmlrpc_server, "countBools", "countBools"); +xmlrpc_server_register_method($xmlrpc_server, "md5sum", "md5sum"); +xmlrpc_server_register_method($xmlrpc_server, "dateChange", "dateChange"); +xmlrpc_server_register_method($xmlrpc_server, "echo", "echo_"); + +$response = xmlrpc_server_call_method ($xmlrpc_server, $HTTP_RAW_POST_DATA, + 0, array ("output_type" => "xml")); +echo ($response); + +xmlrpc_server_destroy ($xmlrpc_server); + +?> diff --git a/tests/xmlrpc-test.c b/tests/xmlrpc-test.c new file mode 100644 index 0000000..2a80f06 --- /dev/null +++ b/tests/xmlrpc-test.c @@ -0,0 +1,457 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2001-2003, Ximian, Inc. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "apache-wrapper.h" + +SoupSession *session; +static const char *uri = "http://localhost:47524/xmlrpc-server.php"; +int debug; + +static const char *const value_type[] = { + "BAD", + "int", + "boolean", + "string", + "double", + "datetime", + "base64", + "struct", + "array" +}; + +static SoupXmlrpcValue * +do_xmlrpc (SoupXmlrpcMessage *xmsg, SoupXmlrpcValueType type) +{ + SoupMessage *msg = SOUP_MESSAGE (xmsg); + SoupXmlrpcResponse *response; + SoupXmlrpcValue *value; + int status; + + soup_xmlrpc_message_persist (xmsg); + status = soup_session_send_message (session, msg); + + if (debug > 1) { + printf ("\n%.*s\n%d %s\n%.*s\n", + msg->request.length, msg->request.body, + msg->status_code, msg->reason_phrase, + msg->response.length, msg->response.body); + } + + if (!SOUP_STATUS_IS_SUCCESSFUL (status)) { + printf ("ERROR: %d %s\n", status, msg->reason_phrase); + return FALSE; + } + + response = soup_xmlrpc_message_parse_response (xmsg); + if (!response || soup_xmlrpc_response_is_fault (response)) { + if (!response) + printf ("ERROR: no response\n"); + else + printf ("ERROR: fault\n"); + return FALSE; + } + + value = soup_xmlrpc_response_get_value (response); + if (!value) { + printf ("ERROR: no value?\n"); + return NULL; + } else if (soup_xmlrpc_value_get_type (value) != type) { + printf ("ERROR: wrong value type; expected %s, got %s\n", + value_type[type], value_type[soup_xmlrpc_value_get_type (value)]); + return NULL; + } + + return value; +} + +static gboolean +test_sum (void) +{ + SoupXmlrpcMessage *msg; + SoupXmlrpcValue *value; + int i, val, sum; + long result; + + printf ("sum (array of int -> int): "); + + msg = soup_xmlrpc_message_new (uri); + soup_xmlrpc_message_start_call (msg, "sum"); + soup_xmlrpc_message_start_param (msg); + soup_xmlrpc_message_start_array (msg); + for (i = sum = 0; i < 10; i++) { + val = rand () % 100; + if (debug) + printf ("%s%d", i == 0 ? "[" : ", ", val); + soup_xmlrpc_message_write_int (msg, val); + sum += val; + } + if (debug) + printf ("] -> "); + soup_xmlrpc_message_end_array (msg); + soup_xmlrpc_message_end_param (msg); + soup_xmlrpc_message_end_call (msg); + + value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_INT); + if (!value) + return FALSE; + + if (!soup_xmlrpc_value_get_int (value, &result)) { + printf ("wrong type?\n"); + return FALSE; + } + + if (debug) + printf ("%ld: ", result); + printf ("%s\n", result == sum ? "OK!" : "WRONG!"); + return result == sum; +} + +static gboolean +test_countBools (void) +{ + SoupXmlrpcMessage *msg; + SoupXmlrpcValue *value; + int i, trues, falses; + long ret_trues, ret_falses; + gboolean val, ok; + GHashTable *result; + + printf ("countBools (array of boolean -> struct of ints): "); + + msg = soup_xmlrpc_message_new (uri); + soup_xmlrpc_message_start_call (msg, "countBools"); + soup_xmlrpc_message_start_param (msg); + soup_xmlrpc_message_start_array (msg); + for (i = trues = falses = 0; i < 10; i++) { + val = rand () > (RAND_MAX / 2); + if (debug) + printf ("%s%c", i == 0 ? "[" : ", ", val ? 'T' : 'F'); + soup_xmlrpc_message_write_boolean (msg, val); + if (val) + trues++; + else + falses++; + } + if (debug) + printf ("] -> "); + soup_xmlrpc_message_end_array (msg); + soup_xmlrpc_message_end_param (msg); + soup_xmlrpc_message_end_call (msg); + + value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_STRUCT); + if (!value) + return FALSE; + + if (!soup_xmlrpc_value_get_struct (value, &result)) { + printf ("wrong type?\n"); + return FALSE; + } + + if (!soup_xmlrpc_value_get_int (g_hash_table_lookup (result, "true"), &ret_trues)) { + printf ("NO 'true' value in response\n"); + return FALSE; + } + if (!soup_xmlrpc_value_get_int (g_hash_table_lookup (result, "false"), &ret_falses)) { + printf ("NO 'false' value in response\n"); + return FALSE; + } + + if (debug) + printf ("{ true: %ld, false: %ld } ", ret_trues, ret_falses); + ok = (trues == ret_trues) && (falses == ret_falses); + printf ("%s\n", ok ? "OK!" : "WRONG!"); + return ok; +} + +static gboolean +test_md5sum (void) +{ + SoupXmlrpcMessage *msg; + SoupXmlrpcValue *value; + GByteArray *result; + char data[512]; + int i; + SoupMD5Context md5; + guchar digest[16]; + gboolean ok; + + printf ("md5sum (base64 -> base64): "); + + msg = soup_xmlrpc_message_new (uri); + soup_xmlrpc_message_start_call (msg, "md5sum"); + soup_xmlrpc_message_start_param (msg); + for (i = 0; i < sizeof (data); i++) + data[i] = (char)(rand () & 0xFF); + soup_xmlrpc_message_write_base64 (msg, data, sizeof (data)); + soup_xmlrpc_message_end_param (msg); + soup_xmlrpc_message_end_call (msg); + + value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_BASE64); + if (!value) + return FALSE; + + if (!soup_xmlrpc_value_get_base64 (value, &result)) { + printf ("wrong type?\n"); + return FALSE; + } + + if (result->len != 16) { + printf ("result has WRONG length (%d)\n", result->len); + g_byte_array_free (result, TRUE); + return FALSE; + } + + soup_md5_init (&md5); + soup_md5_update (&md5, data, sizeof (data)); + soup_md5_final (&md5, digest); + + ok = (memcmp (digest, result->data, 16) == 0); + printf ("%s\n", ok ? "OK!" : "WRONG!"); + g_byte_array_free (result, TRUE); + return ok; +} + +static gboolean +test_dateChange (void) +{ + SoupXmlrpcMessage *msg; + SoupXmlrpcValue *value; + struct tm tm; + time_t when, result; + char timestamp[128]; + + printf ("dateChange (struct of time and ints -> time): "); + + msg = soup_xmlrpc_message_new (uri); + soup_xmlrpc_message_start_call (msg, "dateChange"); + soup_xmlrpc_message_start_param (msg); + soup_xmlrpc_message_start_struct (msg); + + soup_xmlrpc_message_start_member (msg, "date"); + memset (&tm, 0, sizeof (tm)); + tm.tm_year = 70 + (rand () % 50); + tm.tm_mon = rand () % 12; + tm.tm_mday = 1 + (rand () % 28); + tm.tm_hour = rand () % 24; + tm.tm_min = rand () % 60; + tm.tm_sec = rand () % 60; + when = soup_mktime_utc (&tm); + soup_xmlrpc_message_write_datetime (msg, when); + soup_xmlrpc_message_end_member (msg); + + if (debug) { + strftime (timestamp, sizeof (timestamp), + "%Y-%m-%dT%H:%M:%S", &tm); + printf ("{ date: %s", timestamp); + } + + if (rand () % 3) { + tm.tm_year = 70 + (rand () % 50); + if (debug) + printf (", tm_year: %d", tm.tm_year); + soup_xmlrpc_message_start_member (msg, "tm_year"); + soup_xmlrpc_message_write_int (msg, tm.tm_year); + soup_xmlrpc_message_end_member (msg); + } + if (rand () % 3) { + tm.tm_mon = rand () % 12; + if (debug) + printf (", tm_mon: %d", tm.tm_mon); + soup_xmlrpc_message_start_member (msg, "tm_mon"); + soup_xmlrpc_message_write_int (msg, tm.tm_mon); + soup_xmlrpc_message_end_member (msg); + } + if (rand () % 3) { + tm.tm_mday = 1 + (rand () % 28); + if (debug) + printf (", tm_mday: %d", tm.tm_mday); + soup_xmlrpc_message_start_member (msg, "tm_mday"); + soup_xmlrpc_message_write_int (msg, tm.tm_mday); + soup_xmlrpc_message_end_member (msg); + } + if (rand () % 3) { + tm.tm_hour = rand () % 24; + if (debug) + printf (", tm_hour: %d", tm.tm_hour); + soup_xmlrpc_message_start_member (msg, "tm_hour"); + soup_xmlrpc_message_write_int (msg, tm.tm_hour); + soup_xmlrpc_message_end_member (msg); + } + if (rand () % 3) { + tm.tm_min = rand () % 60; + if (debug) + printf (", tm_min: %d", tm.tm_min); + soup_xmlrpc_message_start_member (msg, "tm_min"); + soup_xmlrpc_message_write_int (msg, tm.tm_min); + soup_xmlrpc_message_end_member (msg); + } + if (rand () % 3) { + tm.tm_sec = rand () % 60; + if (debug) + printf (", tm_sec: %d", tm.tm_sec); + soup_xmlrpc_message_start_member (msg, "tm_sec"); + soup_xmlrpc_message_write_int (msg, tm.tm_sec); + soup_xmlrpc_message_end_member (msg); + } + when = soup_mktime_utc (&tm); + + if (debug) + printf (" } -> "); + + soup_xmlrpc_message_end_struct (msg); + soup_xmlrpc_message_end_param (msg); + soup_xmlrpc_message_end_call (msg); + + value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_DATETIME); + if (!value) + return FALSE; + + if (!soup_xmlrpc_value_get_datetime (value, &result)) { + printf ("wrong type?\n"); + return FALSE; + } + + if (debug) { + memset (&tm, 0, sizeof (tm)); + soup_gmtime (&result, &tm); + strftime (timestamp, sizeof (timestamp), + "%Y-%m-%dT%H:%M:%S", &tm); + printf ("%s: ", timestamp); + } + + printf ("%s\n", (when == result) ? "OK!" : "WRONG!"); + return (when == result); +} + +static const char *const echo_strings[] = { + "This is a test", + "& so is this", + "and so is ", + "& so is <this>" +}; +#define N_ECHO_STRINGS G_N_ELEMENTS (echo_strings) + +static gboolean +test_echo (void) +{ + SoupXmlrpcMessage *msg; + SoupXmlrpcValue *value, *elt; + SoupXmlrpcValueArrayIterator *iter; + char *echo; + int i; + + printf ("echo (array of string -> array of string): "); + + msg = soup_xmlrpc_message_new (uri); + soup_xmlrpc_message_start_call (msg, "echo"); + soup_xmlrpc_message_start_param (msg); + soup_xmlrpc_message_start_array (msg); + for (i = 0; i < N_ECHO_STRINGS; i++) { + if (debug) + printf ("%s\"%s\"", i == 0 ? "[" : ", ", echo_strings[i]); + soup_xmlrpc_message_write_string (msg, echo_strings[i]); + } + if (debug) + printf ("] -> "); + soup_xmlrpc_message_end_array (msg); + soup_xmlrpc_message_end_param (msg); + soup_xmlrpc_message_end_call (msg); + + value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_ARRAY); + if (!value) + return FALSE; + + if (!soup_xmlrpc_value_array_get_iterator (value, &iter)) { + printf ("wrong type?\n"); + return FALSE; + } + i = 0; + while (iter) { + if (!soup_xmlrpc_value_array_iterator_get_value (iter, &elt)) { + printf (" WRONG! Can't get result element %d\n", i + 1); + return FALSE; + } + if (!soup_xmlrpc_value_get_string (elt, &echo)) { + printf (" WRONG! Result element %d is not a string", i + 1); + return FALSE; + } + if (debug) + printf ("%s\"%s\"", i == 0 ? "[" : ", ", echo); + if (strcmp (echo_strings[i], echo) != 0) { + printf (" WRONG! Mismatch at %d\n", i + 1); + return FALSE; + } + + iter = soup_xmlrpc_value_array_iterator_next (iter); + i++; + } + if (debug) + printf ("] "); + + printf ("%s\n", i == N_ECHO_STRINGS ? "OK!" : "WRONG! Too few results"); + return i == N_ECHO_STRINGS; +} + +static void +usage (void) +{ + fprintf (stderr, "Usage: xmlrpc-test [-d] [-d]\n"); + exit (1); +} + +int +main (int argc, char **argv) +{ + int opt, errors = 0; + + g_type_init (); + g_thread_init (NULL); + + while ((opt = getopt (argc, argv, "d")) != -1) { + switch (opt) { + case 'd': + debug++; + break; + + case '?': + usage (); + break; + } + } + + srand (time (NULL)); + + if (!apache_init ()) { + fprintf (stderr, "Could not start apache\n"); + return 1; + } + + session = soup_session_sync_new (); + + if (!test_sum ()) + errors++; + if (!test_countBools ()) + errors++; + if (!test_md5sum ()) + errors++; + if (!test_dateChange ()) + errors++; + if (!test_echo ()) + errors++; + + apache_cleanup (); + + printf ("\n%d errors\n", errors); + return errors > 0; +} -- 2.7.4