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