test_dispatch.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /* Copyright (c) 2018, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. #define DISPATCH_PRIVATE
  4. #include "test/test.h"
  5. #include "lib/dispatch/dispatch.h"
  6. #include "lib/dispatch/dispatch_cfg.h"
  7. #include "lib/dispatch/dispatch_st.h"
  8. #include "lib/dispatch/msgtypes.h"
  9. #include "lib/log/escape.h"
  10. #include "lib/malloc/malloc.h"
  11. #include "lib/string/printf.h"
  12. #include <stdio.h>
  13. #include <string.h>
  14. static dispatch_t *dispatcher_in_use=NULL;
  15. /* Construct an empty dispatch_t. */
  16. static void
  17. test_dispatch_empty(void *arg)
  18. {
  19. (void)arg;
  20. dispatch_t *d=NULL;
  21. dispatch_cfg_t *cfg=NULL;
  22. cfg = dcfg_new();
  23. d = dispatch_new(cfg);
  24. tt_assert(d);
  25. done:
  26. dispatch_free(d);
  27. dcfg_free(cfg);
  28. }
  29. static int total_recv1_simple = 0;
  30. static int total_recv2_simple = 0;
  31. static void
  32. simple_recv1(const msg_t *m)
  33. {
  34. total_recv1_simple += m->aux_data__.u64;
  35. }
  36. static char *recv2_received = NULL;
  37. static void
  38. simple_recv2(const msg_t *m)
  39. {
  40. tor_free(recv2_received);
  41. recv2_received = dispatch_fmt_msg_data(dispatcher_in_use, m);
  42. total_recv2_simple += m->aux_data__.u64*10;
  43. }
  44. /* Construct a dispatch_t with two messages, make sure that they both get
  45. * delivered. */
  46. static void
  47. test_dispatch_simple(void *arg)
  48. {
  49. (void)arg;
  50. dispatch_t *d=NULL;
  51. dispatch_cfg_t *cfg=NULL;
  52. int r;
  53. cfg = dcfg_new();
  54. r = dcfg_msg_set_type(cfg,0,0);
  55. r += dcfg_msg_set_chan(cfg,0,0);
  56. r += dcfg_add_recv(cfg,0,1,simple_recv1);
  57. r += dcfg_msg_set_type(cfg,1,0);
  58. r += dcfg_msg_set_chan(cfg,1,0);
  59. r += dcfg_add_recv(cfg,1,1,simple_recv2);
  60. r += dcfg_add_recv(cfg,1,1,simple_recv2); /* second copy */
  61. tt_int_op(r, OP_EQ, 0);
  62. d = dispatch_new(cfg);
  63. tt_assert(d);
  64. dispatcher_in_use = d;
  65. msg_aux_data_t data = {.u64 = 7};
  66. r = dispatch_send(d, 99, 0, 0, 0, data);
  67. tt_int_op(r, OP_EQ, 0);
  68. tt_int_op(total_recv1_simple, OP_EQ, 0);
  69. r = dispatch_flush(d, 0, INT_MAX);
  70. tt_int_op(r, OP_EQ, 0);
  71. tt_int_op(total_recv1_simple, OP_EQ, 7);
  72. tt_int_op(total_recv2_simple, OP_EQ, 0);
  73. total_recv1_simple = 0;
  74. r = dispatch_send(d, 99, 0, 1, 0, data);
  75. tt_int_op(r, OP_EQ, 0);
  76. r = dispatch_flush(d, 0, INT_MAX);
  77. tt_int_op(total_recv1_simple, OP_EQ, 0);
  78. tt_int_op(total_recv2_simple, OP_EQ, 140);
  79. tt_str_op(recv2_received, OP_EQ, "<>"); // no format function was set.
  80. done:
  81. dispatch_free(d);
  82. dcfg_free(cfg);
  83. tor_free(recv2_received);
  84. }
  85. /* Construct a dispatch_t with a message and no reciever; make sure that it
  86. * gets dropped properly. */
  87. static void
  88. test_dispatch_no_recipient(void *arg)
  89. {
  90. (void)arg;
  91. dispatch_t *d=NULL;
  92. dispatch_cfg_t *cfg=NULL;
  93. int r;
  94. cfg = dcfg_new();
  95. r = dcfg_msg_set_type(cfg,0,0);
  96. r += dcfg_msg_set_chan(cfg,0,0);
  97. tt_int_op(r, OP_EQ, 0);
  98. d = dispatch_new(cfg);
  99. tt_assert(d);
  100. dispatcher_in_use = d;
  101. msg_aux_data_t data = { .u64 = 7};
  102. r = dispatch_send(d, 99, 0, 0, 0, data);
  103. tt_int_op(r, OP_EQ, 0);
  104. r = dispatch_flush(d, 0, INT_MAX);
  105. tt_int_op(r, OP_EQ, 0);
  106. done:
  107. dispatch_free(d);
  108. dcfg_free(cfg);
  109. }
  110. struct coord { int x; int y; };
  111. static void
  112. free_coord(msg_aux_data_t d)
  113. {
  114. tor_free(d.ptr);
  115. }
  116. static char *
  117. fmt_coord(msg_aux_data_t d)
  118. {
  119. char *v;
  120. struct coord *c = d.ptr;
  121. tor_asprintf(&v, "[%d, %d]", c->x, c->y);
  122. return v;
  123. }
  124. static dispatch_typefns_t coord_fns = {
  125. .fmt_fn = fmt_coord,
  126. .free_fn = free_coord,
  127. };
  128. static void
  129. alert_run_immediate(dispatch_t *d, channel_id_t ch, void *arg)
  130. {
  131. (void)arg;
  132. dispatch_flush(d, ch, INT_MAX);
  133. }
  134. static char *received_data=NULL;
  135. static void
  136. recv_typed_data(const msg_t *m)
  137. {
  138. tor_free(received_data);
  139. received_data = dispatch_fmt_msg_data(dispatcher_in_use, m);
  140. }
  141. static void
  142. test_dispatch_with_types(void *arg)
  143. {
  144. (void)arg;
  145. dispatch_t *d=NULL;
  146. dispatch_cfg_t *cfg=NULL;
  147. int r;
  148. cfg = dcfg_new();
  149. r = dcfg_msg_set_type(cfg,5,3);
  150. r += dcfg_msg_set_chan(cfg,5,2);
  151. r += dcfg_add_recv(cfg,5,0,recv_typed_data);
  152. r += dcfg_type_set_fns(cfg,3,&coord_fns);
  153. tt_int_op(r, OP_EQ, 0);
  154. d = dispatch_new(cfg);
  155. tt_assert(d);
  156. dispatcher_in_use = d;
  157. /* Make this message get run immediately. */
  158. r = dispatch_set_alert_fn(d, 2, alert_run_immediate, NULL);
  159. tt_int_op(r, OP_EQ, 0);
  160. struct coord *xy = tor_malloc(sizeof(*xy));
  161. xy->x = 13;
  162. xy->y = 37;
  163. msg_aux_data_t data = {.ptr = xy};
  164. r = dispatch_send(d, 99/*sender*/, 2/*channel*/, 5/*msg*/, 3/*type*/, data);
  165. tt_int_op(r, OP_EQ, 0);
  166. tt_str_op(received_data, OP_EQ, "[13, 37]");
  167. done:
  168. dispatch_free(d);
  169. dcfg_free(cfg);
  170. tor_free(received_data);
  171. dispatcher_in_use = NULL;
  172. }
  173. static void
  174. test_dispatch_bad_type_setup(void *arg)
  175. {
  176. (void)arg;
  177. static dispatch_typefns_t fns;
  178. dispatch_cfg_t *cfg = dcfg_new();
  179. tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &coord_fns));
  180. fns = coord_fns;
  181. fns.fmt_fn = NULL;
  182. tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
  183. fns = coord_fns;
  184. fns.free_fn = NULL;
  185. tt_int_op(-1, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
  186. fns = coord_fns;
  187. tt_int_op(0, OP_EQ, dcfg_type_set_fns(cfg, 7, &fns));
  188. done:
  189. dcfg_free(cfg);
  190. }
  191. #define T(name) \
  192. { #name, test_dispatch_ ## name, TT_FORK, NULL, NULL }
  193. struct testcase_t dispatch_tests[] = {
  194. T(empty),
  195. T(simple),
  196. T(no_recipient),
  197. T(with_types),
  198. T(bad_type_setup),
  199. END_OF_TESTCASES
  200. };