test_oos.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /* Copyright (c) 2016, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /* Unit tests for OOS handler */
  4. #define CONNECTION_PRIVATE
  5. #include "or.h"
  6. #include "config.h"
  7. #include "connection.h"
  8. #include "main.h"
  9. #include "test.h"
  10. static or_options_t mock_options;
  11. static void
  12. reset_options_mock(void)
  13. {
  14. memset(&mock_options, 0, sizeof(or_options_t));
  15. }
  16. static const or_options_t *
  17. mock_get_options(void)
  18. {
  19. return &mock_options;
  20. }
  21. static int moribund_calls = 0;
  22. static int moribund_conns = 0;
  23. static int
  24. mock_connection_count_moribund(void)
  25. {
  26. ++moribund_calls;
  27. return moribund_conns;
  28. }
  29. /*
  30. * For unit test purposes it's sufficient to tell that
  31. * kill_conn_list_for_oos() was called with an approximately
  32. * sane argument; it's just the thing we returned from the
  33. * mock for pick_oos_victims().
  34. */
  35. static int kill_conn_list_calls = 0;
  36. static int kill_conn_list_killed = 0;
  37. static void
  38. kill_conn_list_mock(smartlist_t *conns)
  39. {
  40. ++kill_conn_list_calls;
  41. tt_assert(conns != NULL);
  42. kill_conn_list_killed += smartlist_len(conns);
  43. done:
  44. return;
  45. }
  46. static int pick_oos_mock_calls = 0;
  47. static int pick_oos_mock_fail = 0;
  48. static int pick_oos_mock_last_n = 0;
  49. static smartlist_t *
  50. pick_oos_victims_mock(int n)
  51. {
  52. smartlist_t *l;
  53. int i;
  54. ++pick_oos_mock_calls;
  55. tt_int_op(n, OP_GT, 0);
  56. if (!pick_oos_mock_fail) {
  57. /*
  58. * connection_handle_oos() just passes the list onto
  59. * kill_conn_list_for_oos(); we don't need to simulate
  60. * its content for this mock, just its existence, but
  61. * we do need to check the parameter.
  62. */
  63. l = smartlist_new();
  64. for (i = 0; i < n; ++i) smartlist_add(l, NULL);
  65. } else {
  66. l = NULL;
  67. }
  68. pick_oos_mock_last_n = n;
  69. done:
  70. return l;
  71. }
  72. /** Unit test for the logic in connection_handle_oos(), which is concerned
  73. * with comparing thresholds and connection counts to decide if an OOS has
  74. * occurred and if so, how many connections to try to kill, and then using
  75. * pick_oos_victims() and kill_conn_list_for_oos() to carry out its grim
  76. * duty.
  77. */
  78. static void
  79. test_oos_connection_handle_oos(void *arg)
  80. {
  81. (void)arg;
  82. /* Set up mocks */
  83. reset_options_mock();
  84. /* OOS handling is only sensitive to these fields */
  85. mock_options.ConnLimit = 32;
  86. mock_options.ConnLimit_ = 64;
  87. mock_options.ConnLimit_high_thresh = 60;
  88. mock_options.ConnLimit_low_thresh = 50;
  89. MOCK(get_options, mock_get_options);
  90. moribund_calls = 0;
  91. moribund_conns = 0;
  92. MOCK(connection_count_moribund, mock_connection_count_moribund);
  93. kill_conn_list_calls = 0;
  94. kill_conn_list_killed = 0;
  95. MOCK(kill_conn_list_for_oos, kill_conn_list_mock);
  96. pick_oos_mock_calls = 0;
  97. pick_oos_mock_fail = 0;
  98. MOCK(pick_oos_victims, pick_oos_victims_mock);
  99. /* No OOS case */
  100. connection_handle_oos(50, 0);
  101. tt_int_op(moribund_calls, OP_EQ, 0);
  102. tt_int_op(pick_oos_mock_calls, OP_EQ, 0);
  103. tt_int_op(kill_conn_list_calls, OP_EQ, 0);
  104. /* OOS from socket count, nothing moribund */
  105. connection_handle_oos(62, 0);
  106. tt_int_op(moribund_calls, OP_EQ, 1);
  107. tt_int_op(pick_oos_mock_calls, OP_EQ, 1);
  108. /* 12 == 62 - ConnLimit_low_thresh */
  109. tt_int_op(pick_oos_mock_last_n, OP_EQ, 12);
  110. tt_int_op(kill_conn_list_calls, OP_EQ, 1);
  111. tt_int_op(kill_conn_list_killed, OP_EQ, 12);
  112. /* OOS from socket count, some are moribund */
  113. kill_conn_list_killed = 0;
  114. moribund_conns = 5;
  115. connection_handle_oos(62, 0);
  116. tt_int_op(moribund_calls, OP_EQ, 2);
  117. tt_int_op(pick_oos_mock_calls, OP_EQ, 2);
  118. /* 7 == 62 - ConnLimit_low_thresh - moribund_conns */
  119. tt_int_op(pick_oos_mock_last_n, OP_EQ, 7);
  120. tt_int_op(kill_conn_list_calls, OP_EQ, 2);
  121. tt_int_op(kill_conn_list_killed, OP_EQ, 7);
  122. /* OOS from socket count, but pick fails */
  123. kill_conn_list_killed = 0;
  124. moribund_conns = 0;
  125. pick_oos_mock_fail = 1;
  126. connection_handle_oos(62, 0);
  127. tt_int_op(moribund_calls, OP_EQ, 3);
  128. tt_int_op(pick_oos_mock_calls, OP_EQ, 3);
  129. tt_int_op(kill_conn_list_calls, OP_EQ, 2);
  130. tt_int_op(kill_conn_list_killed, OP_EQ, 0);
  131. pick_oos_mock_fail = 0;
  132. /*
  133. * OOS from socket count with so many moribund conns
  134. * we have none to kill.
  135. */
  136. kill_conn_list_killed = 0;
  137. moribund_conns = 15;
  138. connection_handle_oos(62, 0);
  139. tt_int_op(moribund_calls, OP_EQ, 4);
  140. tt_int_op(pick_oos_mock_calls, OP_EQ, 3);
  141. tt_int_op(kill_conn_list_calls, OP_EQ, 2);
  142. /*
  143. * OOS from socket exhaustion; OOS handler will try to
  144. * kill 1/10 (5) of the connections.
  145. */
  146. kill_conn_list_killed = 0;
  147. moribund_conns = 0;
  148. connection_handle_oos(50, 1);
  149. tt_int_op(moribund_calls, OP_EQ, 5);
  150. tt_int_op(pick_oos_mock_calls, OP_EQ, 4);
  151. tt_int_op(kill_conn_list_calls, OP_EQ, 3);
  152. tt_int_op(kill_conn_list_killed, OP_EQ, 5);
  153. /* OOS from socket exhaustion with moribund conns */
  154. kill_conn_list_killed = 0;
  155. moribund_conns = 2;
  156. connection_handle_oos(50, 1);
  157. tt_int_op(moribund_calls, OP_EQ, 6);
  158. tt_int_op(pick_oos_mock_calls, OP_EQ, 5);
  159. tt_int_op(kill_conn_list_calls, OP_EQ, 4);
  160. tt_int_op(kill_conn_list_killed, OP_EQ, 3);
  161. /* OOS from socket exhaustion with many moribund conns */
  162. kill_conn_list_killed = 0;
  163. moribund_conns = 7;
  164. connection_handle_oos(50, 1);
  165. tt_int_op(moribund_calls, OP_EQ, 7);
  166. tt_int_op(pick_oos_mock_calls, OP_EQ, 5);
  167. tt_int_op(kill_conn_list_calls, OP_EQ, 4);
  168. /* OOS with both socket exhaustion and above-threshold */
  169. kill_conn_list_killed = 0;
  170. moribund_conns = 0;
  171. connection_handle_oos(62, 1);
  172. tt_int_op(moribund_calls, OP_EQ, 8);
  173. tt_int_op(pick_oos_mock_calls, OP_EQ, 6);
  174. tt_int_op(kill_conn_list_calls, OP_EQ, 5);
  175. tt_int_op(kill_conn_list_killed, OP_EQ, 12);
  176. /*
  177. * OOS with both socket exhaustion and above-threshold with some
  178. * moribund conns
  179. */
  180. kill_conn_list_killed = 0;
  181. moribund_conns = 5;
  182. connection_handle_oos(62, 1);
  183. tt_int_op(moribund_calls, OP_EQ, 9);
  184. tt_int_op(pick_oos_mock_calls, OP_EQ, 7);
  185. tt_int_op(kill_conn_list_calls, OP_EQ, 6);
  186. tt_int_op(kill_conn_list_killed, OP_EQ, 7);
  187. /*
  188. * OOS with both socket exhaustion and above-threshold with many
  189. * moribund conns
  190. */
  191. kill_conn_list_killed = 0;
  192. moribund_conns = 15;
  193. connection_handle_oos(62, 1);
  194. tt_int_op(moribund_calls, OP_EQ, 10);
  195. tt_int_op(pick_oos_mock_calls, OP_EQ, 7);
  196. tt_int_op(kill_conn_list_calls, OP_EQ, 6);
  197. done:
  198. UNMOCK(pick_oos_victims);
  199. UNMOCK(kill_conn_list_for_oos);
  200. UNMOCK(connection_count_moribund);
  201. UNMOCK(get_options);
  202. return;
  203. }
  204. struct testcase_t oos_tests[] = {
  205. { "connection_handle_oos", test_oos_connection_handle_oos,
  206. TT_FORK, NULL, NULL },
  207. END_OF_TESTCASES
  208. };