Delete unused downloads page asset.
[chromium-blink-merge.git] / third_party / libevent / test / regress_rpc.c
blob760934766a1b92fc2f78f9b4dd625b4cb3940df1
1 /*
2 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #ifdef WIN32
29 #include <winsock2.h>
30 #include <windows.h>
31 #endif
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42 #include <sys/queue.h>
43 #ifndef WIN32
44 #include <sys/socket.h>
45 #include <signal.h>
46 #include <unistd.h>
47 #include <netdb.h>
48 #endif
49 #include <fcntl.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <errno.h>
54 #include <assert.h>
56 #include "event.h"
57 #include "evhttp.h"
58 #include "log.h"
59 #include "evrpc.h"
61 #include "regress.gen.h"
63 void rpc_suite(void);
65 extern int test_ok;
67 static struct evhttp *
68 http_setup(short *pport)
70 int i;
71 struct evhttp *myhttp;
72 short port = -1;
74 /* Try a few different ports */
75 for (i = 0; i < 50; ++i) {
76 myhttp = evhttp_start("127.0.0.1", 8080 + i);
77 if (myhttp != NULL) {
78 port = 8080 + i;
79 break;
83 if (port == -1)
84 event_errx(1, "Could not start web server");
86 *pport = port;
87 return (myhttp);
90 EVRPC_HEADER(Message, msg, kill);
91 EVRPC_HEADER(NeverReply, msg, kill);
93 EVRPC_GENERATE(Message, msg, kill);
94 EVRPC_GENERATE(NeverReply, msg, kill);
96 static int need_input_hook = 0;
97 static int need_output_hook = 0;
99 static void
100 MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
102 struct kill* kill_reply = rpc->reply;
104 if (need_input_hook) {
105 struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
106 const char *header = evhttp_find_header(
107 req->input_headers, "X-Hook");
108 assert(strcmp(header, "input") == 0);
111 /* we just want to fill in some non-sense */
112 EVTAG_ASSIGN(kill_reply, weapon, "dagger");
113 EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
115 /* no reply to the RPC */
116 EVRPC_REQUEST_DONE(rpc);
119 static EVRPC_STRUCT(NeverReply) *saved_rpc;
121 static void
122 NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
124 test_ok += 1;
125 saved_rpc = rpc;
128 static void
129 rpc_setup(struct evhttp **phttp, short *pport, struct evrpc_base **pbase)
131 short port;
132 struct evhttp *http = NULL;
133 struct evrpc_base *base = NULL;
135 http = http_setup(&port);
136 base = evrpc_init(http);
138 EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
139 EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
141 *phttp = http;
142 *pport = port;
143 *pbase = base;
145 need_input_hook = 0;
146 need_output_hook = 0;
149 static void
150 rpc_teardown(struct evrpc_base *base)
152 assert(EVRPC_UNREGISTER(base, Message) == 0);
153 assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
155 evrpc_free(base);
158 static void
159 rpc_postrequest_failure(struct evhttp_request *req, void *arg)
161 if (req->response_code != HTTP_SERVUNAVAIL) {
163 fprintf(stderr, "FAILED (response code)\n");
164 exit(1);
167 test_ok = 1;
168 event_loopexit(NULL);
172 * Test a malformed payload submitted as an RPC
175 static void
176 rpc_basic_test(void)
178 short port;
179 struct evhttp *http = NULL;
180 struct evrpc_base *base = NULL;
181 struct evhttp_connection *evcon = NULL;
182 struct evhttp_request *req = NULL;
184 fprintf(stdout, "Testing Basic RPC Support: ");
186 rpc_setup(&http, &port, &base);
188 evcon = evhttp_connection_new("127.0.0.1", port);
189 if (evcon == NULL) {
190 fprintf(stdout, "FAILED\n");
191 exit(1);
195 * At this point, we want to schedule an HTTP POST request
196 * server using our make request method.
199 req = evhttp_request_new(rpc_postrequest_failure, NULL);
200 if (req == NULL) {
201 fprintf(stdout, "FAILED\n");
202 exit(1);
205 /* Add the information that we care about */
206 evhttp_add_header(req->output_headers, "Host", "somehost");
207 evbuffer_add_printf(req->output_buffer, "Some Nonsense");
209 if (evhttp_make_request(evcon, req,
210 EVHTTP_REQ_POST,
211 "/.rpc.Message") == -1) {
212 fprintf(stdout, "FAILED\n");
213 exit(1);
216 test_ok = 0;
218 event_dispatch();
220 evhttp_connection_free(evcon);
222 rpc_teardown(base);
224 if (test_ok != 1) {
225 fprintf(stdout, "FAILED\n");
226 exit(1);
229 fprintf(stdout, "OK\n");
231 evhttp_free(http);
234 static void
235 rpc_postrequest_done(struct evhttp_request *req, void *arg)
237 struct kill* kill_reply = NULL;
239 if (req->response_code != HTTP_OK) {
241 fprintf(stderr, "FAILED (response code)\n");
242 exit(1);
245 kill_reply = kill_new();
247 if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
248 fprintf(stderr, "FAILED (unmarshal)\n");
249 exit(1);
252 kill_free(kill_reply);
254 test_ok = 1;
255 event_loopexit(NULL);
258 static void
259 rpc_basic_message(void)
261 short port;
262 struct evhttp *http = NULL;
263 struct evrpc_base *base = NULL;
264 struct evhttp_connection *evcon = NULL;
265 struct evhttp_request *req = NULL;
266 struct msg *msg;
268 fprintf(stdout, "Testing Good RPC Post: ");
270 rpc_setup(&http, &port, &base);
272 evcon = evhttp_connection_new("127.0.0.1", port);
273 if (evcon == NULL) {
274 fprintf(stdout, "FAILED\n");
275 exit(1);
279 * At this point, we want to schedule an HTTP POST request
280 * server using our make request method.
283 req = evhttp_request_new(rpc_postrequest_done, NULL);
284 if (req == NULL) {
285 fprintf(stdout, "FAILED\n");
286 exit(1);
289 /* Add the information that we care about */
290 evhttp_add_header(req->output_headers, "Host", "somehost");
292 /* set up the basic message */
293 msg = msg_new();
294 EVTAG_ASSIGN(msg, from_name, "niels");
295 EVTAG_ASSIGN(msg, to_name, "tester");
296 msg_marshal(req->output_buffer, msg);
297 msg_free(msg);
299 if (evhttp_make_request(evcon, req,
300 EVHTTP_REQ_POST,
301 "/.rpc.Message") == -1) {
302 fprintf(stdout, "FAILED\n");
303 exit(1);
306 test_ok = 0;
308 event_dispatch();
310 evhttp_connection_free(evcon);
312 rpc_teardown(base);
314 if (test_ok != 1) {
315 fprintf(stdout, "FAILED\n");
316 exit(1);
319 fprintf(stdout, "OK\n");
321 evhttp_free(http);
324 static struct evrpc_pool *
325 rpc_pool_with_connection(short port)
327 struct evhttp_connection *evcon;
328 struct evrpc_pool *pool;
330 pool = evrpc_pool_new(NULL);
331 assert(pool != NULL);
333 evcon = evhttp_connection_new("127.0.0.1", port);
334 assert(evcon != NULL);
336 evrpc_pool_add_connection(pool, evcon);
338 return (pool);
341 static void
342 GotKillCb(struct evrpc_status *status,
343 struct msg *msg, struct kill *kill, void *arg)
345 char *weapon;
346 char *action;
348 if (need_output_hook) {
349 struct evhttp_request *req = status->http_req;
350 const char *header = evhttp_find_header(
351 req->input_headers, "X-Pool-Hook");
352 assert(strcmp(header, "ran") == 0);
355 if (status->error != EVRPC_STATUS_ERR_NONE)
356 goto done;
358 if (EVTAG_GET(kill, weapon, &weapon) == -1) {
359 fprintf(stderr, "get weapon\n");
360 goto done;
362 if (EVTAG_GET(kill, action, &action) == -1) {
363 fprintf(stderr, "get action\n");
364 goto done;
367 if (strcmp(weapon, "dagger"))
368 goto done;
370 if (strcmp(action, "wave around like an idiot"))
371 goto done;
373 test_ok += 1;
375 done:
376 event_loopexit(NULL);
379 static void
380 GotKillCbTwo(struct evrpc_status *status,
381 struct msg *msg, struct kill *kill, void *arg)
383 char *weapon;
384 char *action;
386 if (status->error != EVRPC_STATUS_ERR_NONE)
387 goto done;
389 if (EVTAG_GET(kill, weapon, &weapon) == -1) {
390 fprintf(stderr, "get weapon\n");
391 goto done;
393 if (EVTAG_GET(kill, action, &action) == -1) {
394 fprintf(stderr, "get action\n");
395 goto done;
398 if (strcmp(weapon, "dagger"))
399 goto done;
401 if (strcmp(action, "wave around like an idiot"))
402 goto done;
404 test_ok += 1;
406 done:
407 if (test_ok == 2)
408 event_loopexit(NULL);
411 static int
412 rpc_hook_add_header(struct evhttp_request *req,
413 struct evbuffer *evbuf, void *arg)
415 const char *hook_type = arg;
416 if (strcmp("input", hook_type) == 0)
417 evhttp_add_header(req->input_headers, "X-Hook", hook_type);
418 else
419 evhttp_add_header(req->output_headers, "X-Hook", hook_type);
420 return (0);
423 static int
424 rpc_hook_remove_header(struct evhttp_request *req,
425 struct evbuffer *evbuf, void *arg)
427 const char *header = evhttp_find_header(req->input_headers, "X-Hook");
428 assert(header != NULL);
429 assert(strcmp(header, arg) == 0);
430 evhttp_remove_header(req->input_headers, "X-Hook");
431 evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
433 return (0);
436 static void
437 rpc_basic_client(void)
439 short port;
440 struct evhttp *http = NULL;
441 struct evrpc_base *base = NULL;
442 struct evrpc_pool *pool = NULL;
443 struct msg *msg;
444 struct kill *kill;
446 fprintf(stdout, "Testing RPC Client: ");
448 rpc_setup(&http, &port, &base);
450 need_input_hook = 1;
451 need_output_hook = 1;
453 assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
454 != NULL);
455 assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
456 != NULL);
458 pool = rpc_pool_with_connection(port);
460 assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
462 /* set up the basic message */
463 msg = msg_new();
464 EVTAG_ASSIGN(msg, from_name, "niels");
465 EVTAG_ASSIGN(msg, to_name, "tester");
467 kill = kill_new();
469 EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
471 test_ok = 0;
473 event_dispatch();
475 if (test_ok != 1) {
476 fprintf(stdout, "FAILED (1)\n");
477 exit(1);
480 /* we do it twice to make sure that reuse works correctly */
481 kill_clear(kill);
483 EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
485 event_dispatch();
487 rpc_teardown(base);
489 if (test_ok != 2) {
490 fprintf(stdout, "FAILED (2)\n");
491 exit(1);
494 fprintf(stdout, "OK\n");
496 msg_free(msg);
497 kill_free(kill);
499 evrpc_pool_free(pool);
500 evhttp_free(http);
504 * We are testing that the second requests gets send over the same
505 * connection after the first RPCs completes.
507 static void
508 rpc_basic_queued_client(void)
510 short port;
511 struct evhttp *http = NULL;
512 struct evrpc_base *base = NULL;
513 struct evrpc_pool *pool = NULL;
514 struct msg *msg;
515 struct kill *kill_one, *kill_two;
517 fprintf(stdout, "Testing RPC (Queued) Client: ");
519 rpc_setup(&http, &port, &base);
521 pool = rpc_pool_with_connection(port);
523 /* set up the basic message */
524 msg = msg_new();
525 EVTAG_ASSIGN(msg, from_name, "niels");
526 EVTAG_ASSIGN(msg, to_name, "tester");
528 kill_one = kill_new();
529 kill_two = kill_new();
531 EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one, GotKillCbTwo, NULL);
532 EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two, GotKillCb, NULL);
534 test_ok = 0;
536 event_dispatch();
538 rpc_teardown(base);
540 if (test_ok != 2) {
541 fprintf(stdout, "FAILED (1)\n");
542 exit(1);
545 fprintf(stdout, "OK\n");
547 msg_free(msg);
548 kill_free(kill_one);
549 kill_free(kill_two);
551 evrpc_pool_free(pool);
552 evhttp_free(http);
555 static void
556 GotErrorCb(struct evrpc_status *status,
557 struct msg *msg, struct kill *kill, void *arg)
559 if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
560 goto done;
562 /* should never be complete but just to check */
563 if (kill_complete(kill) == 0)
564 goto done;
566 test_ok += 1;
568 done:
569 event_loopexit(NULL);
572 static void
573 rpc_client_timeout(void)
575 short port;
576 struct evhttp *http = NULL;
577 struct evrpc_base *base = NULL;
578 struct evrpc_pool *pool = NULL;
579 struct msg *msg;
580 struct kill *kill;
582 fprintf(stdout, "Testing RPC Client Timeout: ");
584 rpc_setup(&http, &port, &base);
586 pool = rpc_pool_with_connection(port);
588 /* set the timeout to 5 seconds */
589 evrpc_pool_set_timeout(pool, 5);
591 /* set up the basic message */
592 msg = msg_new();
593 EVTAG_ASSIGN(msg, from_name, "niels");
594 EVTAG_ASSIGN(msg, to_name, "tester");
596 kill = kill_new();
598 EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
600 test_ok = 0;
602 event_dispatch();
604 /* free the saved RPC structure up */
605 EVRPC_REQUEST_DONE(saved_rpc);
607 rpc_teardown(base);
609 if (test_ok != 2) {
610 fprintf(stdout, "FAILED (1)\n");
611 exit(1);
614 fprintf(stdout, "OK\n");
616 msg_free(msg);
617 kill_free(kill);
619 evrpc_pool_free(pool);
620 evhttp_free(http);
623 void
624 rpc_suite(void)
626 rpc_basic_test();
627 rpc_basic_message();
628 rpc_basic_client();
629 rpc_basic_queued_client();
630 rpc_client_timeout();