stampede_SUITE.erl 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. %% Copyright (c) 2019-2021, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(stampede_SUITE).
  15. -compile(export_all).
  16. -compile(nowarn_export_all).
  17. -import(ct_helper, [doc/1]).
  18. -import(ct_helper, [name/0]).
  19. %% ct.
  20. all() ->
  21. [{group, tcp}, {group, tcp_socket}, {group, ssl}].
  22. groups() ->
  23. [
  24. {
  25. tcp,
  26. [],
  27. [
  28. stampede_tcp,
  29. stampede_embedded
  30. ]
  31. },
  32. {
  33. tcp_socket,
  34. [],
  35. [
  36. stampede_tcp,
  37. stampede_embedded
  38. ]
  39. },
  40. {
  41. ssl,
  42. [],
  43. [
  44. stampede_ssl
  45. ]
  46. }
  47. ].
  48. init_per_group(tcp_socket, Config) ->
  49. %% The socket backend for inet/gen_tcp was introduced as an experimental
  50. %% feature in OTP/23.0, and bugs https://bugs.erlang.org/browse/ERL-1284,
  51. %% 1287 and 1293 were solved in OTP/23.1. socket:use_registry/1 first
  52. %% appears in this release.
  53. %% Due to https://bugs.erlang.org/browse/ERL-1401, the socket backend
  54. %% is not working on Windows.
  55. case
  56. os:type() =/= {win32, nt} andalso
  57. code:ensure_loaded(socket) =:= {module, socket} andalso
  58. erlang:function_exported(socket, use_registry, 1)
  59. of
  60. true ->
  61. [{socket_opts, [{inet_backend, socket}]}|Config];
  62. false ->
  63. {skip, "No socket backend support"}
  64. end;
  65. init_per_group(_, Config) ->
  66. Config.
  67. end_per_group(_, _) ->
  68. ok.
  69. init_per_suite(Config) ->
  70. {ok, _} = application:ensure_all_started(ranch),
  71. ok = application:start(stampede),
  72. %% Enable logging of progress reports.
  73. %% They will only be available in the HTML reports by default.
  74. ok = logger:set_primary_config(level, none),
  75. ok = logger:set_module_level(?MODULE, info),
  76. ok = logger:set_application_level(stampede, error),
  77. Config.
  78. end_per_suite(_) ->
  79. ok = application:stop(stampede),
  80. ok = application:stop(ranch).
  81. %% Tests.
  82. stampede_tcp(Config) ->
  83. doc("Start a TCP listener, establish a hundred connections, "
  84. "run stampede, confirm we can still connect."),
  85. %% Start a TCP listener.
  86. Name = name(),
  87. SockOpts = do_get_sockopts(Config),
  88. {ok, _} = ranch:start_listener(Name,
  89. ranch_tcp, #{socket_opts => SockOpts},
  90. echo_protocol, []),
  91. %% Set restart frequency of ranch_sup.
  92. do_set_sup_frequencies([ranch_sup], 999999, 1),
  93. %% Run stampede.
  94. {ok, _} = stampede:start_herd(ranch_stampede, {application, ranch},
  95. #{interval => {100, 100}, before_kill => fun do_log/1}),
  96. %% Establish a hundred connections.
  97. ok = do_connect(100, ranch_tcp, ranch:get_port(Name), 1000),
  98. ok = stampede:activate(ranch_stampede),
  99. timer:sleep(10000),
  100. ok = stampede:stop_herd(ranch_stampede),
  101. timer:sleep(1000),
  102. %% Confirm we can still connect.
  103. ok = do_connect(1, ranch_tcp, ranch:get_port(Name), 1000),
  104. ok = ranch:stop_listener(Name).
  105. stampede_ssl(_) ->
  106. doc("Start a SSL listener, establish a hundred connections, "
  107. "run stampede, confirm we can still connect."),
  108. %% Start a TCP listener.
  109. Name = name(),
  110. {ok, _} = ranch:start_listener(Name,
  111. ranch_ssl, ct_helper:get_certs_from_ets(),
  112. echo_protocol, []),
  113. %% Set restart frequencies of ranch_sup and ssl_sup.
  114. do_set_sup_frequencies([ranch_sup, ssl_sup], 999999, 1),
  115. %% Run stampede.
  116. {ok, _} = stampede:start_herd(ranch_stampede, {application, ranch},
  117. #{interval => {100, 100}, before_kill => fun do_log/1}),
  118. {ok, _} = stampede:start_herd(ssl_stampede, {application, ssl},
  119. #{interval => {100, 100}, before_kill => fun do_log/1}),
  120. %% Establish a hundred connections.
  121. ok = do_connect(100, ranch_ssl, ranch:get_port(Name), 1000),
  122. ok = stampede:activate(ranch_stampede),
  123. ok = stampede:activate(ssl_stampede),
  124. timer:sleep(10000),
  125. ok = stampede:stop_herd(ssl_stampede),
  126. ok = stampede:stop_herd(ranch_stampede),
  127. timer:sleep(1000),
  128. %% Confirm we can still connect.
  129. ok = do_connect(1, ranch_ssl, ranch:get_port(Name), 1000),
  130. ok = ranch:stop_listener(Name).
  131. stampede_embedded(Config) ->
  132. doc("Start an embedded TCP listener, establish a hundred connections, "
  133. "run stampede, confirm we can still connect."),
  134. %% Start embedded listener.
  135. Name = name(),
  136. SockOpts = do_get_sockopts(Config),
  137. {ok, SupPid} = embedded_sup:start_link(),
  138. {ok, _} = embedded_sup:start_listener(SupPid, Name,
  139. ranch_tcp, #{socket_opts => SockOpts}, echo_protocol, []),
  140. %% Set restart frequency of ranch_sup and embedded_sup.
  141. do_set_sup_frequencies([ranch_sup, SupPid], 999999, 1),
  142. %% Run stampede.
  143. {ok, _} = stampede:start_herd(ranch_stampede, {application, ranch},
  144. #{interval => {100, 100}, before_kill => fun do_log/1}),
  145. {ok, _} = stampede:start_herd(embedded_stampede, {supervisor, SupPid},
  146. #{interval => {100, 100}, before_kill => fun do_log/1}),
  147. %% Establish a hundred connections.
  148. ok = do_connect(100, ranch_tcp, ranch:get_port(Name), 1000),
  149. ok = stampede:activate(ranch_stampede),
  150. ok = stampede:activate(embedded_stampede),
  151. timer:sleep(10000),
  152. ok = stampede:stop_herd(ranch_stampede),
  153. ok = stampede:stop_herd(embedded_stampede),
  154. timer:sleep(1000),
  155. %% Confirm we can still connect.
  156. ok = do_connect(1, ranch_tcp, ranch:get_port(Name), 1000),
  157. ok = embedded_sup:stop_listener(SupPid, Name),
  158. embedded_sup:stop(SupPid),
  159. ok.
  160. do_set_sup_frequencies(Sups, Intensity, Period) ->
  161. StateFun = fun (S) -> setelement(7, setelement(6, S, Intensity), Period) end,
  162. _ = [sys:replace_state(Sup, StateFun) || Sup <- Sups],
  163. ok.
  164. do_connect(0, _, _, _) ->
  165. ok;
  166. do_connect(N, Transport, Port, Timeout) ->
  167. {ok, _} = Transport:connect("localhost", Port, [{active, false}], Timeout),
  168. do_connect(N - 1, Transport, Port, Timeout).
  169. do_log(Pid) when is_pid(Pid) ->
  170. ct:log(info, "~p: ~p~n", [Pid, erlang:process_info(Pid)]),
  171. true;
  172. do_log(Port) when is_port(Port) ->
  173. ct:log(info, "~p: ~p~n", [Port, erlang:port_info(Port)]),
  174. true.
  175. do_get_sockopts(Config) ->
  176. proplists:get_value(socket_opts, Config, []).