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