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