]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/sntp/libevent/test/regress_rpc.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / sntp / libevent / test / regress_rpc.c
1 /*
2  * Copyright (c) 2003-2007 Niels Provos <provos@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 };