Require glib 2.31 and update to new thread APIs
[platform/upstream/libsoup.git] / tests / xmlrpc-server-test.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Red Hat, Inc.
4  */
5
6 #include "config.h"
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <sys/wait.h>
11
12 #include <libsoup/soup.h>
13
14 #include "test-utils.h"
15
16 GMainLoop *loop;
17
18 static void
19 type_error (SoupMessage *msg, GType expected, GValueArray *params, int bad_value)
20 {
21         soup_xmlrpc_set_fault (msg,
22                                SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS,
23                                "Bad parameter #%d: expected %s, got %s",
24                                bad_value + 1, g_type_name (expected),
25                                g_type_name (G_VALUE_TYPE (&params->values[bad_value])));
26 }
27
28 static void
29 args_error (SoupMessage *msg, GValueArray *params, int expected)
30 {
31         soup_xmlrpc_set_fault (msg,
32                                SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS,
33                                "Wrong number of parameters: expected %d, got %d",
34                                expected, params->n_values);
35 }
36
37 static void
38 do_sum (SoupMessage *msg, GValueArray *params)
39 {
40         int sum = 0, i, val;
41         GValueArray *nums;
42
43         if (params->n_values != 1) {
44                 args_error (msg, params, 1);
45                 return;
46         }
47         if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &nums)) {
48                 type_error (msg, G_TYPE_VALUE_ARRAY, params, 0);
49                 return;
50         }
51
52         for (i = 0; i < nums->n_values; i++) {
53                 if (!soup_value_array_get_nth (nums, i, G_TYPE_INT, &val)) {
54                         type_error (msg, G_TYPE_INT, nums, i);
55                         return;
56                 }
57                 sum += val;
58         }
59
60         soup_xmlrpc_set_response (msg, G_TYPE_INT, sum);
61
62 }
63
64 static void
65 do_countBools (SoupMessage *msg, GValueArray *params)
66 {
67         int i, trues = 0, falses = 0;
68         GValueArray *bools;
69         GHashTable *ret = soup_value_hash_new ();
70         gboolean val;
71
72         if (params->n_values != 1) {
73                 args_error (msg, params, 1);
74                 return;
75         }
76         if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &bools)) {
77                 type_error (msg, G_TYPE_VALUE_ARRAY, params, 0);
78                 return;
79         }
80
81         for (i = 0; i < bools->n_values; i++) {
82                 if (!soup_value_array_get_nth (bools, i, G_TYPE_BOOLEAN, &val)) {
83                         type_error (msg, G_TYPE_BOOLEAN, params, i);
84                         return;
85                 }
86                 if (val)
87                         trues++;
88                 else
89                         falses++;
90         }
91
92         soup_value_hash_insert (ret, "true", G_TYPE_INT, trues);
93         soup_value_hash_insert (ret, "false", G_TYPE_INT, falses);
94         soup_xmlrpc_set_response (msg, G_TYPE_HASH_TABLE, ret);
95         g_hash_table_destroy (ret);
96
97 }
98
99 static void
100 do_md5sum (SoupMessage *msg, GValueArray *params)
101 {
102         GChecksum *checksum;
103         GByteArray *data, *digest;
104         gsize digest_len = 16;
105
106         if (params->n_values != 1) {
107                 args_error (msg, params, 1);
108                 return;
109         }
110
111         if (!soup_value_array_get_nth (params, 0, SOUP_TYPE_BYTE_ARRAY, &data)) {
112                 type_error (msg, SOUP_TYPE_BYTE_ARRAY, params, 0);
113                 return;
114         }
115         checksum = g_checksum_new (G_CHECKSUM_MD5);
116         g_checksum_update (checksum, data->data, data->len);
117         digest = g_byte_array_new ();
118         g_byte_array_set_size (digest, digest_len);
119         g_checksum_get_digest (checksum, digest->data, &digest_len);
120         g_checksum_free (checksum);
121
122         soup_xmlrpc_set_response (msg, SOUP_TYPE_BYTE_ARRAY, digest);
123         g_byte_array_free (digest, TRUE);
124 }
125
126
127 static void
128 do_dateChange (SoupMessage *msg, GValueArray *params)
129 {
130         GHashTable *arg;
131         SoupDate *date;
132         int val;
133
134         if (params->n_values != 2) {
135                 args_error (msg, params, 2);
136                 return;
137         }
138
139         if (!soup_value_array_get_nth (params, 0, SOUP_TYPE_DATE, &date)) {
140                 type_error (msg, SOUP_TYPE_DATE, params, 0);
141                 return;
142         }
143         if (!soup_value_array_get_nth (params, 1, G_TYPE_HASH_TABLE, &arg)) {
144                 type_error (msg, G_TYPE_HASH_TABLE, params, 1);
145                 return;
146         }
147
148         if (soup_value_hash_lookup (arg, "tm_year", G_TYPE_INT, &val))
149                 date->year = val + 1900;
150         if (soup_value_hash_lookup (arg, "tm_mon", G_TYPE_INT, &val))
151                 date->month = val + 1;
152         if (soup_value_hash_lookup (arg, "tm_mday", G_TYPE_INT, &val))
153                 date->day = val;
154         if (soup_value_hash_lookup (arg, "tm_hour", G_TYPE_INT, &val))
155                 date->hour = val;
156         if (soup_value_hash_lookup (arg, "tm_min", G_TYPE_INT, &val))
157                 date->minute = val;
158         if (soup_value_hash_lookup (arg, "tm_sec", G_TYPE_INT, &val))
159                 date->second = val;
160
161         soup_xmlrpc_set_response (msg, SOUP_TYPE_DATE, date);
162 }
163
164 static void
165 do_echo (SoupMessage *msg, GValueArray *params)
166 {
167         int i;
168         const char *val;
169         GValueArray *in, *out;
170
171         if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &in)) {
172                 type_error (msg, G_TYPE_VALUE_ARRAY, params, 0);
173                 return;
174         }
175
176         out = g_value_array_new (in->n_values);
177         for (i = 0; i < in->n_values; i++) {
178                 if (!soup_value_array_get_nth (in, i, G_TYPE_STRING, &val)) {
179                         type_error (msg, G_TYPE_STRING, in, i);
180                         return;
181                 }
182                 soup_value_array_append (out, G_TYPE_STRING, val);
183         }
184
185         soup_xmlrpc_set_response (msg, G_TYPE_VALUE_ARRAY, out);
186         g_value_array_free (out);
187
188 }
189
190 static void
191 server_callback (SoupServer *server, SoupMessage *msg,
192                  const char *path, GHashTable *query,
193                  SoupClientContext *context, gpointer data)
194 {
195         char *method_name;
196         GValueArray *params;
197
198         if (msg->method != SOUP_METHOD_POST) {
199                 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
200                 return;
201         }
202
203         soup_message_set_status (msg, SOUP_STATUS_OK);
204
205         if (!soup_xmlrpc_parse_method_call (msg->request_body->data,
206                                             msg->request_body->length,
207                                             &method_name, &params)) {
208                 soup_xmlrpc_set_fault (msg, SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED,
209                                        "Could not parse method call");
210                 return;
211         }
212
213         if (!strcmp (method_name, "sum"))
214                 do_sum (msg, params);
215         else if (!strcmp (method_name, "countBools"))
216                 do_countBools (msg, params);
217         else if (!strcmp (method_name, "md5sum"))
218                 do_md5sum (msg, params);
219         else if (!strcmp (method_name, "dateChange"))
220                 do_dateChange (msg, params);
221         else if (!strcmp (method_name, "echo"))
222                 do_echo (msg, params);
223         else {
224                 soup_xmlrpc_set_fault (msg, SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND,
225                                        "Unknown method %s", method_name);
226         }
227
228         g_free (method_name);
229         g_value_array_free (params);
230 }
231
232 static void
233 xmlrpc_test_exited (GPid pid, int status, gpointer data)
234 {
235         errors = WIFEXITED (status) ? WEXITSTATUS (status) : 1;
236         g_main_loop_quit (loop);
237 }
238
239 static gboolean
240 xmlrpc_test_print (GIOChannel *io, GIOCondition cond, gpointer data)
241 {
242         char *line;
243         gsize len;
244         GIOStatus status;
245
246         if (!(cond & G_IO_IN))
247                 return FALSE;
248
249         status = g_io_channel_read_line (io, &line, &len, NULL, NULL);
250         if (status == G_IO_STATUS_NORMAL) {
251                 /* Don't print the exit status, just the debug stuff */
252                 if (strncmp (line, "xmlrpc-test:", strlen ("xmlrpc-test:")) != 0)
253                         printf ("%s", line);
254                 g_free (line);
255                 return TRUE;
256         } else if (status == G_IO_STATUS_AGAIN)
257                 return TRUE;
258         else
259                 return FALSE;
260 }
261
262 static void
263 do_xmlrpc_tests (SoupURI *uri)
264 {
265         char *argv[8];
266         int arg, out;
267         gboolean ok;
268         GPid pid;
269         GError *error = NULL;
270         GIOChannel *child_out;
271
272         argv[0] = "./xmlrpc-test";
273         argv[1] = "-s";
274         argv[2] = "-u";
275         argv[3] = soup_uri_to_string (uri, FALSE);
276
277         for (arg = 0; arg < debug_level && arg < 3; arg++)
278                 argv[arg + 4] = "-d";
279         argv[arg + 4] = NULL;
280
281         ok = g_spawn_async_with_pipes (NULL, argv, NULL,
282                                        G_SPAWN_DO_NOT_REAP_CHILD,
283                                        NULL, NULL, &pid,
284                                        NULL, &out, NULL,
285                                        &error);
286         g_free (argv[3]);
287
288         if (!ok) {
289                 printf ("Could not run xmlrpc-test: %s\n", error->message);
290                 errors++;
291                 return;
292         }
293
294         g_child_watch_add (pid, xmlrpc_test_exited, NULL);
295         child_out = g_io_channel_unix_new (out);
296         g_io_add_watch (child_out, G_IO_IN | G_IO_ERR | G_IO_HUP,
297                         xmlrpc_test_print, NULL);
298         g_io_channel_unref (child_out);
299 }
300
301 gboolean run_tests = TRUE;
302
303 static GOptionEntry no_test_entry[] = {
304         { "no-tests", 'n', G_OPTION_FLAG_REVERSE,
305           G_OPTION_ARG_NONE, &run_tests,
306           "Don't run tests, just run the test server", NULL },
307         { NULL }
308 };
309
310 int
311 main (int argc, char **argv)
312 {
313         SoupServer *server;
314         SoupURI *uri;
315
316         test_init (argc, argv, no_test_entry);
317
318         server = soup_test_server_new (FALSE);
319         soup_server_add_handler (server, "/xmlrpc-server.php",
320                                  server_callback, NULL, NULL);
321
322         loop = g_main_loop_new (NULL, TRUE);
323
324         if (run_tests) {
325                 uri = soup_uri_new ("http://127.0.0.1/xmlrpc-server.php");
326                 soup_uri_set_port (uri, soup_server_get_port (server));
327                 do_xmlrpc_tests (uri);
328                 soup_uri_free (uri);
329         } else
330                 printf ("Listening on port %d\n", soup_server_get_port (server));
331
332         g_main_loop_run (loop);
333         g_main_loop_unref (loop);
334
335         soup_test_server_quit_unref (server);
336         if (run_tests)
337                 test_cleanup ();
338         return errors != 0;
339 }