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