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