shutdown_SUITE.erl 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. %% Copyright (c) 2013-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(shutdown_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. ct_helper:all(?MODULE).
  22. %% Tests.
  23. brutal_kill(_) ->
  24. doc("Shutdown Ranch listener with shutdown option set to brutal_kill."),
  25. Name = name(),
  26. {ok, ListenerSup} = ranch:start_listener(Name,
  27. ranch_tcp, #{shutdown => brutal_kill},
  28. echo_protocol, []),
  29. Port = ranch:get_port(Name),
  30. ok = do_connect_and_ping(Port),
  31. ListenerSupChildren = supervisor:which_children(ListenerSup),
  32. {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren),
  33. [Pid] = do_get_conn_pids(ConnsSupSup),
  34. true = is_process_alive(Pid),
  35. ok = ranch:stop_listener(Name),
  36. receive after 100 -> ok end,
  37. false = is_process_alive(Pid),
  38. false = is_process_alive(ListenerSup),
  39. {error, _} = gen_tcp:connect("localhost", Port, []),
  40. ok.
  41. infinity(_) ->
  42. doc("Shutdown Ranch listener with shutdown option set to infinity."),
  43. Name = name(),
  44. {ok, ListenerSup} = ranch:start_listener(Name,
  45. ranch_tcp, #{shutdown => infinity},
  46. echo_protocol, []),
  47. Port = ranch:get_port(Name),
  48. ok = do_connect_and_ping(Port),
  49. ListenerSupChildren = supervisor:which_children(ListenerSup),
  50. {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren),
  51. [Pid] = do_get_conn_pids(ConnsSupSup),
  52. true = is_process_alive(Pid),
  53. ok = ranch:stop_listener(Name),
  54. receive after 100 -> ok end,
  55. false = is_process_alive(Pid),
  56. false = is_process_alive(ListenerSup),
  57. {error, _} = gen_tcp:connect("localhost", Port, []),
  58. ok.
  59. infinity_trap_exit(_) ->
  60. doc("Shutdown Ranch listener with shutdown option set to infinity "
  61. "and protocol process trapping exits. The listener must not stop "
  62. "until the protocol process terminates."),
  63. Name = name(),
  64. {ok, ListenerSup} = ranch:start_listener(Name,
  65. ranch_tcp, #{shutdown => infinity},
  66. trap_exit_protocol, []),
  67. Port = ranch:get_port(Name),
  68. ok = do_connect_and_ping(Port),
  69. ListenerSupChildren = supervisor:which_children(ListenerSup),
  70. {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren),
  71. [Pid] = do_get_conn_pids(ConnsSupSup),
  72. true = is_process_alive(Pid),
  73. %% This call will block infinitely.
  74. SpawnPid = spawn(fun() -> ok = ranch:stop_listener(Name) end),
  75. receive after 100 -> ok end,
  76. %% The protocol traps exit signals, and ignore them, so it won't die.
  77. true = is_process_alive(Pid),
  78. %% The listener will stay up forever too.
  79. true = is_process_alive(ListenerSup),
  80. %% We can't connect, though.
  81. {error, _} = gen_tcp:connect("localhost", Port, []),
  82. %% Killing the process unblocks everything.
  83. exit(Pid, kill),
  84. receive after 100 -> ok end,
  85. false = is_process_alive(ListenerSup),
  86. false = is_process_alive(SpawnPid),
  87. ok.
  88. timeout(_) ->
  89. doc("Shutdown Ranch listener with shutdown option set to 500ms."),
  90. Name = name(),
  91. {ok, ListenerSup} = ranch:start_listener(Name,
  92. ranch_tcp, #{shutdown => 500},
  93. echo_protocol, []),
  94. Port = ranch:get_port(Name),
  95. ok = do_connect_and_ping(Port),
  96. ListenerSupChildren = supervisor:which_children(ListenerSup),
  97. {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren),
  98. [Pid] = do_get_conn_pids(ConnsSupSup),
  99. true = is_process_alive(Pid),
  100. ok = ranch:stop_listener(Name),
  101. receive after 100 -> ok end,
  102. false = is_process_alive(Pid),
  103. false = is_process_alive(ListenerSup),
  104. {error, _} = gen_tcp:connect("localhost", Port, []),
  105. ok.
  106. timeout_trap_exit(_) ->
  107. doc("Shutdown Ranch listener with shutdown option set to 500ms "
  108. "and protocol process trapping exits. The listener will only stop "
  109. "after the 500ms timeout."),
  110. Name = name(),
  111. {ok, ListenerSup} = ranch:start_listener(Name,
  112. ranch_tcp, #{shutdown => 500},
  113. trap_exit_protocol, []),
  114. Port = ranch:get_port(Name),
  115. ok = do_connect_and_ping(Port),
  116. ListenerSupChildren = supervisor:which_children(ListenerSup),
  117. {_, ConnsSupSup, _, _} = lists:keyfind(ranch_conns_sup_sup, 1, ListenerSupChildren),
  118. [Pid] = do_get_conn_pids(ConnsSupSup),
  119. true = is_process_alive(Pid),
  120. %% This call will block for the duration of the shutdown.
  121. SpawnPid = spawn(fun() -> ok = ranch:stop_listener(Name) end),
  122. receive after 100 -> ok end,
  123. %% The protocol traps exit signals, and ignore them, so it won't die.
  124. true = is_process_alive(Pid),
  125. %% The listener will stay up for now too.
  126. true = is_process_alive(ListenerSup),
  127. %% We can't connect, though.
  128. {error, _} = gen_tcp:connect("localhost", Port, []),
  129. %% Wait for the timeout to finish and see that everything is killed.
  130. receive after 500 -> ok end,
  131. false = is_process_alive(Pid),
  132. false = is_process_alive(ListenerSup),
  133. false = is_process_alive(SpawnPid),
  134. ok.
  135. do_get_conn_pids(ConnsSupSup) ->
  136. ConnsSups = [ConnsSup ||
  137. {_, ConnsSup, _, _} <- supervisor:which_children(ConnsSupSup)],
  138. ConnChildren = lists:flatten(
  139. [supervisor:which_children(ConnsSup) || ConnsSup <- ConnsSups]),
  140. [ConnPid || {_, ConnPid, _, _} <- ConnChildren].
  141. do_connect_and_ping(Port) ->
  142. {ok, Conn} = gen_tcp:connect("localhost", Port, [binary, {active, false}, {packet, raw}]),
  143. ok = gen_tcp:send(Conn, <<"PING">>),
  144. {ok, <<"PING">>} = gen_tcp:recv(Conn, 4, 1000),
  145. ok.