initial load of upstream version 1.06.32
[xmlrpc-c] / src / test / method_registry.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "casprintf.h"
5 #include "girstring.h"
6
7 #include "xmlrpc_config.h"
8
9 #include "xmlrpc-c/base.h"
10 #include "xmlrpc-c/server.h"
11
12 #include "test.h"
13 #include "xml_data.h"
14 #include "method_registry.h"
15
16
17 #define FOO_USER_DATA ((void*) 0xF00)
18 #define BAR_USER_DATA ((void*) 0xBAF)
19
20
21
22 static xmlrpc_value *
23 test_foo(xmlrpc_env *   const envP,
24          xmlrpc_value * const paramArrayP,
25          void *         const userData) {
26
27     xmlrpc_int32 x, y;
28
29     TEST_NO_FAULT(envP);
30     TEST(paramArrayP != NULL);
31     TEST(userData == FOO_USER_DATA);
32
33     xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y);
34     TEST_NO_FAULT(envP);
35     TEST(x == 25);
36     TEST(y == 17);
37
38     return xmlrpc_build_value(envP, "i", (xmlrpc_int32) x + y);
39 }
40
41
42
43 static xmlrpc_value *
44 test_bar(xmlrpc_env *   const envP,
45          xmlrpc_value * const paramArrayP,
46          void *         const userData) {
47
48     xmlrpc_int32 x, y;
49
50     TEST_NO_FAULT(envP);
51     TEST(paramArrayP != NULL);
52     TEST(userData == BAR_USER_DATA);
53
54     xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y);
55     TEST_NO_FAULT(envP);
56     TEST(x == 25);
57     TEST(y == 17);
58
59     xmlrpc_env_set_fault(envP, 123, "Test fault");
60
61     return NULL;
62 }
63
64
65
66 static xmlrpc_value *
67 test_default(xmlrpc_env *   const envP,
68              const char *   const host ATTR_UNUSED,
69              const char *   const methodName ATTR_UNUSED,
70              xmlrpc_value * const paramArrayP,
71              void *         const userData) {
72
73     xmlrpc_int32 x, y;
74
75     TEST_NO_FAULT(envP);
76     TEST(paramArrayP != NULL);
77     TEST(userData == FOO_USER_DATA);
78
79     xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y);
80     TEST_NO_FAULT(envP);
81     TEST(x == 25);
82     TEST(y == 17);
83
84     return xmlrpc_build_value(envP, "i", 2 * (x + y));
85 }
86
87
88
89 static void
90 doRpc(xmlrpc_env *      const envP,
91       xmlrpc_registry * const registryP,
92       const char *      const methodName,
93       xmlrpc_value *    const argArrayP,
94       xmlrpc_value **   const resultPP) {
95 /*----------------------------------------------------------------------------
96    Do what an XML-RPC server would do -- pass an XML call to the registry
97    and get XML back.
98
99    Actually to our caller, we look more like an Xmlrpc-c client.  We're
100    both the client and the server all bound together.
101 -----------------------------------------------------------------------------*/
102     xmlrpc_mem_block * callP;
103     xmlrpc_mem_block * responseP;
104
105     /* Build a call, and tell the registry to handle it. */
106     callP = xmlrpc_mem_block_new(envP, 0);
107     TEST_NO_FAULT(envP);
108     xmlrpc_serialize_call(envP, callP, methodName, argArrayP);
109     TEST_NO_FAULT(envP);
110     responseP = xmlrpc_registry_process_call(envP, registryP, NULL,
111                                              xmlrpc_mem_block_contents(callP),
112                                              xmlrpc_mem_block_size(callP));
113     TEST_NO_FAULT(envP);
114     TEST(responseP != NULL);
115
116     /* Parse the response. */
117     *resultPP = xmlrpc_parse_response(envP,
118                                       xmlrpc_mem_block_contents(responseP),
119                                       xmlrpc_mem_block_size(responseP));
120
121     xmlrpc_mem_block_free(callP);
122     xmlrpc_mem_block_free(responseP);
123 }
124
125
126
127 static const char * const validSigString[] = {
128     "i:",
129     "s:d",
130     "i:bds86SA",
131     "i:,i:",
132     "i:dd,s:,A:A",
133     "i:,",
134     "b:i,",
135     "b:i,b:,",
136     NULL
137 };
138
139 static const char * const invalidSigString[] = {
140     "",
141     "i",
142     "q",
143     "i:q",
144     "i:ddq",
145     ",",
146     ",i:",
147     "i,",
148     "b:i,,b:i",
149     "ii:",
150     "ii:ii",
151     NULL
152 };
153
154
155 static void
156 test_signature_method(xmlrpc_registry * const registryP) {
157 /*----------------------------------------------------------------------------
158    Test system.methodSignature system method.
159 -----------------------------------------------------------------------------*/
160     xmlrpc_env env;
161     xmlrpc_value * argArrayP;
162     xmlrpc_value * resultP;
163     const char * type0;
164     const char * type1;
165     const char * type2;
166     const char * type3;
167     const char * type4;
168     const char * type5;
169     const char * type6;
170     const char * type7;
171     const char * nosigstring;
172
173     xmlrpc_env_init(&env);
174
175     argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosuchmethod");
176     doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP);
177     TEST_FAULT(&env, XMLRPC_NO_SUCH_METHOD_ERROR);
178     xmlrpc_DECREF(argArrayP);
179
180     argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosig0");
181
182     doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP);
183     TEST_NO_FAULT(&env);
184
185     xmlrpc_read_string(&env, resultP, &nosigstring);
186     TEST_NO_FAULT(&env);
187     
188     TEST(streq(nosigstring, "undef"));
189     strfree(nosigstring);
190     xmlrpc_DECREF(resultP);
191     xmlrpc_DECREF(argArrayP);
192
193     argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig0");
194     doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP);
195     TEST_NO_FAULT(&env);
196
197     xmlrpc_decompose_value(&env, resultP, "((s))", &type0);
198     TEST_NO_FAULT(&env);
199     TEST(streq(type0, "int"));
200     strfree(type0);
201     xmlrpc_DECREF(resultP);
202     xmlrpc_DECREF(argArrayP);
203
204     argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig2");
205     doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP);
206     TEST_NO_FAULT(&env);
207     xmlrpc_decompose_value(&env, resultP, "((ssssssss))",
208                            &type0, &type1, &type2, &type3,
209                            &type4, &type5, &type6, &type7);
210     TEST_NO_FAULT(&env);
211     TEST(streq(type0, "int"));
212     TEST(streq(type1, "boolean"));
213     TEST(streq(type2, "double"));
214     TEST(streq(type3, "string"));
215     TEST(streq(type4, "dateTime.iso8601"));
216     TEST(streq(type5, "base64"));
217     TEST(streq(type6, "struct"));
218     TEST(streq(type7, "array"));
219     strfree(type0); strfree(type1); strfree(type2); strfree(type3);
220     strfree(type4); strfree(type5); strfree(type6); strfree(type7);
221     xmlrpc_DECREF(resultP);
222     xmlrpc_DECREF(argArrayP);
223
224     argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig3");
225     doRpc(&env, registryP, "system.methodSignature", argArrayP, &resultP);
226     TEST_NO_FAULT(&env);
227     xmlrpc_decompose_value(&env, resultP, "((s)(s))", &type0, &type1);
228
229     TEST_NO_FAULT(&env);
230     TEST(streq(type0, "int"));
231     TEST(streq(type1, "int"));
232     xmlrpc_DECREF(resultP);
233     xmlrpc_DECREF(argArrayP);
234
235     xmlrpc_env_clean(&env);
236 }
237
238
239
240 static void
241 test_signature(void) {
242
243     xmlrpc_env env;
244     xmlrpc_registry * registryP;
245     uint i;
246
247     xmlrpc_env_init(&env);
248
249     printf("  Running signature tests.");
250
251     registryP = xmlrpc_registry_new(&env);
252     TEST_NO_FAULT(&env);
253
254     xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, "test.nosig0",
255                                      test_foo, FOO_USER_DATA,
256                                      NULL, NULL);
257     TEST_NO_FAULT(&env);
258
259     xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, "test.nosig1",
260                                      test_foo, FOO_USER_DATA,
261                                      "?", NULL);
262     TEST_NO_FAULT(&env);
263
264     for (i = 0; validSigString[i]; ++i) {
265         const char * methodName;
266         casprintf(&methodName, "test.validsig%u", i);
267         xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, methodName,
268                                          test_foo, FOO_USER_DATA,
269                                          validSigString[i], NULL);
270         TEST_NO_FAULT(&env);
271         strfree(methodName);
272     }
273
274     for (i = 0; invalidSigString[i]; ++i) {
275         const char * methodName;
276         casprintf(&methodName, "test.invalidsig%u", i);
277         xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, methodName,
278                                          test_foo, FOO_USER_DATA,
279                                          invalidSigString[i], NULL);
280         TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR);
281         strfree(methodName);
282     }
283
284     test_signature_method(registryP);
285
286     xmlrpc_registry_free(registryP);
287
288     xmlrpc_env_clean(&env);
289
290     printf("\n");
291 }
292
293
294
295 static void
296 test_system_multicall(xmlrpc_registry * const registryP) {
297 /*----------------------------------------------------------------------------
298    Test system.multicall
299 -----------------------------------------------------------------------------*/
300     xmlrpc_env env;
301     xmlrpc_value * multiP;
302     xmlrpc_int32 foo1_result, foo2_result;
303     xmlrpc_int32 bar_code, nosuch_code, multi_code, bogus1_code, bogus2_code;
304     char *bar_string, *nosuch_string, *multi_string;
305     char *bogus1_string, *bogus2_string;
306     xmlrpc_value * valueP;
307     xmlrpc_value * argArrayP;
308
309     xmlrpc_env_init(&env);
310
311     printf("  Running multicall tests.");
312
313     /* Build an argument array for our calls. */
314     argArrayP = xmlrpc_build_value(&env, "(ii)",
315                                    (xmlrpc_int32) 25, (xmlrpc_int32) 17); 
316     TEST_NO_FAULT(&env);
317
318     multiP = xmlrpc_build_value(&env,
319                                "(({s:s,s:V}{s:s,s:V}{s:s,s:V}"
320                                "{s:s,s:()}s{}{s:s,s:V}))",
321                                "methodName", "test.foo",
322                                "params", argArrayP,
323                                "methodName", "test.bar",
324                                "params", argArrayP,
325                                "methodName", "test.nosuch",
326                                "params", argArrayP,
327                                "methodName", "system.multicall",
328                                "params",
329                                "bogus_entry",
330                                "methodName", "test.foo",
331                                "params", argArrayP);
332     TEST_NO_FAULT(&env);    
333     doRpc(&env, registryP, "system.multicall", multiP, &valueP);
334     TEST_NO_FAULT(&env);
335     xmlrpc_decompose_value(&env, valueP,
336                            "((i){s:i,s:s,*}{s:i,s:s,*}"
337                            "{s:i,s:s,*}{s:i,s:s,*}{s:i,s:s,*}(i))",
338                            &foo1_result,
339                            "faultCode", &bar_code,
340                            "faultString", &bar_string,
341                            "faultCode", &nosuch_code,
342                            "faultString", &nosuch_string,
343                            "faultCode", &multi_code,
344                            "faultString", &multi_string,
345                            "faultCode", &bogus1_code,
346                            "faultString", &bogus1_string,
347                            "faultCode", &bogus2_code,
348                            "faultString", &bogus2_string,
349                            &foo2_result);
350     xmlrpc_DECREF(valueP);
351     TEST_NO_FAULT(&env);    
352     TEST(foo1_result == 42);
353     TEST(bar_code == 123);
354     TEST(strcmp(bar_string, "Test fault") == 0);
355     TEST(nosuch_code == XMLRPC_NO_SUCH_METHOD_ERROR);
356     TEST(multi_code == XMLRPC_REQUEST_REFUSED_ERROR);
357     TEST(foo2_result == 42);
358     xmlrpc_DECREF(multiP);
359     free(bar_string);
360     free(nosuch_string);
361     free(multi_string);
362     free(bogus1_string);
363     free(bogus2_string);
364     
365     xmlrpc_DECREF(argArrayP);
366
367     xmlrpc_env_clean(&env);
368
369     printf("\n");
370 }
371
372
373
374 static void
375 testCall(xmlrpc_registry * const registryP) {
376
377     xmlrpc_env env;
378     xmlrpc_env env2;
379     xmlrpc_value * argArrayP;
380     xmlrpc_value * valueP;
381     xmlrpc_int32 i;
382
383     printf("  Running call tests.");
384
385     xmlrpc_env_init(&env);
386
387     /* Build an argument array for our calls. */
388     argArrayP = xmlrpc_build_value(&env, "(ii)",
389                                    (xmlrpc_int32) 25, (xmlrpc_int32) 17); 
390     TEST_NO_FAULT(&env);
391
392     /* Call test.foo and check the result. */
393     doRpc(&env, registryP, "test.foo", argArrayP, &valueP);
394     TEST_NO_FAULT(&env);
395     TEST(valueP != NULL);
396     xmlrpc_decompose_value(&env, valueP, "i", &i);
397     xmlrpc_DECREF(valueP);
398     TEST_NO_FAULT(&env);
399     TEST(i == 42);
400
401     /* Call test.bar and check the result. */
402     xmlrpc_env_init(&env2);
403     doRpc(&env2, registryP, "test.bar", argArrayP, &valueP);
404     TEST(env2.fault_occurred);
405     TEST(env2.fault_code == 123);
406     TEST(env2.fault_string && strcmp(env2.fault_string, "Test fault") == 0);
407     xmlrpc_env_clean(&env2);
408
409     /* Call a non-existant method and check the result. */
410     xmlrpc_env_init(&env2);
411     doRpc(&env2, registryP, "test.nosuch", argArrayP, &valueP);
412     TEST(valueP == NULL);
413     TEST_FAULT(&env2, XMLRPC_NO_SUCH_METHOD_ERROR);
414     xmlrpc_env_clean(&env2);
415
416     xmlrpc_DECREF(argArrayP);
417
418     xmlrpc_env_clean(&env);
419
420     printf("\n");
421 }
422
423
424
425 static void
426 testDefaultMethod(xmlrpc_registry * const registryP) {
427     
428     xmlrpc_env env;
429     xmlrpc_value * argArrayP;
430     xmlrpc_value * valueP;
431     xmlrpc_int32 i;
432  
433     xmlrpc_env_init(&env);
434
435     printf("  Running default method tests.");
436
437     /* Build an argument array for our calls. */
438     argArrayP = xmlrpc_build_value(&env, "(ii)",
439                                    (xmlrpc_int32) 25, (xmlrpc_int32) 17); 
440
441     xmlrpc_registry_set_default_method(&env, registryP, &test_default,
442                                        FOO_USER_DATA);
443     TEST_NO_FAULT(&env);
444     doRpc(&env, registryP, "test.nosuch", argArrayP, &valueP);
445     TEST_NO_FAULT(&env);
446     TEST(valueP != NULL);
447     xmlrpc_decompose_value(&env, valueP, "i", &i);
448     xmlrpc_DECREF(valueP);
449     TEST_NO_FAULT(&env);
450     TEST(i == 84);
451
452     /* Change the default method. */
453     xmlrpc_registry_set_default_method(&env, registryP, &test_default,
454                                        BAR_USER_DATA);
455     TEST_NO_FAULT(&env);
456
457     xmlrpc_DECREF(argArrayP);
458
459     xmlrpc_env_clean(&env);
460
461     printf("\n");
462 }
463
464
465
466 void
467 test_method_registry(void) {
468
469     xmlrpc_env env, env2;
470     xmlrpc_value * valueP;
471     xmlrpc_registry *registryP;
472     xmlrpc_mem_block *response;
473
474     xmlrpc_env_init(&env);
475
476     printf("Running method registry tests.");
477
478     /* Create a new registry. */
479     registryP = xmlrpc_registry_new(&env);
480     TEST_NO_FAULT(&env);
481     TEST(registryP != NULL);
482
483     /* Add some test methods. */
484     xmlrpc_registry_add_method(&env, registryP, NULL, "test.foo",
485                                test_foo, FOO_USER_DATA);
486     TEST_NO_FAULT(&env);
487     xmlrpc_registry_add_method(&env, registryP, NULL, "test.bar",
488                                test_bar, BAR_USER_DATA);
489     TEST_NO_FAULT(&env);
490
491     printf("\n");
492     testCall(registryP);
493
494     test_system_multicall(registryP);
495
496     /* PASS bogus XML data and make sure our parser pukes gracefully.
497     ** (Because of the way the code is laid out, and the presence of other
498     ** test suites, this lets us skip tests for invalid XML-RPC data.) */
499     xmlrpc_env_init(&env2);
500     response = xmlrpc_registry_process_call(&env, registryP, NULL,
501                                             expat_error_data,
502                                             strlen(expat_error_data));
503     TEST_NO_FAULT(&env);
504     TEST(response != NULL);
505     valueP = xmlrpc_parse_response(&env2, xmlrpc_mem_block_contents(response),
506                                   xmlrpc_mem_block_size(response));
507     TEST(valueP == NULL);
508     TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
509     xmlrpc_mem_block_free(response);
510     xmlrpc_env_clean(&env2);
511
512     printf("\n");
513     testDefaultMethod(registryP);
514
515     test_signature();
516     
517     /* Test cleanup code (w/memprof). */
518     xmlrpc_registry_free(registryP);
519
520     printf("\n");
521
522     xmlrpc_env_clean(&env);
523 }
524