1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2001-2003, Ximian, Inc.
4 */
5
6 #include "test-utils.h"
7
8 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
9 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
10 #endif
11
12 static SoupSession *session;
13 static const char *default_uri = "http://127.0.0.1:47524/xmlrpc-server.php";
14 static const char *uri = NULL;
15 static gboolean server_test = FALSE;
16
17 #ifdef HAVE_PHP_XMLRPC
18 #define SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER
19 #else
20 #define SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER \
21 G_STMT_START { \
22 if (!server_test) { \
23 g_test_skip ("php-xmlrpc is not available"); \
24 return; \
25 } \
26 } G_STMT_END
27 #endif
28
29 static gboolean
send_xmlrpc(const char * body,GValue * retval)30 send_xmlrpc (const char *body, GValue *retval)
31 {
32 SoupMessage *msg;
33 GError *err = NULL;
34
35 msg = soup_message_new ("POST", uri);
36 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_COPY,
37 body, strlen (body));
38 soup_session_send_message (session, msg);
39
40 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
41
42 if (!soup_xmlrpc_parse_method_response (msg->response_body->data,
43 msg->response_body->length,
44 retval, &err)) {
45 if (err) {
46 soup_test_assert (FALSE, "FAULT: %d %s\n", err->code, err->message);
47 g_error_free (err);
48 } else
49 soup_test_assert (FALSE, "ERROR: could not parse response\n");
50 g_object_unref (msg);
51 return FALSE;
52 }
53 g_object_unref (msg);
54
55 return TRUE;
56 }
57
58 static gboolean
do_xmlrpc(const char * method,GValue * retval,...)59 do_xmlrpc (const char *method, GValue *retval, ...)
60 {
61 va_list args;
62 GValueArray *params;
63 char *body;
64 gboolean ret;
65
66 va_start (args, retval);
67 params = soup_value_array_from_args (args);
68 va_end (args);
69
70 body = soup_xmlrpc_build_method_call (method, params->values,
71 params->n_values);
72 g_value_array_free (params);
73 if (!body)
74 return FALSE;
75
76 ret = send_xmlrpc (body, retval);
77 g_free (body);
78
79 return ret;
80 }
81
82 static gboolean
check_xmlrpc(GValue * value,GType type,...)83 check_xmlrpc (GValue *value, GType type, ...)
84 {
85 va_list args;
86
87 if (!G_VALUE_HOLDS (value, type)) {
88 g_assert_true (G_VALUE_HOLDS (value, type));
89 return FALSE;
90 }
91
92 va_start (args, type);
93 SOUP_VALUE_GETV (value, type, args);
94 va_end (args);
95 return TRUE;
96 }
97
98 static void
test_sum(void)99 test_sum (void)
100 {
101 GValueArray *dbls;
102 int i;
103 double val, sum, result;
104 GValue retval;
105 gboolean ok;
106
107 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
108
109 debug_printf (2, "sum (array of double -> double): ");
110
111 dbls = g_value_array_new (10);
112 for (i = sum = 0; i < 10; i++) {
113 val = g_random_int_range (0, 400) / 4.0;
114 debug_printf (2, "%s%.2f", i == 0 ? "[" : ", ", val);
115 soup_value_array_append (dbls, G_TYPE_DOUBLE, val);
116 sum += val;
117 }
118 debug_printf (2, "] -> ");
119
120 ok = (do_xmlrpc ("sum", &retval,
121 G_TYPE_VALUE_ARRAY, dbls,
122 G_TYPE_INVALID) &&
123 check_xmlrpc (&retval, G_TYPE_DOUBLE, &result));
124 g_value_array_free (dbls);
125
126 if (!ok)
127 return;
128
129 debug_printf (2, "%.2f\n", result);
130 g_assert_cmpfloat (result, ==, sum);
131 }
132
133 static void
test_countBools(void)134 test_countBools (void)
135 {
136 GValueArray *bools;
137 int i, trues, falses;
138 GValue retval;
139 int ret_trues, ret_falses;
140 gboolean val, ok;
141 GHashTable *result;
142
143 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
144
145 debug_printf (2, "countBools (array of boolean -> struct of ints): ");
146
147 bools = g_value_array_new (10);
148 for (i = trues = falses = 0; i < 10; i++) {
149 val = g_random_boolean ();
150 debug_printf (2, "%s%c", i == 0 ? "[" : ", ", val ? 'T' : 'F');
151 soup_value_array_append (bools, G_TYPE_BOOLEAN, val);
152 if (val)
153 trues++;
154 else
155 falses++;
156 }
157 debug_printf (2, "] -> ");
158
159 ok = (do_xmlrpc ("countBools", &retval,
160 G_TYPE_VALUE_ARRAY, bools,
161 G_TYPE_INVALID) &&
162 check_xmlrpc (&retval, G_TYPE_HASH_TABLE, &result));
163 g_value_array_free (bools);
164 if (!ok)
165 return;
166
167 g_assert_true (soup_value_hash_lookup (result, "true", G_TYPE_INT, &ret_trues));
168 g_assert_true (soup_value_hash_lookup (result, "false", G_TYPE_INT, &ret_falses));
169
170 g_hash_table_destroy (result);
171
172 debug_printf (2, "{ true: %d, false: %d }\n", ret_trues, ret_falses);
173 g_assert_cmpint (trues, ==, ret_trues);
174 g_assert_cmpint (falses, ==, ret_falses);
175 }
176
177 static void
test_md5sum(void)178 test_md5sum (void)
179 {
180 GByteArray *data, *result;
181 int i;
182 GChecksum *checksum;
183 guchar digest[16];
184 gsize digest_len = sizeof (digest);
185 GValue retval;
186 gboolean ok;
187
188 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
189
190 debug_printf (2, "md5sum (base64 -> base64)\n");
191
192 data = g_byte_array_new ();
193 g_byte_array_set_size (data, 256);
194 for (i = 0; i < data->len; i++)
195 data->data[i] = (char)(g_random_int_range (0, 256));
196
197 checksum = g_checksum_new (G_CHECKSUM_MD5);
198 g_checksum_update (checksum, data->data, data->len);
199 g_checksum_get_digest (checksum, digest, &digest_len);
200 g_checksum_free (checksum);
201
202 ok = (do_xmlrpc ("md5sum", &retval,
203 SOUP_TYPE_BYTE_ARRAY, data,
204 G_TYPE_INVALID) &&
205 check_xmlrpc (&retval, SOUP_TYPE_BYTE_ARRAY, &result));
206 g_byte_array_free (data, TRUE);
207 if (!ok)
208 return;
209
210 soup_assert_cmpmem (result->data, result->len,
211 digest, digest_len);
212 g_byte_array_free (result, TRUE);
213 }
214
215 static void
test_dateChange(void)216 test_dateChange (void)
217 {
218 GHashTable *structval;
219 SoupDate *date, *result;
220 char *timestamp;
221 GValue retval;
222 gboolean ok;
223
224 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
225
226 debug_printf (2, "dateChange (date, struct of ints -> time)\n");
227
228 date = soup_date_new (1970 + (g_random_int_range (0, 50)),
229 1 + g_random_int_range (0, 12),
230 1 + g_random_int_range (0, 28),
231 g_random_int_range (0, 24),
232 g_random_int_range (0, 60),
233 g_random_int_range (0, 60));
234 if (debug_level >= 2) {
235 timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
236 debug_printf (2, "date: %s, {", timestamp);
237 g_free (timestamp);
238 }
239
240 structval = soup_value_hash_new ();
241
242 #define MAYBE (g_random_int_range (0, 3) != 0)
243
244 if (MAYBE) {
245 date->year = 1970 + (g_random_int_range (0, 50));
246 debug_printf (2, "tm_year: %d, ", date->year - 1900);
247 soup_value_hash_insert (structval, "tm_year",
248 G_TYPE_INT, date->year - 1900);
249 }
250 if (MAYBE) {
251 date->month = 1 + g_random_int_range (0, 12);
252 debug_printf (2, "tm_mon: %d, ", date->month - 1);
253 soup_value_hash_insert (structval, "tm_mon",
254 G_TYPE_INT, date->month - 1);
255 }
256 if (MAYBE) {
257 date->day = 1 + g_random_int_range (0, 28);
258 debug_printf (2, "tm_mday: %d, ", date->day);
259 soup_value_hash_insert (structval, "tm_mday",
260 G_TYPE_INT, date->day);
261 }
262 if (MAYBE) {
263 date->hour = g_random_int_range (0, 24);
264 debug_printf (2, "tm_hour: %d, ", date->hour);
265 soup_value_hash_insert (structval, "tm_hour",
266 G_TYPE_INT, date->hour);
267 }
268 if (MAYBE) {
269 date->minute = g_random_int_range (0, 60);
270 debug_printf (2, "tm_min: %d, ", date->minute);
271 soup_value_hash_insert (structval, "tm_min",
272 G_TYPE_INT, date->minute);
273 }
274 if (MAYBE) {
275 date->second = g_random_int_range (0, 60);
276 debug_printf (2, "tm_sec: %d, ", date->second);
277 soup_value_hash_insert (structval, "tm_sec",
278 G_TYPE_INT, date->second);
279 }
280
281 debug_printf (2, "} -> ");
282
283 ok = (do_xmlrpc ("dateChange", &retval,
284 SOUP_TYPE_DATE, date,
285 G_TYPE_HASH_TABLE, structval,
286 G_TYPE_INVALID) &&
287 check_xmlrpc (&retval, SOUP_TYPE_DATE, &result));
288 g_hash_table_destroy (structval);
289 if (!ok) {
290 soup_date_free (date);
291 return;
292 }
293
294 if (debug_level >= 2) {
295 timestamp = soup_date_to_string (result, SOUP_DATE_ISO8601_XMLRPC);
296 debug_printf (2, "%s\n", timestamp);
297 g_free (timestamp);
298 }
299
300 g_assert_cmpint (date->year, ==, result->year);
301 g_assert_cmpint (date->month, ==, result->month);
302 g_assert_cmpint (date->day, ==, result->day);
303 g_assert_cmpint (date->hour, ==, result->hour);
304 g_assert_cmpint (date->minute, ==, result->minute);
305 g_assert_cmpint (date->second, ==, result->second);
306
307 soup_date_free (date);
308 soup_date_free (result);
309 }
310
311 static const char *const echo_strings[] = {
312 "This is a test",
313 "& so is this",
314 "and so is <this>",
315 "& so is <this>"
316 };
317 #define N_ECHO_STRINGS G_N_ELEMENTS (echo_strings)
318
319 static void
test_echo(void)320 test_echo (void)
321 {
322 GValueArray *originals, *echoes;
323 GValue retval;
324 int i;
325
326 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
327
328 debug_printf (2, "echo (array of string -> array of string):\n");
329
330 originals = g_value_array_new (N_ECHO_STRINGS);
331 for (i = 0; i < N_ECHO_STRINGS; i++) {
332 soup_value_array_append (originals, G_TYPE_STRING, echo_strings[i]);
333 debug_printf (2, "%s\"%s\"", i == 0 ? "[" : ", ", echo_strings[i]);
334 }
335 debug_printf (2, "] -> ");
336
337 if (!(do_xmlrpc ("echo", &retval,
338 G_TYPE_VALUE_ARRAY, originals,
339 G_TYPE_INVALID) &&
340 check_xmlrpc (&retval, G_TYPE_VALUE_ARRAY, &echoes))) {
341 g_value_array_free (originals);
342 return;
343 }
344 g_value_array_free (originals);
345
346 if (debug_level >= 2) {
347 for (i = 0; i < echoes->n_values; i++) {
348 debug_printf (2, "%s\"%s\"", i == 0 ? "[" : ", ",
349 g_value_get_string (&echoes->values[i]));
350 }
351 debug_printf (2, "]\n");
352 }
353
354 g_assert_cmpint (echoes->n_values, ==, N_ECHO_STRINGS);
355
356 for (i = 0; i < echoes->n_values; i++)
357 g_assert_cmpstr (echo_strings[i], ==, g_value_get_string (&echoes->values[i]));
358
359 g_value_array_free (echoes);
360 }
361
362 static void
test_ping(gconstpointer include_params)363 test_ping (gconstpointer include_params)
364 {
365 GValueArray *params;
366 GValue retval;
367 char *request;
368 char *out;
369 gboolean ret;
370
371 g_test_bug ("671661");
372
373 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
374
375 debug_printf (2, "ping (void (%s) -> string)\n",
376 include_params ? "empty <params>" : "no <params>");
377
378 params = soup_value_array_new ();
379 request = soup_xmlrpc_build_method_call ("ping", params->values,
380 params->n_values);
381 g_value_array_free (params);
382 if (!request)
383 return;
384
385 if (!include_params) {
386 char *params, *end;
387
388 params = strstr (request, "<params/>");
389 if (!params) {
390 soup_test_assert (FALSE, "ERROR: XML did not contain <params/>!");
391 return;
392 }
393 end = params + strlen ("<params/>");
394 memmove (params, end, strlen (end) + 1);
395 }
396
397 ret = send_xmlrpc (request, &retval);
398 g_free (request);
399
400 if (!ret || !check_xmlrpc (&retval, G_TYPE_STRING, &out))
401 return;
402
403 g_assert_cmpstr (out, ==, "pong");
404
405 g_free (out);
406 }
407
408 static void
do_bad_xmlrpc(const char * body)409 do_bad_xmlrpc (const char *body)
410 {
411 SoupMessage *msg;
412 GError *err = NULL;
413 GValue retval;
414
415 msg = soup_message_new ("POST", uri);
416 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_COPY,
417 body, strlen (body));
418 soup_session_send_message (session, msg);
419
420 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
421
422 if (!soup_xmlrpc_parse_method_response (msg->response_body->data,
423 msg->response_body->length,
424 &retval, &err)) {
425 if (err) {
426 debug_printf (1, "FAULT: %d %s (OK!)\n",
427 err->code, err->message);
428 g_error_free (err);
429 g_object_unref (msg);
430 return;
431 } else
432 soup_test_assert (FALSE, "ERROR: could not parse response\n");
433 } else
434 soup_test_assert (FALSE, "Unexpectedly got successful response!\n");
435
436 g_object_unref (msg);
437 }
438
439 static void
test_fault_malformed(void)440 test_fault_malformed (void)
441 {
442 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
443
444 do_bad_xmlrpc ("<methodCall/>");
445 }
446
447 static void
test_fault_method(void)448 test_fault_method (void)
449 {
450 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
451
452 do_bad_xmlrpc ("<methodCall><methodName>no_such_method</methodName><params><param><value><int>1</int></value></param></params></methodCall>");
453 }
454
455 static void
test_fault_args(void)456 test_fault_args (void)
457 {
458 SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER;
459
460 do_bad_xmlrpc ("<methodCall><methodName>sum</methodName><params><param><value><int>1</int></value></param></params></methodCall>");
461 }
462
463 static GOptionEntry xmlrpc_entries[] = {
464 { "uri", 'U', 0, G_OPTION_ARG_STRING, &uri,
465 "Alternate URI for server", NULL },
466 { "server-test", 'S', 0, G_OPTION_ARG_NONE, &server_test,
467 "If this is being run from xmlrpc-old-server-test", NULL },
468 { NULL }
469 };
470
471 int
main(int argc,char ** argv)472 main (int argc, char **argv)
473 {
474 int ret;
475
476 test_init (argc, argv, xmlrpc_entries);
477
478 if (!uri && !server_test) {
479 apache_init ();
480 uri = default_uri;
481 }
482
483 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
484
485 g_test_add_func ("/xmlrpc-old/sum", test_sum);
486 g_test_add_func ("/xmlrpc-old/countBools", test_countBools);
487 g_test_add_func ("/xmlrpc-old/md5sum", test_md5sum);
488 g_test_add_func ("/xmlrpc-old/dateChange", test_dateChange);
489 g_test_add_func ("/xmlrpc-old/echo", test_echo);
490 g_test_add_data_func ("/xmlrpc-old/ping/empty-params", GINT_TO_POINTER (TRUE), test_ping);
491 g_test_add_data_func ("/xmlrpc-old/ping/no-params", GINT_TO_POINTER (FALSE), test_ping);
492 g_test_add_func ("/xmlrpc-old/fault/malformed", test_fault_malformed);
493 g_test_add_func ("/xmlrpc-old/fault/method", test_fault_method);
494 g_test_add_func ("/xmlrpc-old/fault/args", test_fault_args);
495
496 ret = g_test_run ();
497
498 soup_test_session_abort_unref (session);
499
500 test_cleanup ();
501 return ret;
502 }
503