Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (c) 2003-2007 Niels Provos <provos (at) citi.umich.edu>
      3  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
      4  *
      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.
     15  *
     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.
     26  */
     27 
     28 /* The old tests here need assertions to work. */
     29 #undef NDEBUG
     30 
     31 #ifdef _WIN32
     32 #include <winsock2.h>
     33 #include <windows.h>
     34 #endif
     35 
     36 #include "event2/event-config.h"
     37 
     38 #include <sys/types.h>
     39 #include <sys/stat.h>
     40 #ifdef EVENT__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>
     56 
     57 #include "event2/buffer.h"
     58 #include "event2/event.h"
     59 #include "event2/event_compat.h"
     60 #include "event2/http.h"
     61 #include "event2/http_compat.h"
     62 #include "event2/http_struct.h"
     63 #include "event2/rpc.h"
     64 #include "event2/rpc.h"
     65 #include "event2/rpc_struct.h"
     66 #include "event2/tag.h"
     67 #include "log-internal.h"
     68 
     69 #include "regress.gen.h"
     70 
     71 #include "regress.h"
     72 #include "regress_testutils.h"
     73 
     74 #ifndef NO_PYTHON_EXISTS
     75 
     76 static struct evhttp *
     77 http_setup(ev_uint16_t *pport)
     78 {
     79 	struct evhttp *myhttp;
     80 	ev_uint16_t port;
     81 	struct evhttp_bound_socket *sock;
     82 
     83 	myhttp = evhttp_new(NULL);
     84 	if (!myhttp)
     85 		event_errx(1, "Could not start web server");
     86 
     87 	/* Try a few different ports */
     88 	sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", 0);
     89 	if (!sock)
     90 		event_errx(1, "Couldn't open web port");
     91 
     92 	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
     93 
     94 	*pport = port;
     95 	return (myhttp);
     96 }
     97 
     98 EVRPC_HEADER(Message, msg, kill)
     99 EVRPC_HEADER(NeverReply, msg, kill)
    100 
    101 EVRPC_GENERATE(Message, msg, kill)
    102 EVRPC_GENERATE(NeverReply, msg, kill)
    103 
    104 static int need_input_hook = 0;
    105 static int need_output_hook = 0;
    106 
    107 static void
    108 MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
    109 {
    110 	struct kill* kill_reply = rpc->reply;
    111 
    112 	if (need_input_hook) {
    113 		struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
    114 		const char *header = evhttp_find_header(
    115 			req->input_headers, "X-Hook");
    116 		assert(header);
    117 		assert(strcmp(header, "input") == 0);
    118 	}
    119 
    120 	/* we just want to fill in some non-sense */
    121 	EVTAG_ASSIGN(kill_reply, weapon, "dagger");
    122 	EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
    123 
    124 	/* no reply to the RPC */
    125 	EVRPC_REQUEST_DONE(rpc);
    126 }
    127 
    128 static EVRPC_STRUCT(NeverReply) *saved_rpc;
    129 
    130 static void
    131 NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
    132 {
    133 	test_ok += 1;
    134 	saved_rpc = rpc;
    135 }
    136 
    137 static void
    138 rpc_setup(struct evhttp **phttp, ev_uint16_t *pport, struct evrpc_base **pbase)
    139 {
    140 	ev_uint16_t port;
    141 	struct evhttp *http = NULL;
    142 	struct evrpc_base *base = NULL;
    143 
    144 	http = http_setup(&port);
    145 	base = evrpc_init(http);
    146 
    147 	EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
    148 	EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
    149 
    150 	*phttp = http;
    151 	*pport = port;
    152 	*pbase = base;
    153 
    154 	need_input_hook = 0;
    155 	need_output_hook = 0;
    156 }
    157 
    158 static void
    159 rpc_teardown(struct evrpc_base *base)
    160 {
    161 	assert(EVRPC_UNREGISTER(base, Message) == 0);
    162 	assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
    163 
    164 	evrpc_free(base);
    165 }
    166 
    167 static void
    168 rpc_postrequest_failure(struct evhttp_request *req, void *arg)
    169 {
    170 	if (req->response_code != HTTP_SERVUNAVAIL) {
    171 
    172 		fprintf(stderr, "FAILED (response code)\n");
    173 		exit(1);
    174 	}
    175 
    176 	test_ok = 1;
    177 	event_loopexit(NULL);
    178 }
    179 
    180 /*
    181  * Test a malformed payload submitted as an RPC
    182  */
    183 
    184 static void
    185 rpc_basic_test(void)
    186 {
    187 	ev_uint16_t port;
    188 	struct evhttp *http = NULL;
    189 	struct evrpc_base *base = NULL;
    190 	struct evhttp_connection *evcon = NULL;
    191 	struct evhttp_request *req = NULL;
    192 
    193 	rpc_setup(&http, &port, &base);
    194 
    195 	evcon = evhttp_connection_new("127.0.0.1", port);
    196 	tt_assert(evcon);
    197 
    198 	/*
    199 	 * At this point, we want to schedule an HTTP POST request
    200 	 * server using our make request method.
    201 	 */
    202 
    203 	req = evhttp_request_new(rpc_postrequest_failure, NULL);
    204 	tt_assert(req);
    205 
    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");
    209 
    210 	if (evhttp_make_request(evcon, req,
    211 		EVHTTP_REQ_POST,
    212 		"/.rpc.Message") == -1) {
    213 		tt_abort();
    214 	}
    215 
    216 	test_ok = 0;
    217 
    218 	event_dispatch();
    219 
    220 	evhttp_connection_free(evcon);
    221 
    222 	rpc_teardown(base);
    223 
    224 	tt_assert(test_ok == 1);
    225 
    226 end:
    227 	evhttp_free(http);
    228 }
    229 
    230 static void
    231 rpc_postrequest_done(struct evhttp_request *req, void *arg)
    232 {
    233 	struct kill* kill_reply = NULL;
    234 
    235 	if (req->response_code != HTTP_OK) {
    236 		fprintf(stderr, "FAILED (response code)\n");
    237 		exit(1);
    238 	}
    239 
    240 	kill_reply = kill_new();
    241 
    242 	if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
    243 		fprintf(stderr, "FAILED (unmarshal)\n");
    244 		exit(1);
    245 	}
    246 
    247 	kill_free(kill_reply);
    248 
    249 	test_ok = 1;
    250 	event_loopexit(NULL);
    251 }
    252 
    253 static void
    254 rpc_basic_message(void)
    255 {
    256 	ev_uint16_t port;
    257 	struct evhttp *http = NULL;
    258 	struct evrpc_base *base = NULL;
    259 	struct evhttp_connection *evcon = NULL;
    260 	struct evhttp_request *req = NULL;
    261 	struct msg *msg;
    262 
    263 	rpc_setup(&http, &port, &base);
    264 
    265 	evcon = evhttp_connection_new("127.0.0.1", port);
    266 	tt_assert(evcon);
    267 
    268 	/*
    269 	 * At this point, we want to schedule an HTTP POST request
    270 	 * server using our make request method.
    271 	 */
    272 
    273 	req = evhttp_request_new(rpc_postrequest_done, NULL);
    274 	if (req == NULL) {
    275 		fprintf(stdout, "FAILED\n");
    276 		exit(1);
    277 	}
    278 
    279 	/* Add the information that we care about */
    280 	evhttp_add_header(req->output_headers, "Host", "somehost");
    281 
    282 	/* set up the basic message */
    283 	msg = msg_new();
    284 	EVTAG_ASSIGN(msg, from_name, "niels");
    285 	EVTAG_ASSIGN(msg, to_name, "tester");
    286 	msg_marshal(req->output_buffer, msg);
    287 	msg_free(msg);
    288 
    289 	if (evhttp_make_request(evcon, req,
    290 		EVHTTP_REQ_POST,
    291 		"/.rpc.Message") == -1) {
    292 		fprintf(stdout, "FAILED\n");
    293 		exit(1);
    294 	}
    295 
    296 	test_ok = 0;
    297 
    298 	event_dispatch();
    299 
    300 	evhttp_connection_free(evcon);
    301 
    302 	rpc_teardown(base);
    303 
    304 end:
    305 	evhttp_free(http);
    306 }
    307 
    308 static struct evrpc_pool *
    309 rpc_pool_with_connection(ev_uint16_t port)
    310 {
    311 	struct evhttp_connection *evcon;
    312 	struct evrpc_pool *pool;
    313 
    314 	pool = evrpc_pool_new(NULL);
    315 	assert(pool != NULL);
    316 
    317 	evcon = evhttp_connection_new("127.0.0.1", port);
    318 	assert(evcon != NULL);
    319 
    320 	evrpc_pool_add_connection(pool, evcon);
    321 
    322 	return (pool);
    323 }
    324 
    325 static void
    326 GotKillCb(struct evrpc_status *status,
    327     struct msg *msg, struct kill *kill, void *arg)
    328 {
    329 	char *weapon;
    330 	char *action;
    331 
    332 	if (need_output_hook) {
    333 		struct evhttp_request *req = status->http_req;
    334 		const char *header = evhttp_find_header(
    335 			req->input_headers, "X-Pool-Hook");
    336 		assert(header);
    337 		assert(strcmp(header, "ran") == 0);
    338 	}
    339 
    340 	if (status->error != EVRPC_STATUS_ERR_NONE)
    341 		goto done;
    342 
    343 	if (EVTAG_GET(kill, weapon, &weapon) == -1) {
    344 		fprintf(stderr, "get weapon\n");
    345 		goto done;
    346 	}
    347 	if (EVTAG_GET(kill, action, &action) == -1) {
    348 		fprintf(stderr, "get action\n");
    349 		goto done;
    350 	}
    351 
    352 	if (strcmp(weapon, "dagger"))
    353 		goto done;
    354 
    355 	if (strcmp(action, "wave around like an idiot"))
    356 		goto done;
    357 
    358 	test_ok += 1;
    359 
    360 done:
    361 	event_loopexit(NULL);
    362 }
    363 
    364 static void
    365 GotKillCbTwo(struct evrpc_status *status,
    366     struct msg *msg, struct kill *kill, void *arg)
    367 {
    368 	char *weapon;
    369 	char *action;
    370 
    371 	if (status->error != EVRPC_STATUS_ERR_NONE)
    372 		goto done;
    373 
    374 	if (EVTAG_GET(kill, weapon, &weapon) == -1) {
    375 		fprintf(stderr, "get weapon\n");
    376 		goto done;
    377 	}
    378 	if (EVTAG_GET(kill, action, &action) == -1) {
    379 		fprintf(stderr, "get action\n");
    380 		goto done;
    381 	}
    382 
    383 	if (strcmp(weapon, "dagger"))
    384 		goto done;
    385 
    386 	if (strcmp(action, "wave around like an idiot"))
    387 		goto done;
    388 
    389 	test_ok += 1;
    390 
    391 done:
    392 	if (test_ok == 2)
    393 		event_loopexit(NULL);
    394 }
    395 
    396 static int
    397 rpc_hook_add_header(void *ctx, struct evhttp_request *req,
    398     struct evbuffer *evbuf, void *arg)
    399 {
    400 	const char *hook_type = arg;
    401 	if (strcmp("input", hook_type) == 0)
    402 		evhttp_add_header(req->input_headers, "X-Hook", hook_type);
    403 	else
    404 		evhttp_add_header(req->output_headers, "X-Hook", hook_type);
    405 
    406 	assert(evrpc_hook_get_connection(ctx) != NULL);
    407 
    408 	return (EVRPC_CONTINUE);
    409 }
    410 
    411 static int
    412 rpc_hook_add_meta(void *ctx, struct evhttp_request *req,
    413     struct evbuffer *evbuf, void *arg)
    414 {
    415 	evrpc_hook_add_meta(ctx, "meta", "test", 5);
    416 
    417 	assert(evrpc_hook_get_connection(ctx) != NULL);
    418 
    419 	return (EVRPC_CONTINUE);
    420 }
    421 
    422 static int
    423 rpc_hook_remove_header(void *ctx, struct evhttp_request *req,
    424     struct evbuffer *evbuf, void *arg)
    425 {
    426 	const char *header = evhttp_find_header(req->input_headers, "X-Hook");
    427 	void *data = NULL;
    428 	size_t data_len = 0;
    429 
    430 	assert(header != NULL);
    431 	assert(strcmp(header, arg) == 0);
    432 
    433 	evhttp_remove_header(req->input_headers, "X-Hook");
    434 	evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
    435 
    436 	assert(evrpc_hook_find_meta(ctx, "meta", &data, &data_len) == 0);
    437 	assert(data != NULL);
    438 	assert(data_len == 5);
    439 
    440 	assert(evrpc_hook_get_connection(ctx) != NULL);
    441 
    442 	return (EVRPC_CONTINUE);
    443 }
    444 
    445 static void
    446 rpc_basic_client(void)
    447 {
    448 	ev_uint16_t port;
    449 	struct evhttp *http = NULL;
    450 	struct evrpc_base *base = NULL;
    451 	struct evrpc_pool *pool = NULL;
    452 	struct msg *msg = NULL;
    453 	struct kill *kill = NULL;
    454 
    455 	rpc_setup(&http, &port, &base);
    456 
    457 	need_input_hook = 1;
    458 	need_output_hook = 1;
    459 
    460 	assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
    461 	    != NULL);
    462 	assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
    463 	    != NULL);
    464 
    465 	pool = rpc_pool_with_connection(port);
    466 	tt_assert(pool);
    467 
    468 	assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_add_meta, NULL));
    469 	assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
    470 
    471 	/* set up the basic message */
    472 	msg = msg_new();
    473 	tt_assert(msg);
    474 	EVTAG_ASSIGN(msg, from_name, "niels");
    475 	EVTAG_ASSIGN(msg, to_name, "tester");
    476 
    477 	kill = kill_new();
    478 
    479 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill,  GotKillCb, NULL);
    480 
    481 	test_ok = 0;
    482 
    483 	event_dispatch();
    484 
    485 	tt_assert(test_ok == 1);
    486 
    487 	/* we do it twice to make sure that reuse works correctly */
    488 	kill_clear(kill);
    489 
    490 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill,  GotKillCb, NULL);
    491 
    492 	event_dispatch();
    493 
    494 	tt_assert(test_ok == 2);
    495 
    496 	/* we do it trice to make sure other stuff works, too */
    497 	kill_clear(kill);
    498 
    499 	{
    500 		struct evrpc_request_wrapper *ctx =
    501 		    EVRPC_MAKE_CTX(Message, msg, kill,
    502 			pool, msg, kill, GotKillCb, NULL);
    503 		evrpc_make_request(ctx);
    504 	}
    505 
    506 	event_dispatch();
    507 
    508 	rpc_teardown(base);
    509 
    510 	tt_assert(test_ok == 3);
    511 
    512 end:
    513 	if (msg)
    514 		msg_free(msg);
    515 	if (kill)
    516 		kill_free(kill);
    517 
    518 	if (pool)
    519 		evrpc_pool_free(pool);
    520 	if (http)
    521 		evhttp_free(http);
    522 
    523 	need_input_hook = 0;
    524 	need_output_hook = 0;
    525 }
    526 
    527 /*
    528  * We are testing that the second requests gets send over the same
    529  * connection after the first RPCs completes.
    530  */
    531 static void
    532 rpc_basic_queued_client(void)
    533 {
    534 	ev_uint16_t port;
    535 	struct evhttp *http = NULL;
    536 	struct evrpc_base *base = NULL;
    537 	struct evrpc_pool *pool = NULL;
    538 	struct msg *msg=NULL;
    539 	struct kill *kill_one=NULL, *kill_two=NULL;
    540 
    541 	rpc_setup(&http, &port, &base);
    542 
    543 	pool = rpc_pool_with_connection(port);
    544 	tt_assert(pool);
    545 
    546 	/* set up the basic message */
    547 	msg = msg_new();
    548 	tt_assert(msg);
    549 	EVTAG_ASSIGN(msg, from_name, "niels");
    550 	EVTAG_ASSIGN(msg, to_name, "tester");
    551 
    552 	kill_one = kill_new();
    553 	kill_two = kill_new();
    554 
    555 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one,  GotKillCbTwo, NULL);
    556 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two,  GotKillCb, NULL);
    557 
    558 	test_ok = 0;
    559 
    560 	event_dispatch();
    561 
    562 	rpc_teardown(base);
    563 
    564 	tt_assert(test_ok == 2);
    565 
    566 end:
    567 	if (msg)
    568 		msg_free(msg);
    569 	if (kill_one)
    570 		kill_free(kill_one);
    571 	if (kill_two)
    572 		kill_free(kill_two);
    573 
    574 	if (pool)
    575 		evrpc_pool_free(pool);
    576 	if (http)
    577 		evhttp_free(http);
    578 }
    579 
    580 static void
    581 GotErrorCb(struct evrpc_status *status,
    582     struct msg *msg, struct kill *kill, void *arg)
    583 {
    584 	if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
    585 		goto done;
    586 
    587 	/* should never be complete but just to check */
    588 	if (kill_complete(kill) == 0)
    589 		goto done;
    590 
    591 	test_ok += 1;
    592 
    593 done:
    594 	event_loopexit(NULL);
    595 }
    596 
    597 /* we just pause the rpc and continue it in the next callback */
    598 
    599 struct rpc_hook_ctx_ {
    600 	void *vbase;
    601 	void *ctx;
    602 };
    603 
    604 static int hook_pause_cb_called=0;
    605 
    606 static void
    607 rpc_hook_pause_cb(evutil_socket_t fd, short what, void *arg)
    608 {
    609 	struct rpc_hook_ctx_ *ctx = arg;
    610 	++hook_pause_cb_called;
    611 	evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
    612 	free(arg);
    613 }
    614 
    615 static int
    616 rpc_hook_pause(void *ctx, struct evhttp_request *req, struct evbuffer *evbuf,
    617     void *arg)
    618 {
    619 	struct rpc_hook_ctx_ *tmp = malloc(sizeof(*tmp));
    620 	struct timeval tv;
    621 
    622 	assert(tmp != NULL);
    623 	tmp->vbase = arg;
    624 	tmp->ctx = ctx;
    625 
    626 	memset(&tv, 0, sizeof(tv));
    627 	event_once(-1, EV_TIMEOUT, rpc_hook_pause_cb, tmp, &tv);
    628 	return EVRPC_PAUSE;
    629 }
    630 
    631 static void
    632 rpc_basic_client_with_pause(void)
    633 {
    634 	ev_uint16_t port;
    635 	struct evhttp *http = NULL;
    636 	struct evrpc_base *base = NULL;
    637 	struct evrpc_pool *pool = NULL;
    638 	struct msg *msg = NULL;
    639 	struct kill *kill= NULL;
    640 
    641 	rpc_setup(&http, &port, &base);
    642 
    643 	assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_pause, base));
    644 	assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_pause, base));
    645 
    646 	pool = rpc_pool_with_connection(port);
    647 	tt_assert(pool);
    648 	assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_pause, pool));
    649 	assert(evrpc_add_hook(pool, EVRPC_OUTPUT, rpc_hook_pause, pool));
    650 
    651 	/* set up the basic message */
    652 	msg = msg_new();
    653 	tt_assert(msg);
    654 	EVTAG_ASSIGN(msg, from_name, "niels");
    655 	EVTAG_ASSIGN(msg, to_name, "tester");
    656 
    657 	kill = kill_new();
    658 
    659 	EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
    660 
    661 	test_ok = 0;
    662 
    663 	event_dispatch();
    664 
    665 	tt_int_op(test_ok, ==, 1);
    666 	tt_int_op(hook_pause_cb_called, ==, 4);
    667 
    668 end:
    669 	if (base)
    670 		rpc_teardown(base);
    671 
    672 	if (msg)
    673 		msg_free(msg);
    674 	if (kill)
    675 		kill_free(kill);
    676 
    677 	if (pool)
    678 		evrpc_pool_free(pool);
    679 	if (http)
    680 		evhttp_free(http);
    681 }
    682 
    683 static void
    684 rpc_client_timeout(void)
    685 {
    686 	ev_uint16_t port;
    687 	struct evhttp *http = NULL;
    688 	struct evrpc_base *base = NULL;
    689 	struct evrpc_pool *pool = NULL;
    690 	struct msg *msg = NULL;
    691 	struct kill *kill = NULL;
    692 
    693 	rpc_setup(&http, &port, &base);
    694 
    695 	pool = rpc_pool_with_connection(port);
    696 	tt_assert(pool);
    697 
    698 	/* set the timeout to 1 second. */
    699 	evrpc_pool_set_timeout(pool, 1);
    700 
    701 	/* set up the basic message */
    702 	msg = msg_new();
    703 	tt_assert(msg);
    704 	EVTAG_ASSIGN(msg, from_name, "niels");
    705 	EVTAG_ASSIGN(msg, to_name, "tester");
    706 
    707 	kill = kill_new();
    708 
    709 	EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
    710 
    711 	test_ok = 0;
    712 
    713 	event_dispatch();
    714 
    715 	/* free the saved RPC structure up */
    716 	EVRPC_REQUEST_DONE(saved_rpc);
    717 
    718 	rpc_teardown(base);
    719 
    720 	tt_assert(test_ok == 2);
    721 
    722 end:
    723 	if (msg)
    724 		msg_free(msg);
    725 	if (kill)
    726 		kill_free(kill);
    727 
    728 	if (pool)
    729 		evrpc_pool_free(pool);
    730 	if (http)
    731 		evhttp_free(http);
    732 }
    733 
    734 static void
    735 rpc_test(void)
    736 {
    737 	struct msg *msg = NULL, *msg2 = NULL;
    738 	struct kill *attack = NULL;
    739 	struct run *run = NULL;
    740 	struct evbuffer *tmp = evbuffer_new();
    741 	struct timeval tv_start, tv_end;
    742 	ev_uint32_t tag;
    743 	int i;
    744 
    745 	msg = msg_new();
    746 
    747 	tt_assert(msg);
    748 
    749 	EVTAG_ASSIGN(msg, from_name, "niels");
    750 	EVTAG_ASSIGN(msg, to_name, "phoenix");
    751 
    752 	if (EVTAG_GET(msg, attack, &attack) == -1) {
    753 		tt_abort_msg("Failed to set kill message.");
    754 	}
    755 
    756 	EVTAG_ASSIGN(attack, weapon, "feather");
    757 	EVTAG_ASSIGN(attack, action, "tickle");
    758 	for (i = 0; i < 3; ++i) {
    759 		if (EVTAG_ARRAY_ADD_VALUE(attack, how_often, i) == NULL) {
    760 			tt_abort_msg("Failed to add how_often.");
    761 		}
    762 	}
    763 
    764 	evutil_gettimeofday(&tv_start, NULL);
    765 	for (i = 0; i < 1000; ++i) {
    766 		run = EVTAG_ARRAY_ADD(msg, run);
    767 		if (run == NULL) {
    768 			tt_abort_msg("Failed to add run message.");
    769 		}
    770 		EVTAG_ASSIGN(run, how, "very fast but with some data in it");
    771 		EVTAG_ASSIGN(run, fixed_bytes,
    772 		    (ev_uint8_t*)"012345678901234567890123");
    773 
    774 		if (EVTAG_ARRAY_ADD_VALUE(
    775 			    run, notes, "this is my note") == NULL) {
    776 			tt_abort_msg("Failed to add note.");
    777 		}
    778 		if (EVTAG_ARRAY_ADD_VALUE(run, notes, "pps") == NULL) {
    779 			tt_abort_msg("Failed to add note");
    780 		}
    781 
    782 		EVTAG_ASSIGN(run, large_number, 0xdead0a0bcafebeefLL);
    783 		EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xdead0a0b);
    784 		EVTAG_ARRAY_ADD_VALUE(run, other_numbers, 0xbeefcafe);
    785 	}
    786 
    787 	if (msg_complete(msg) == -1)
    788 		tt_abort_msg("Failed to make complete message.");
    789 
    790 	evtag_marshal_msg(tmp, 0xdeaf, msg);
    791 
    792 	if (evtag_peek(tmp, &tag) == -1)
    793 		tt_abort_msg("Failed to peak tag.");
    794 
    795 	if (tag != 0xdeaf)
    796 		TT_DIE(("Got incorrect tag: %0x.", (unsigned)tag));
    797 
    798 	msg2 = msg_new();
    799 	if (evtag_unmarshal_msg(tmp, 0xdeaf, msg2) == -1)
    800 		tt_abort_msg("Failed to unmarshal message.");
    801 
    802 	evutil_gettimeofday(&tv_end, NULL);
    803 	evutil_timersub(&tv_end, &tv_start, &tv_end);
    804 	TT_BLATHER(("(%.1f us/add) ",
    805 		(float)tv_end.tv_sec/(float)i * 1000000.0 +
    806 		tv_end.tv_usec / (float)i));
    807 
    808 	if (!EVTAG_HAS(msg2, from_name) ||
    809 	    !EVTAG_HAS(msg2, to_name) ||
    810 	    !EVTAG_HAS(msg2, attack)) {
    811 		tt_abort_msg("Missing data structures.");
    812 	}
    813 
    814 	if (EVTAG_GET(msg2, attack, &attack) == -1) {
    815 		tt_abort_msg("Could not get attack.");
    816 	}
    817 
    818 	if (EVTAG_ARRAY_LEN(msg2, run) != i) {
    819 		tt_abort_msg("Wrong number of run messages.");
    820 	}
    821 
    822 	/* get the very first run message */
    823 	if (EVTAG_ARRAY_GET(msg2, run, 0, &run) == -1) {
    824 		tt_abort_msg("Failed to get run msg.");
    825 	} else {
    826 		/* verify the notes */
    827 		char *note_one, *note_two;
    828 		ev_uint64_t large_number;
    829 		ev_uint32_t short_number;
    830 
    831 		if (EVTAG_ARRAY_LEN(run, notes) != 2) {
    832 			tt_abort_msg("Wrong number of note strings.");
    833 		}
    834 
    835 		if (EVTAG_ARRAY_GET(run, notes, 0, &note_one) == -1 ||
    836 		    EVTAG_ARRAY_GET(run, notes, 1, &note_two) == -1) {
    837 			tt_abort_msg("Could not get note strings.");
    838 		}
    839 
    840 		if (strcmp(note_one, "this is my note") ||
    841 		    strcmp(note_two, "pps")) {
    842 			tt_abort_msg("Incorrect note strings encoded.");
    843 		}
    844 
    845 		if (EVTAG_GET(run, large_number, &large_number) == -1 ||
    846 		    large_number != 0xdead0a0bcafebeefLL) {
    847 			tt_abort_msg("Incorrrect large_number.");
    848 		}
    849 
    850 		if (EVTAG_ARRAY_LEN(run, other_numbers) != 2) {
    851 			tt_abort_msg("Wrong number of other_numbers.");
    852 		}
    853 
    854 		if (EVTAG_ARRAY_GET(
    855 			    run, other_numbers, 0, &short_number) == -1) {
    856 			tt_abort_msg("Could not get short number.");
    857 		}
    858 		tt_uint_op(short_number, ==, 0xdead0a0b);
    859 
    860 	}
    861 	tt_int_op(EVTAG_ARRAY_LEN(attack, how_often), ==, 3);
    862 
    863 	for (i = 0; i < 3; ++i) {
    864 		ev_uint32_t res;
    865 		if (EVTAG_ARRAY_GET(attack, how_often, i, &res) == -1) {
    866 			TT_DIE(("Cannot get %dth how_often msg.", i));
    867 		}
    868 		if ((int)res != i) {
    869 			TT_DIE(("Wrong message encoded %d != %d", i, res));
    870 		}
    871 	}
    872 
    873 	test_ok = 1;
    874 end:
    875 	if (msg)
    876 		msg_free(msg);
    877 	if (msg2)
    878 		msg_free(msg2);
    879 	if (tmp)
    880 		evbuffer_free(tmp);
    881 }
    882 
    883 #define RPC_LEGACY(name)						\
    884 	{ #name, run_legacy_test_fn, TT_FORK|TT_NEED_BASE|TT_LEGACY,	\
    885 		    &legacy_setup,					\
    886 		    rpc_##name }
    887 #else
    888 /* NO_PYTHON_EXISTS */
    889 
    890 #define RPC_LEGACY(name) \
    891 	{ #name, NULL, TT_SKIP, NULL, NULL }
    892 
    893 #endif
    894 
    895 struct testcase_t rpc_testcases[] = {
    896 	RPC_LEGACY(basic_test),
    897 	RPC_LEGACY(basic_message),
    898 	RPC_LEGACY(basic_client),
    899 	RPC_LEGACY(basic_queued_client),
    900 	RPC_LEGACY(basic_client_with_pause),
    901 	RPC_LEGACY(client_timeout),
    902 	RPC_LEGACY(test),
    903 
    904 	END_OF_TESTCASES,
    905 };
    906