Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / libevent / dist / test / regress_rpc.c
bloba177dbbf7a41ab62ca6d278fa02ed2cdc366247f
1 /* $NetBSD$ */
2 /*
3 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #ifdef WIN32
30 #include <winsock2.h>
31 #include <windows.h>
32 #endif
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #ifdef HAVE_SYS_TIME_H
41 #include <sys/time.h>
42 #endif
43 #include <sys/queue.h>
44 #ifndef WIN32
45 #include <sys/socket.h>
46 #include <signal.h>
47 #include <unistd.h>
48 #include <netdb.h>
49 #endif
50 #include <fcntl.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <errno.h>
55 #include <assert.h>
57 #include "event.h"
58 #include "evhttp.h"
59 #include "log.h"
60 #include "evrpc.h"
62 #include "regress.gen.h"
64 void rpc_suite(void);
66 extern int test_ok;
68 static struct evhttp *
69 http_setup(short *pport)
71 int i;
72 struct evhttp *myhttp;
73 short port = -1;
75 /* Try a few different ports */
76 for (i = 0; i < 50; ++i) {
77 myhttp = evhttp_start("127.0.0.1", 8080 + i);
78 if (myhttp != NULL) {
79 port = 8080 + i;
80 break;
84 if (port == -1)
85 event_errx(1, "Could not start web server");
87 *pport = port;
88 return (myhttp);
91 EVRPC_HEADER(Message, msg, kill);
92 EVRPC_HEADER(NeverReply, msg, kill);
94 EVRPC_GENERATE(Message, msg, kill);
95 EVRPC_GENERATE(NeverReply, msg, kill);
97 static int need_input_hook = 0;
98 static int need_output_hook = 0;
100 static void
101 MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
103 struct kill* kill_reply = rpc->reply;
105 if (need_input_hook) {
106 struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
107 const char *header = evhttp_find_header(
108 req->input_headers, "X-Hook");
109 assert(strcmp(header, "input") == 0);
112 /* we just want to fill in some non-sense */
113 EVTAG_ASSIGN(kill_reply, weapon, "dagger");
114 EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
116 /* no reply to the RPC */
117 EVRPC_REQUEST_DONE(rpc);
120 static EVRPC_STRUCT(NeverReply) *saved_rpc;
122 static void
123 NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
125 test_ok += 1;
126 saved_rpc = rpc;
129 static void
130 rpc_setup(struct evhttp **phttp, short *pport, struct evrpc_base **pbase)
132 short port;
133 struct evhttp *http = NULL;
134 struct evrpc_base *base = NULL;
136 http = http_setup(&port);
137 base = evrpc_init(http);
139 EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
140 EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
142 *phttp = http;
143 *pport = port;
144 *pbase = base;
146 need_input_hook = 0;
147 need_output_hook = 0;
150 static void
151 rpc_teardown(struct evrpc_base *base)
153 assert(EVRPC_UNREGISTER(base, Message) == 0);
154 assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
156 evrpc_free(base);
159 static void
160 rpc_postrequest_failure(struct evhttp_request *req, void *arg)
162 if (req->response_code != HTTP_SERVUNAVAIL) {
164 fprintf(stderr, "FAILED (response code)\n");
165 exit(1);
168 test_ok = 1;
169 event_loopexit(NULL);
173 * Test a malformed payload submitted as an RPC
176 static void
177 rpc_basic_test(void)
179 short port;
180 struct evhttp *http = NULL;
181 struct evrpc_base *base = NULL;
182 struct evhttp_connection *evcon = NULL;
183 struct evhttp_request *req = NULL;
185 fprintf(stdout, "Testing Basic RPC Support: ");
187 rpc_setup(&http, &port, &base);
189 evcon = evhttp_connection_new("127.0.0.1", port);
190 if (evcon == NULL) {
191 fprintf(stdout, "FAILED\n");
192 exit(1);
196 * At this point, we want to schedule an HTTP POST request
197 * server using our make request method.
200 req = evhttp_request_new(rpc_postrequest_failure, NULL);
201 if (req == NULL) {
202 fprintf(stdout, "FAILED\n");
203 exit(1);
206 /* Add the information that we care about */
207 evhttp_add_header(req->output_headers, "Host", "somehost");
208 evbuffer_add_printf(req->output_buffer, "Some Nonsense");
210 if (evhttp_make_request(evcon, req,
211 EVHTTP_REQ_POST,
212 "/.rpc.Message") == -1) {
213 fprintf(stdout, "FAILED\n");
214 exit(1);
217 test_ok = 0;
219 event_dispatch();
221 evhttp_connection_free(evcon);
223 rpc_teardown(base);
225 if (test_ok != 1) {
226 fprintf(stdout, "FAILED\n");
227 exit(1);
230 fprintf(stdout, "OK\n");
232 evhttp_free(http);
235 static void
236 rpc_postrequest_done(struct evhttp_request *req, void *arg)
238 struct kill* kill_reply = NULL;
240 if (req->response_code != HTTP_OK) {
242 fprintf(stderr, "FAILED (response code)\n");
243 exit(1);
246 kill_reply = kill_new();
248 if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
249 fprintf(stderr, "FAILED (unmarshal)\n");
250 exit(1);
253 kill_free(kill_reply);
255 test_ok = 1;
256 event_loopexit(NULL);
259 static void
260 rpc_basic_message(void)
262 short port;
263 struct evhttp *http = NULL;
264 struct evrpc_base *base = NULL;
265 struct evhttp_connection *evcon = NULL;
266 struct evhttp_request *req = NULL;
267 struct msg *msg;
269 fprintf(stdout, "Testing Good RPC Post: ");
271 rpc_setup(&http, &port, &base);
273 evcon = evhttp_connection_new("127.0.0.1", port);
274 if (evcon == NULL) {
275 fprintf(stdout, "FAILED\n");
276 exit(1);
280 * At this point, we want to schedule an HTTP POST request
281 * server using our make request method.
284 req = evhttp_request_new(rpc_postrequest_done, NULL);
285 if (req == NULL) {
286 fprintf(stdout, "FAILED\n");
287 exit(1);
290 /* Add the information that we care about */
291 evhttp_add_header(req->output_headers, "Host", "somehost");
293 /* set up the basic message */
294 msg = msg_new();
295 EVTAG_ASSIGN(msg, from_name, "niels");
296 EVTAG_ASSIGN(msg, to_name, "tester");
297 msg_marshal(req->output_buffer, msg);
298 msg_free(msg);
300 if (evhttp_make_request(evcon, req,
301 EVHTTP_REQ_POST,
302 "/.rpc.Message") == -1) {
303 fprintf(stdout, "FAILED\n");
304 exit(1);
307 test_ok = 0;
309 event_dispatch();
311 evhttp_connection_free(evcon);
313 rpc_teardown(base);
315 if (test_ok != 1) {
316 fprintf(stdout, "FAILED\n");
317 exit(1);
320 fprintf(stdout, "OK\n");
322 evhttp_free(http);
325 static struct evrpc_pool *
326 rpc_pool_with_connection(short port)
328 struct evhttp_connection *evcon;
329 struct evrpc_pool *pool;
331 pool = evrpc_pool_new(NULL);
332 assert(pool != NULL);
334 evcon = evhttp_connection_new("127.0.0.1", port);
335 assert(evcon != NULL);
337 evrpc_pool_add_connection(pool, evcon);
339 return (pool);
342 static void
343 GotKillCb(struct evrpc_status *status,
344 struct msg *msg, struct kill *kill, void *arg)
346 char *weapon;
347 char *action;
349 if (need_output_hook) {
350 struct evhttp_request *req = status->http_req;
351 const char *header = evhttp_find_header(
352 req->input_headers, "X-Pool-Hook");
353 assert(strcmp(header, "ran") == 0);
356 if (status->error != EVRPC_STATUS_ERR_NONE)
357 goto done;
359 if (EVTAG_GET(kill, weapon, &weapon) == -1) {
360 fprintf(stderr, "get weapon\n");
361 goto done;
363 if (EVTAG_GET(kill, action, &action) == -1) {
364 fprintf(stderr, "get action\n");
365 goto done;
368 if (strcmp(weapon, "dagger"))
369 goto done;
371 if (strcmp(action, "wave around like an idiot"))
372 goto done;
374 test_ok += 1;
376 done:
377 event_loopexit(NULL);
380 static void
381 GotKillCbTwo(struct evrpc_status *status,
382 struct msg *msg, struct kill *kill, void *arg)
384 char *weapon;
385 char *action;
387 if (status->error != EVRPC_STATUS_ERR_NONE)
388 goto done;
390 if (EVTAG_GET(kill, weapon, &weapon) == -1) {
391 fprintf(stderr, "get weapon\n");
392 goto done;
394 if (EVTAG_GET(kill, action, &action) == -1) {
395 fprintf(stderr, "get action\n");
396 goto done;
399 if (strcmp(weapon, "dagger"))
400 goto done;
402 if (strcmp(action, "wave around like an idiot"))
403 goto done;
405 test_ok += 1;
407 done:
408 if (test_ok == 2)
409 event_loopexit(NULL);
412 static int
413 rpc_hook_add_header(struct evhttp_request *req,
414 struct evbuffer *evbuf, void *arg)
416 const char *hook_type = arg;
417 if (strcmp("input", hook_type) == 0)
418 evhttp_add_header(req->input_headers, "X-Hook", hook_type);
419 else
420 evhttp_add_header(req->output_headers, "X-Hook", hook_type);
421 return (0);
424 static int
425 rpc_hook_remove_header(struct evhttp_request *req,
426 struct evbuffer *evbuf, void *arg)
428 const char *header = evhttp_find_header(req->input_headers, "X-Hook");
429 assert(header != NULL);
430 assert(strcmp(header, arg) == 0);
431 evhttp_remove_header(req->input_headers, "X-Hook");
432 evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
434 return (0);
437 static void
438 rpc_basic_client(void)
440 short port;
441 struct evhttp *http = NULL;
442 struct evrpc_base *base = NULL;
443 struct evrpc_pool *pool = NULL;
444 struct msg *msg;
445 struct kill *kill;
447 fprintf(stdout, "Testing RPC Client: ");
449 rpc_setup(&http, &port, &base);
451 need_input_hook = 1;
452 need_output_hook = 1;
454 assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
455 != NULL);
456 assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
457 != NULL);
459 pool = rpc_pool_with_connection(port);
461 assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
463 /* set up the basic message */
464 msg = msg_new();
465 EVTAG_ASSIGN(msg, from_name, "niels");
466 EVTAG_ASSIGN(msg, to_name, "tester");
468 kill = kill_new();
470 EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
472 test_ok = 0;
474 event_dispatch();
476 if (test_ok != 1) {
477 fprintf(stdout, "FAILED (1)\n");
478 exit(1);
481 /* we do it twice to make sure that reuse works correctly */
482 kill_clear(kill);
484 EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
486 event_dispatch();
488 rpc_teardown(base);
490 if (test_ok != 2) {
491 fprintf(stdout, "FAILED (2)\n");
492 exit(1);
495 fprintf(stdout, "OK\n");
497 msg_free(msg);
498 kill_free(kill);
500 evrpc_pool_free(pool);
501 evhttp_free(http);
505 * We are testing that the second requests gets send over the same
506 * connection after the first RPCs completes.
508 static void
509 rpc_basic_queued_client(void)
511 short port;
512 struct evhttp *http = NULL;
513 struct evrpc_base *base = NULL;
514 struct evrpc_pool *pool = NULL;
515 struct msg *msg;
516 struct kill *kill_one, *kill_two;
518 fprintf(stdout, "Testing RPC (Queued) Client: ");
520 rpc_setup(&http, &port, &base);
522 pool = rpc_pool_with_connection(port);
524 /* set up the basic message */
525 msg = msg_new();
526 EVTAG_ASSIGN(msg, from_name, "niels");
527 EVTAG_ASSIGN(msg, to_name, "tester");
529 kill_one = kill_new();
530 kill_two = kill_new();
532 EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one, GotKillCbTwo, NULL);
533 EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two, GotKillCb, NULL);
535 test_ok = 0;
537 event_dispatch();
539 rpc_teardown(base);
541 if (test_ok != 2) {
542 fprintf(stdout, "FAILED (1)\n");
543 exit(1);
546 fprintf(stdout, "OK\n");
548 msg_free(msg);
549 kill_free(kill_one);
550 kill_free(kill_two);
552 evrpc_pool_free(pool);
553 evhttp_free(http);
556 static void
557 GotErrorCb(struct evrpc_status *status,
558 struct msg *msg, struct kill *kill, void *arg)
560 if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
561 goto done;
563 /* should never be complete but just to check */
564 if (kill_complete(kill) == 0)
565 goto done;
567 test_ok += 1;
569 done:
570 event_loopexit(NULL);
573 static void
574 rpc_client_timeout(void)
576 short port;
577 struct evhttp *http = NULL;
578 struct evrpc_base *base = NULL;
579 struct evrpc_pool *pool = NULL;
580 struct msg *msg;
581 struct kill *kill;
583 fprintf(stdout, "Testing RPC Client Timeout: ");
585 rpc_setup(&http, &port, &base);
587 pool = rpc_pool_with_connection(port);
589 /* set the timeout to 5 seconds */
590 evrpc_pool_set_timeout(pool, 5);
592 /* set up the basic message */
593 msg = msg_new();
594 EVTAG_ASSIGN(msg, from_name, "niels");
595 EVTAG_ASSIGN(msg, to_name, "tester");
597 kill = kill_new();
599 EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
601 test_ok = 0;
603 event_dispatch();
605 /* free the saved RPC structure up */
606 EVRPC_REQUEST_DONE(saved_rpc);
608 rpc_teardown(base);
610 if (test_ok != 2) {
611 fprintf(stdout, "FAILED (1)\n");
612 exit(1);
615 fprintf(stdout, "OK\n");
617 msg_free(msg);
618 kill_free(kill);
620 evrpc_pool_free(pool);
621 evhttp_free(http);
624 void
625 rpc_suite(void)
627 rpc_basic_test();
628 rpc_basic_message();
629 rpc_basic_client();
630 rpc_basic_queued_client();
631 rpc_client_timeout();