Jelajahi Sumber

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

fix(test): avoid port collision
William Yang 2 tahun lalu
induk
melakukan
15fe445c66

+ 33 - 1
apps/emqx/test/emqx_common_test_helpers.erl

@@ -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.

+ 26 - 13
apps/emqx/test/emqx_listeners_SUITE.erl

@@ -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(_) ->
-    ?assertEqual(0, emqx_listeners:current_conns('tcp:listener_test', {{127, 0, 0, 1}, 9999})).
+t_current_conns_tcp(Config) ->
+    ?assertEqual(
+        0,
+        emqx_listeners:current_conns('tcp:listener_test', {
+            {127, 0, 0, 1}, ?config(tcp_port, Config)
+        })
+    ).
 
 
-t_wss_conn(_) ->
-    {ok, Socket} = ssl:connect({127, 0, 0, 1}, 9998, [{verify, verify_none}], 1000),
+t_wss_conn(Config) ->
+    {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,

+ 1 - 12
apps/emqx/test/emqx_quic_multistreams_SUITE.erl

@@ -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}]),
-    {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.
+    emqx_common_test_helpers:select_free_port(quic).
 
 
 -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().