Merge pull request #10527 from qzhuyan/test/william/test-use-os-selected-port

fix(test): avoid port collision
This commit is contained in:
William Yang 2023-04-26 13:39:36 +02:00 committed by GitHub
commit 15fe445c66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 26 deletions

View File

@ -59,7 +59,8 @@
read_schema_configs/2, read_schema_configs/2,
render_config_file/2, render_config_file/2,
wait_for/4, wait_for/4,
wait_mqtt_payload/1 wait_mqtt_payload/1,
select_free_port/1
]). ]).
-export([ -export([
@ -1242,3 +1243,34 @@ get_or_spawn_janitor() ->
on_exit(Fun) -> on_exit(Fun) ->
Janitor = get_or_spawn_janitor(), Janitor = get_or_spawn_janitor(),
ok = emqx_test_janitor:push_on_exit_callback(Janitor, Fun). ok = emqx_test_janitor:push_on_exit_callback(Janitor, Fun).
%%-------------------------------------------------------------------------------
%% Select a free transport port from the OS
%%-------------------------------------------------------------------------------
%% @doc get unused port from OS
-spec select_free_port(tcp | udp | ssl | quic) -> inets:port_number().
select_free_port(tcp) ->
select_free_port(gen_tcp, listen);
select_free_port(udp) ->
select_free_port(gen_udp, open);
select_free_port(ssl) ->
select_free_port(tcp);
select_free_port(quic) ->
select_free_port(udp).
select_free_port(GenModule, Fun) when
GenModule == gen_tcp orelse
GenModule == gen_udp
->
{ok, S} = GenModule:Fun(0, [{reuseaddr, true}]),
{ok, Port} = inet:port(S),
ok = GenModule:close(S),
case os:type() of
{unix, darwin} ->
%% in MacOS, still get address_in_use after close port
timer:sleep(500);
_ ->
skip
end,
ct:pal("Select free OS port: ~p", [Port]),
Port.

View File

@ -47,13 +47,14 @@ init_per_testcase(Case, Config) when
Case =:= t_max_conns_tcp; Case =:= t_current_conns_tcp Case =:= t_max_conns_tcp; Case =:= t_current_conns_tcp
-> ->
catch emqx_config_handler:stop(), catch emqx_config_handler:stop(),
Port = emqx_common_test_helpers:select_free_port(tcp),
{ok, _} = emqx_config_handler:start_link(), {ok, _} = emqx_config_handler:start_link(),
PrevListeners = emqx_config:get([listeners], #{}), PrevListeners = emqx_config:get([listeners], #{}),
PureListeners = remove_default_limiter(PrevListeners), PureListeners = remove_default_limiter(PrevListeners),
PureListeners2 = PureListeners#{ PureListeners2 = PureListeners#{
tcp => #{ tcp => #{
listener_test => #{ listener_test => #{
bind => {"127.0.0.1", 9999}, bind => {"127.0.0.1", Port},
max_connections => 4321, max_connections => 4321,
limiter => #{} limiter => #{}
} }
@ -63,19 +64,20 @@ init_per_testcase(Case, Config) when
ok = emqx_listeners:start(), ok = emqx_listeners:start(),
[ [
{prev_listener_conf, PrevListeners} {prev_listener_conf, PrevListeners},
{tcp_port, Port}
| Config | Config
]; ];
init_per_testcase(t_wss_conn, Config) -> init_per_testcase(t_wss_conn, Config) ->
catch emqx_config_handler:stop(), catch emqx_config_handler:stop(),
Port = emqx_common_test_helpers:select_free_port(ssl),
{ok, _} = emqx_config_handler:start_link(), {ok, _} = emqx_config_handler:start_link(),
PrevListeners = emqx_config:get([listeners], #{}), PrevListeners = emqx_config:get([listeners], #{}),
PureListeners = remove_default_limiter(PrevListeners), PureListeners = remove_default_limiter(PrevListeners),
PureListeners2 = PureListeners#{ PureListeners2 = PureListeners#{
wss => #{ wss => #{
listener_test => #{ listener_test => #{
bind => {{127, 0, 0, 1}, 9998}, bind => {{127, 0, 0, 1}, Port},
limiter => #{}, limiter => #{},
ssl_options => #{ ssl_options => #{
cacertfile => ?CERTS_PATH("cacert.pem"), cacertfile => ?CERTS_PATH("cacert.pem"),
@ -89,7 +91,8 @@ init_per_testcase(t_wss_conn, Config) ->
ok = emqx_listeners:start(), ok = emqx_listeners:start(),
[ [
{prev_listener_conf, PrevListeners} {prev_listener_conf, PrevListeners},
{wss_port, Port}
| Config | Config
]; ];
init_per_testcase(_, Config) -> init_per_testcase(_, Config) ->
@ -171,20 +174,30 @@ t_restart_listeners_with_hibernate_after_disabled(_Config) ->
ok = emqx_listeners:stop(), ok = emqx_listeners:stop(),
emqx_config:put([listeners], OldLConf). emqx_config:put([listeners], OldLConf).
t_max_conns_tcp(_) -> t_max_conns_tcp(Config) ->
%% Note: Using a string representation for the bind address like %% Note: Using a string representation for the bind address like
%% "127.0.0.1" does not work %% "127.0.0.1" does not work
?assertEqual(4321, emqx_listeners:max_conns('tcp:listener_test', {{127, 0, 0, 1}, 9999})). ?assertEqual(
4321,
emqx_listeners:max_conns('tcp:listener_test', {{127, 0, 0, 1}, ?config(tcp_port, Config)})
).
t_current_conns_tcp(_) -> t_current_conns_tcp(Config) ->
?assertEqual(0, emqx_listeners:current_conns('tcp:listener_test', {{127, 0, 0, 1}, 9999})). ?assertEqual(
0,
emqx_listeners:current_conns('tcp:listener_test', {
{127, 0, 0, 1}, ?config(tcp_port, Config)
})
).
t_wss_conn(_) -> t_wss_conn(Config) ->
{ok, Socket} = ssl:connect({127, 0, 0, 1}, 9998, [{verify, verify_none}], 1000), {ok, Socket} = ssl:connect(
{127, 0, 0, 1}, ?config(wss_port, Config), [{verify, verify_none}], 1000
),
ok = ssl:close(Socket). ok = ssl:close(Socket).
t_quic_conn(Config) -> t_quic_conn(Config) ->
Port = 24568, Port = emqx_common_test_helpers:select_free_port(quic),
DataDir = ?config(data_dir, Config), DataDir = ?config(data_dir, Config),
SSLOpts = #{ SSLOpts = #{
password => ?SERVER_KEY_PASSWORD, password => ?SERVER_KEY_PASSWORD,
@ -207,7 +220,7 @@ t_quic_conn(Config) ->
emqx_listeners:stop_listener(quic, ?FUNCTION_NAME, #{bind => Port}). emqx_listeners:stop_listener(quic, ?FUNCTION_NAME, #{bind => Port}).
t_ssl_password_cert(Config) -> t_ssl_password_cert(Config) ->
Port = 24568, Port = emqx_common_test_helpers:select_free_port(ssl),
DataDir = ?config(data_dir, Config), DataDir = ?config(data_dir, Config),
SSLOptsPWD = #{ SSLOptsPWD = #{
password => ?SERVER_KEY_PASSWORD, password => ?SERVER_KEY_PASSWORD,

View File

@ -2026,18 +2026,7 @@ stop_emqx() ->
%% select a random port picked by OS %% select a random port picked by OS
-spec select_port() -> inet:port_number(). -spec select_port() -> inet:port_number().
select_port() -> select_port() ->
{ok, S} = gen_udp:open(0, [{reuseaddr, true}]), emqx_common_test_helpers:select_free_port(quic).
{ok, {_, Port}} = inet:sockname(S),
gen_udp:close(S),
case os:type() of
{unix, darwin} ->
%% in MacOS, still get address_in_use after close port
timer:sleep(500);
_ ->
skip
end,
ct:pal("select port: ~p", [Port]),
Port.
-spec via_stream({quic, quicer:connection_handle(), quicer:stream_handle()}) -> -spec via_stream({quic, quicer:connection_handle(), quicer:stream_handle()}) ->
quicer:stream_handle(). quicer:stream_handle().