Line data Source code
1 : /* Copyright (c) 2018-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : #define DISPATCH_NEW_PRIVATE
5 : #define DISPATCH_PRIVATE
6 :
7 : #include "test/test.h"
8 :
9 : #include "lib/dispatch/dispatch.h"
10 : #include "lib/dispatch/dispatch_cfg.h"
11 : #include "lib/dispatch/dispatch_st.h"
12 : #include "lib/dispatch/msgtypes.h"
13 :
14 : #include "lib/log/escape.h"
15 : #include "lib/malloc/malloc.h"
16 : #include "lib/string/printf.h"
17 :
18 : #include <stdio.h>
19 : #include <string.h>
20 :
21 : static dispatch_t *dispatcher_in_use=NULL;
22 :
23 : static void
24 1 : test_dispatch_max_in_u16_sl(void *arg)
25 : {
26 1 : (void)arg;
27 1 : smartlist_t *sl = smartlist_new();
28 1 : uint16_t nums[] = { 10, 20, 30 };
29 1 : tt_int_op(-1, OP_EQ, max_in_u16_sl(sl, -1));
30 :
31 1 : smartlist_add(sl, NULL);
32 1 : tt_int_op(-1, OP_EQ, max_in_u16_sl(sl, -1));
33 :
34 1 : smartlist_add(sl, &nums[1]);
35 1 : tt_int_op(20, OP_EQ, max_in_u16_sl(sl, -1));
36 :
37 1 : smartlist_add(sl, &nums[0]);
38 1 : tt_int_op(20, OP_EQ, max_in_u16_sl(sl, -1));
39 :
40 1 : smartlist_add(sl, NULL);
41 1 : tt_int_op(20, OP_EQ, max_in_u16_sl(sl, -1));
42 :
43 1 : smartlist_add(sl, &nums[2]);
44 1 : tt_int_op(30, OP_EQ, max_in_u16_sl(sl, -1));
45 :
46 1 : done:
47 1 : smartlist_free(sl);
48 1 : }
49 :
50 : /* Construct an empty dispatch_t. */
51 : static void
52 1 : test_dispatch_empty(void *arg)
53 : {
54 1 : (void)arg;
55 :
56 1 : dispatch_t *d=NULL;
57 1 : dispatch_cfg_t *cfg=NULL;
58 :
59 1 : cfg = dcfg_new();
60 1 : d = dispatch_new(cfg);
61 1 : tt_assert(d);
62 :
63 1 : done:
64 1 : dispatch_free(d);
65 1 : dcfg_free(cfg);
66 1 : }
67 :
68 : static int total_recv1_simple = 0;
69 : static int total_recv2_simple = 0;
70 :
71 : static void
72 1 : simple_recv1(const msg_t *m)
73 : {
74 1 : total_recv1_simple += m->aux_data__.u64;
75 1 : }
76 :
77 : static char *recv2_received = NULL;
78 :
79 : static void
80 2 : simple_recv2(const msg_t *m)
81 : {
82 2 : tor_free(recv2_received);
83 2 : recv2_received = dispatch_fmt_msg_data(dispatcher_in_use, m);
84 :
85 2 : total_recv2_simple += m->aux_data__.u64*10;
86 2 : }
87 :
88 : /* Construct a dispatch_t with two messages, make sure that they both get
89 : * delivered. */
90 : static void
91 1 : test_dispatch_simple(void *arg)
92 : {
93 1 : (void)arg;
94 :
95 1 : dispatch_t *d=NULL;
96 1 : dispatch_cfg_t *cfg=NULL;
97 1 : int r;
98 :
99 1 : cfg = dcfg_new();
100 1 : r = dcfg_msg_set_type(cfg,0,0);
101 1 : r += dcfg_msg_set_chan(cfg,0,0);
102 1 : r += dcfg_add_recv(cfg,0,1,simple_recv1);
103 1 : r += dcfg_msg_set_type(cfg,1,0);
104 1 : r += dcfg_msg_set_chan(cfg,1,0);
105 1 : r += dcfg_add_recv(cfg,1,1,simple_recv2);
106 1 : r += dcfg_add_recv(cfg,1,1,simple_recv2); /* second copy */
107 1 : tt_int_op(r, OP_EQ, 0);
108 :
109 1 : d = dispatch_new(cfg);
110 1 : tt_assert(d);
111 1 : dispatcher_in_use = d;
112 :
113 1 : msg_aux_data_t data = {.u64 = 7};
114 1 : r = dispatch_send(d, 99, 0, 0, 0, data);
115 1 : tt_int_op(r, OP_EQ, 0);
116 1 : tt_int_op(total_recv1_simple, OP_EQ, 0);
117 :
118 1 : r = dispatch_flush(d, 0, INT_MAX);
119 1 : tt_int_op(r, OP_EQ, 0);
120 1 : tt_int_op(total_recv1_simple, OP_EQ, 7);
121 1 : tt_int_op(total_recv2_simple, OP_EQ, 0);
122 :
123 1 : total_recv1_simple = 0;
124 1 : r = dispatch_send(d, 99, 0, 1, 0, data);
125 1 : tt_int_op(r, OP_EQ, 0);
126 1 : r = dispatch_flush(d, 0, INT_MAX);
127 1 : tt_int_op(total_recv1_simple, OP_EQ, 0);
128 1 : tt_int_op(total_recv2_simple, OP_EQ, 140);
129 :
130 1 : tt_str_op(recv2_received, OP_EQ, "<>"); // no format function was set.
131 :
132 1 : done:
133 1 : dispatch_free(d);
134 1 : dcfg_free(cfg);
135 1 : tor_free(recv2_received);
136 1 : }
137 :
138 : /* Construct a dispatch_t with a message and no receiver; make sure that it
139 : * gets dropped properly. */
140 : static void
141 1 : test_dispatch_no_recipient(void *arg)
142 : {
143 1 : (void)arg;
144 :
145 1 : dispatch_t *d=NULL;
146 1 : dispatch_cfg_t *cfg=NULL;
147 1 : int r;
148 :
149 1 : cfg = dcfg_new();
150 1 : r = dcfg_msg_set_type(cfg,0,0);
151 1 : r += dcfg_msg_set_chan(cfg,0,0);
152 1 : tt_int_op(r, OP_EQ, 0);
153 :
154 1 : d = dispatch_new(cfg);
155 1 : tt_assert(d);
156 1 : dispatcher_in_use = d;
157 :
158 1 : msg_aux_data_t data = { .u64 = 7};
159 1 : r = dispatch_send(d, 99, 0, 0, 0, data);
160 1 : tt_int_op(r, OP_EQ, 0);
161 :
162 1 : r = dispatch_flush(d, 0, INT_MAX);
163 1 : tt_int_op(r, OP_EQ, 0);
164 :
165 1 : done:
166 1 : dispatch_free(d);
167 1 : dcfg_free(cfg);
168 1 : }
169 :
170 : struct coord_t { int x; int y; };
171 : static void
172 1 : free_coord(msg_aux_data_t d)
173 : {
174 1 : tor_free(d.ptr);
175 1 : }
176 : static char *
177 3 : fmt_coord(msg_aux_data_t d)
178 : {
179 3 : char *v;
180 3 : struct coord_t *c = d.ptr;
181 3 : tor_asprintf(&v, "[%d, %d]", c->x, c->y);
182 3 : return v;
183 : }
184 : static dispatch_typefns_t coord_fns = {
185 : .fmt_fn = fmt_coord,
186 : .free_fn = free_coord,
187 : };
188 : static void
189 1 : alert_run_immediate(dispatch_t *d, channel_id_t ch, void *arg)
190 : {
191 1 : (void)arg;
192 1 : dispatch_flush(d, ch, INT_MAX);
193 1 : }
194 :
195 : static char *received_data=NULL;
196 :
197 : static void
198 1 : recv_typed_data(const msg_t *m)
199 : {
200 1 : tor_free(received_data);
201 1 : received_data = dispatch_fmt_msg_data(dispatcher_in_use, m);
202 1 : }
203 :
204 : static void
205 1 : test_dispatch_with_types(void *arg)
206 : {
207 1 : (void)arg;
208 :
209 1 : dispatch_t *d=NULL;
210 1 : dispatch_cfg_t *cfg=NULL;
211 1 : int r;
212 :
213 1 : cfg = dcfg_new();
214 1 : r = dcfg_msg_set_type(cfg,5,3);
215 1 : r += dcfg_msg_set_chan(cfg,5,2);
216 1 : r += dcfg_add_recv(cfg,5,0,recv_typed_data);
217 1 : r += dcfg_type_set_fns(cfg,3,&coord_fns);
218 1 : tt_int_op(r, OP_EQ, 0);
219 :
220 1 : d = dispatch_new(cfg);
221 1 : tt_assert(d);
222 1 : dispatcher_in_use = d;
223 :
224 : /* Make this message get run immediately. */
225 1 : r = dispatch_set_alert_fn(d, 2, alert_run_immediate, NULL);
226 1 : tt_int_op(r, OP_EQ, 0);
227 :
228 1 : struct coord_t *xy = tor_malloc(sizeof(*xy));
229 1 : xy->x = 13;
230 1 : xy->y = 37;
231 1 : msg_aux_data_t data = {.ptr = xy};
232 1 : r = dispatch_send(d, 99/*sender*/, 2/*channel*/, 5/*msg*/, 3/*type*/, data);
233 1 : tt_int_op(r, OP_EQ, 0);
234 1 : tt_str_op(received_data, OP_EQ, "[13, 37]");
235 :
236 1 : done:
237 1 : dispatch_free(d);
238 1 : dcfg_free(cfg);
239 1 : tor_free(received_data);
240 1 : dispatcher_in_use = NULL;
241 1 : }
242 :
243 : static void
244 1 : test_dispatch_bad_type_setup(void *arg)
245 : {
246 1 : (void)arg;
247 1 : static dispatch_typefns_t fns;
248 1 : dispatch_cfg_t *cfg = dcfg_new();
249 :
250 1 : tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &coord_fns));
251 :
252 1 : fns = coord_fns;
253 1 : fns.fmt_fn = NULL;
254 1 : tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
255 :
256 1 : fns = coord_fns;
257 1 : fns.free_fn = NULL;
258 1 : tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
259 :
260 1 : fns = coord_fns;
261 1 : tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
262 :
263 1 : done:
264 1 : dcfg_free(cfg);
265 1 : }
266 :
267 : #define T(name) \
268 : { #name, test_dispatch_ ## name, TT_FORK, NULL, NULL }
269 :
270 : struct testcase_t dispatch_tests[] = {
271 : T(max_in_u16_sl),
272 : T(empty),
273 : T(simple),
274 : T(no_recipient),
275 : T(with_types),
276 : T(bad_type_setup),
277 : END_OF_TESTCASES
278 : };
|