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