From 57b1ec13fd46bed369628ad962509e3e39ad83a4 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 08:22:40 +0200 Subject: [PATCH 01/19] Use OTP28/Elixir 1.18 in the pipelines --- .github/workflows/oci-make.yaml | 6 +++--- .github/workflows/peer-discovery-aws.yaml | 6 +++--- .github/workflows/test-authnz.yaml | 2 +- .github/workflows/test-make-target.yaml | 2 +- .github/workflows/test-make.yaml | 17 +++++++++-------- .../workflows/test-management-ui-for-pr.yaml | 2 +- .github/workflows/test-management-ui.yaml | 2 +- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.github/workflows/oci-make.yaml b/.github/workflows/oci-make.yaml index 98353c8aa270..e00c080179bf 100644 --- a/.github/workflows/oci-make.yaml +++ b/.github/workflows/oci-make.yaml @@ -20,7 +20,7 @@ on: # a tag of the erlang image, see https://hub.docker.com/_/erlang for available tags # also used in the setup-beam step (same tag should work for both) description: OTP version (eg. `26`, `26.2.5.6`) - default: 27 + default: 28 build_arm: description: Build for ARM64 as well? type: boolean @@ -36,7 +36,7 @@ jobs: strategy: matrix: otp_version: - - ${{ github.event.inputs.otp_version || '27' }} + - ${{ github.event.inputs.otp_version || '28' }} runs-on: ubuntu-latest outputs: # When dependabot, or a user from a fork, creates PRs, secrets are not injected, and the OCI workflow can't push the image @@ -76,7 +76,7 @@ jobs: fail-fast: false matrix: otp_version: - - ${{ github.event.inputs.otp_version || '27' }} + - ${{ github.event.inputs.otp_version || '28' }} needs: build-package-generic-unix runs-on: ubuntu-latest if: ${{ needs.build-package-generic-unix.outputs.authorized }} == 'true' diff --git a/.github/workflows/peer-discovery-aws.yaml b/.github/workflows/peer-discovery-aws.yaml index f8f643590cd2..fb22f4f2d2b1 100644 --- a/.github/workflows/peer-discovery-aws.yaml +++ b/.github/workflows/peer-discovery-aws.yaml @@ -13,7 +13,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true env: - OTP_VERSION: "27" + OTP_VERSION: "28" jobs: peer-discovery-aws-integration-test: name: Integration Test @@ -48,10 +48,10 @@ jobs: polling-seconds: 60 - name: CONFIGURE OTP & ELIXIR if: steps.authorized.outputs.authorized == 'true' - uses: erlef/setup-beam@v1.17 + uses: erlef/setup-beam@v1 with: otp-version: ${{ env.OTP_VERSION }} - elixir-version: "1.17" + elixir-version: "1.18" - name: SETUP ecs-cli if: steps.authorized.outputs.authorized == 'true' env: diff --git a/.github/workflows/test-authnz.yaml b/.github/workflows/test-authnz.yaml index f9c329c32c0b..132d4938de71 100644 --- a/.github/workflows/test-authnz.yaml +++ b/.github/workflows/test-authnz.yaml @@ -44,7 +44,7 @@ jobs: uses: actions/checkout@v4 - name: Configure OTP & Elixir - uses: erlef/setup-beam@v1.17 + uses: erlef/setup-beam@v1 with: otp-version: ${{ matrix.erlang_version }} elixir-version: ${{ matrix.elixir_version }} diff --git a/.github/workflows/test-make-target.yaml b/.github/workflows/test-make-target.yaml index 9724962ae366..715fb510395a 100644 --- a/.github/workflows/test-make-target.yaml +++ b/.github/workflows/test-make-target.yaml @@ -34,7 +34,7 @@ jobs: run: git fetch --tags - name: SETUP OTP & ELIXIR - uses: erlef/setup-beam@v1.17 + uses: erlef/setup-beam@v1 with: otp-version: ${{ inputs.erlang_version }} elixir-version: ${{ inputs.elixir_version }} diff --git a/.github/workflows/test-make.yaml b/.github/workflows/test-make.yaml index eddf299b536c..7b274228d8ab 100644 --- a/.github/workflows/test-make.yaml +++ b/.github/workflows/test-make.yaml @@ -23,8 +23,9 @@ jobs: erlang_version: - '26' - '27' + - '28' elixir_version: - - '1.17' + - '1.18' # @todo Add macOS and Windows. runs-on: ubuntu-latest timeout-minutes: 60 @@ -36,7 +37,7 @@ jobs: run: git fetch --tags - name: SETUP OTP & ELIXIR - uses: erlef/setup-beam@v1.17 + uses: erlef/setup-beam@v1.19 with: otp-version: ${{ matrix.erlang_version }} elixir-version: ${{ matrix.elixir_version }} @@ -62,9 +63,9 @@ jobs: fail-fast: false matrix: erlang_version: - - '27' + - '28' elixir_version: - - '1.17' + - '1.18' metadata_store: - mnesia - khepri @@ -81,9 +82,9 @@ jobs: fail-fast: false matrix: erlang_version: - - '27' + - '28' elixir_version: - - '1.17' + - '1.18' metadata_store: - mnesia - khepri @@ -100,9 +101,9 @@ jobs: fail-fast: false matrix: erlang_version: # Latest OTP - - '27' + - '28' elixir_version: # Latest Elixir - - '1.17' + - '1.18' uses: ./.github/workflows/test-make-type-check.yaml with: erlang_version: ${{ matrix.erlang_version }} diff --git a/.github/workflows/test-management-ui-for-pr.yaml b/.github/workflows/test-management-ui-for-pr.yaml index 9458be81641e..8fc61046e048 100644 --- a/.github/workflows/test-management-ui-for-pr.yaml +++ b/.github/workflows/test-management-ui-for-pr.yaml @@ -32,7 +32,7 @@ jobs: uses: actions/checkout@v4 - name: Configure OTP & Elixir - uses: erlef/setup-beam@v1.17 + uses: erlef/setup-beam@v1 with: otp-version: ${{ matrix.erlang_version }} elixir-version: ${{ matrix.elixir_version }} diff --git a/.github/workflows/test-management-ui.yaml b/.github/workflows/test-management-ui.yaml index 8a0b9cdc57ff..f5e12c661559 100644 --- a/.github/workflows/test-management-ui.yaml +++ b/.github/workflows/test-management-ui.yaml @@ -36,7 +36,7 @@ jobs: uses: actions/checkout@v4 - name: Configure OTP & Elixir - uses: erlef/setup-beam@v1.17 + uses: erlef/setup-beam@v1 with: otp-version: ${{ matrix.erlang_version }} elixir-version: ${{ matrix.elixir_version }} From da8f4299b5fe53f8358ff0e59c2284dfdf2c4b4e Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 18:05:21 +0200 Subject: [PATCH 02/19] Adapt to OTP28 sslsocket 1. OTP28 changed sslsocket structure 2. an old hack is no longer necessary --- deps/rabbit/src/rabbit_networking.erl | 4 +-- deps/rabbit/src/rabbit_reader.erl | 8 +++--- deps/rabbit_common/src/rabbit_net.erl | 35 +++------------------------ 3 files changed, 9 insertions(+), 38 deletions(-) diff --git a/deps/rabbit/src/rabbit_networking.erl b/deps/rabbit/src/rabbit_networking.erl index 0d24ef9efe90..361b1c1dfaa2 100644 --- a/deps/rabbit/src/rabbit_networking.erl +++ b/deps/rabbit/src/rabbit_networking.erl @@ -610,13 +610,13 @@ ranch_handshake(Ref) -> tune_buffer_size(Sock, dynamic_buffer) -> case rabbit_net:setopts(Sock, [{buffer, 128}]) of ok -> ok; - {error, _} -> rabbit_net:fast_close(Sock), + {error, _} -> _ = rabbit_net:fast_close(Sock), exit(normal) end; tune_buffer_size(Sock, static_buffer) -> case tune_buffer_size_static(Sock) of ok -> ok; - {error, _} -> rabbit_net:fast_close(Sock), + {error, _} -> _ = rabbit_net:fast_close(Sock), exit(normal) end. diff --git a/deps/rabbit/src/rabbit_reader.erl b/deps/rabbit/src/rabbit_reader.erl index e89595e469b3..bbaa79bd0388 100644 --- a/deps/rabbit/src/rabbit_reader.erl +++ b/deps/rabbit/src/rabbit_reader.erl @@ -275,7 +275,7 @@ socket_op(Sock, Fun) -> case Fun(Sock) of {ok, Res} -> Res; {error, Reason} -> socket_error(Reason), - rabbit_net:fast_close(RealSocket), + _ = rabbit_net:fast_close(RealSocket), exit(normal) end. @@ -287,10 +287,10 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) -> RealSocket = rabbit_net:unwrap_socket(Sock), Name = case rabbit_net:connection_string(Sock, inbound) of {ok, Str} -> list_to_binary(Str); - {error, enotconn} -> rabbit_net:fast_close(RealSocket), + {error, enotconn} -> _ = rabbit_net:fast_close(RealSocket), exit(normal); {error, Reason} -> socket_error(Reason), - rabbit_net:fast_close(RealSocket), + _ = rabbit_net:fast_close(RealSocket), exit(normal) end, {ok, HandshakeTimeout} = application:get_env(rabbit, handshake_timeout), @@ -364,7 +364,7 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) -> %% We don't call gen_tcp:close/1 here since it waits for %% pending output to be sent, which results in unnecessary %% delays. - rabbit_net:fast_close(RealSocket), + _ = rabbit_net:fast_close(RealSocket), rabbit_networking:unregister_connection(self()), rabbit_core_metrics:connection_closed(self()), ClientProperties = case get(client_properties) of diff --git a/deps/rabbit_common/src/rabbit_net.erl b/deps/rabbit_common/src/rabbit_net.erl index 949f483eeac2..d2a43431b471 100644 --- a/deps/rabbit_common/src/rabbit_net.erl +++ b/deps/rabbit_common/src/rabbit_net.erl @@ -82,19 +82,10 @@ -define(SSL_CLOSE_TIMEOUT, 5000). -define(IS_SSL(Sock), is_tuple(Sock) - andalso (tuple_size(Sock) =:= 3) andalso (element(1, Sock) =:= sslsocket)). is_ssl(Sock) -> ?IS_SSL(Sock). -%% Seems hackish. Is hackish. But the structure is stable and -%% kept this way for backward compatibility reasons. We need -%% it for two reasons: there are no ssl:getstat(Sock) function, -%% and no ssl:close(Timeout) function. Both of them are being -%% worked on as we speak. -ssl_get_socket(Sock) -> - element(2, element(2, Sock)). - ssl_info(Sock) when ?IS_SSL(Sock) -> ssl:connection_information(Sock); ssl_info(_Sock) -> @@ -119,12 +110,12 @@ controlling_process(Sock, Pid) when is_port(Sock) -> gen_tcp:controlling_process(Sock, Pid). getstat(Sock, Stats) when ?IS_SSL(Sock) -> - inet:getstat(ssl_get_socket(Sock), Stats); + ssl:getstat(Sock, Stats); getstat(Sock, Stats) when is_port(Sock) -> inet:getstat(Sock, Stats); %% Used by Proxy protocol support in plugins getstat({rabbit_proxy_socket, Sock, _}, Stats) when ?IS_SSL(Sock) -> - inet:getstat(ssl_get_socket(Sock), Stats); + ssl:getstat(Sock, Stats); getstat({rabbit_proxy_socket, Sock, _}, Stats) when is_port(Sock) -> inet:getstat(Sock, Stats). @@ -177,27 +168,7 @@ close(Sock) when ?IS_SSL(Sock) -> ssl:close(Sock); close(Sock) when is_port(Sock) -> gen_tcp:close(Sock). fast_close(Sock) when ?IS_SSL(Sock) -> - %% We cannot simply port_close the underlying tcp socket since the - %% TLS protocol is quite insistent that a proper closing handshake - %% should take place (see RFC 5245 s7.2.1). So we call ssl:close - %% instead, but that can block for a very long time, e.g. when - %% there is lots of pending output and there is tcp backpressure, - %% or the ssl_connection process has entered the the - %% workaround_transport_delivery_problems function during - %% termination, which, inexplicably, does a gen_tcp:recv(Socket, - %% 0), which may never return if the client doesn't send a FIN or - %% that gets swallowed by the network. Since there is no timeout - %% variant of ssl:close, we construct our own. - {Pid, MRef} = spawn_monitor(fun () -> ssl:close(Sock) end), - erlang:send_after(?SSL_CLOSE_TIMEOUT, self(), {Pid, ssl_close_timeout}), - receive - {Pid, ssl_close_timeout} -> - erlang:demonitor(MRef, [flush]), - exit(Pid, kill); - {'DOWN', MRef, process, Pid, _Reason} -> - ok - end, - catch port_close(ssl_get_socket(Sock)), + _ = ssl:close(Sock, ?SSL_CLOSE_TIMEOUT), ok; fast_close(Sock) when is_port(Sock) -> catch port_close(Sock), ok. From edd1b6dc6f1c87b2a5fc381a5cf29b347aa6abd5 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 23:05:22 +0200 Subject: [PATCH 03/19] Bump x509 to 0.9.0 for OTP28 support --- deps/rabbitmq_cli/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbitmq_cli/Makefile b/deps/rabbitmq_cli/Makefile index ac74acc6880d..95d9a672cb12 100644 --- a/deps/rabbitmq_cli/Makefile +++ b/deps/rabbitmq_cli/Makefile @@ -22,7 +22,7 @@ dep_amqp = hex 3.3.0 dep_csv = hex 3.2.1 dep_json = hex 1.4.1 dep_temp = hex 0.4.7 -dep_x509 = hex 0.8.8 +dep_x509 = hex 0.9.0 DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-build.mk From 79e3a946cc961efb18d94de051c80c928993a17e Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 23:22:00 +0200 Subject: [PATCH 04/19] Add xmerl to PLT_APPS for rabbit_common --- deps/rabbit_common/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbit_common/Makefile b/deps/rabbit_common/Makefile index 510d6cb0fa32..87be767cd70d 100644 --- a/deps/rabbit_common/Makefile +++ b/deps/rabbit_common/Makefile @@ -43,7 +43,7 @@ DEP_EARLY_PLUGINS = $(PROJECT)/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = $(PROJECT)/mk/rabbitmq-build.mk \ $(PROJECT)/mk/rabbitmq-hexpm.mk -PLT_APPS += mnesia crypto ssl +PLT_APPS += mnesia crypto ssl xmerl include ../../rabbitmq-components.mk include ../../erlang.mk From 8273c500c4b84bbabaddd50bbf2585dc6f31bb02 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 23:25:50 +0200 Subject: [PATCH 05/19] STOMP: Handle OTP28 re:split("", ...) behaviour --- deps/rabbit_common/src/rabbit_routing_parser.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deps/rabbit_common/src/rabbit_routing_parser.erl b/deps/rabbit_common/src/rabbit_routing_parser.erl index 81b26d4a913b..eb38eea89cda 100644 --- a/deps/rabbit_common/src/rabbit_routing_parser.erl +++ b/deps/rabbit_common/src/rabbit_routing_parser.erl @@ -23,7 +23,9 @@ parse_endpoint(Destination, AllowAnonymousQueue) parse_endpoint(Destination, AllowAnonymousQueue) when is_list(Destination) -> case re:split(Destination, "/", [unicode, {return, list}]) of - [Name] -> + [] -> %% in OTP28+, re:split("", "/") returns [] + {ok, {queue, unescape("")}}; + [Name] -> %% before OTP28, re:split("", "/") returns [[]] {ok, {queue, unescape(Name)}}; ["", Type | Rest] when Type =:= "exchange" orelse Type =:= "queue" orelse From 3aa99a984301b1430ba697e90bacf6283987b69d Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 23:48:11 +0200 Subject: [PATCH 06/19] rabbitmq_ct_client_helpers: fix dialyzer on OTP28 --- deps/rabbitmq_ct_client_helpers/Makefile | 2 +- deps/rabbitmq_ct_client_helpers/src/rfc6455_client.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/rabbitmq_ct_client_helpers/Makefile b/deps/rabbitmq_ct_client_helpers/Makefile index ac964056746c..fda66799bc56 100644 --- a/deps/rabbitmq_ct_client_helpers/Makefile +++ b/deps/rabbitmq_ct_client_helpers/Makefile @@ -5,7 +5,7 @@ DEPS = rabbit_common rabbitmq_ct_helpers amqp_client DEP_PLUGINS = rabbit_common/mk/rabbitmq-build.mk -PLT_APPS += common_test crypto +PLT_APPS += common_test crypto ssl include ../../rabbitmq-components.mk include ../../erlang.mk diff --git a/deps/rabbitmq_ct_client_helpers/src/rfc6455_client.erl b/deps/rabbitmq_ct_client_helpers/src/rfc6455_client.erl index 047548abd81f..f57816b23ed8 100644 --- a/deps/rabbitmq_ct_client_helpers/src/rfc6455_client.erl +++ b/deps/rabbitmq_ct_client_helpers/src/rfc6455_client.erl @@ -23,7 +23,7 @@ new(WsUrl, PPid, AuthInfo, Protocols) -> new(WsUrl, PPid, AuthInfo, Protocols, <<>>). new(WsUrl, PPid, AuthInfo, Protocols, TcpPreface) -> - _ = crypto:start(), + _ = application:start(crypto), _ = application:ensure_all_started(ssl), {Transport, Url} = case WsUrl of "ws://" ++ Rest -> {gen_tcp, Rest}; From 1f681ba6d7eb843fd7e98eea5db90df7b6dc0271 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 23:49:42 +0200 Subject: [PATCH 07/19] rabbitmq_web_mqtt: add ssl to PLT_APPS --- deps/rabbitmq_web_mqtt/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbitmq_web_mqtt/Makefile b/deps/rabbitmq_web_mqtt/Makefile index 79e07ba57b8b..7458f062fe9a 100644 --- a/deps/rabbitmq_web_mqtt/Makefile +++ b/deps/rabbitmq_web_mqtt/Makefile @@ -21,7 +21,7 @@ LOCAL_DEPS = ssl DEPS = rabbit cowboy rabbitmq_mqtt TEST_DEPS = emqtt rabbitmq_ct_helpers rabbitmq_ct_client_helpers rabbitmq_management rabbitmq_stomp rabbitmq_consistent_hash_exchange -PLT_APPS += rabbitmq_cli elixir cowlib +PLT_APPS += rabbitmq_cli elixir cowlib ssl # FIXME: Add Ranch as a BUILD_DEPS to be sure the correct version is picked. # See rabbitmq-components.mk. From caa174aac909a42e65bc75bd282069dc14a0ef2a Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Tue, 24 Jun 2025 23:51:28 +0200 Subject: [PATCH 08/19] rabbitmq_stomp: add ssl to PLT_APPS --- deps/rabbitmq_stomp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbitmq_stomp/Makefile b/deps/rabbitmq_stomp/Makefile index f1bcf891d021..561daa93d3fb 100644 --- a/deps/rabbitmq_stomp/Makefile +++ b/deps/rabbitmq_stomp/Makefile @@ -33,7 +33,7 @@ endef DEPS = ranch rabbit_common rabbit amqp_client TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers rabbitmq_management -PLT_APPS += rabbitmq_cli elixir +PLT_APPS += rabbitmq_cli elixir ssl DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk From 97fb7d5783db933a38c5cc549aeeb7b830a50c80 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 00:00:54 +0200 Subject: [PATCH 09/19] management_agent: Don't auto-import ceil/1 --- deps/rabbitmq_management_agent/src/exometer_slide.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/deps/rabbitmq_management_agent/src/exometer_slide.erl b/deps/rabbitmq_management_agent/src/exometer_slide.erl index bc124fbaea5e..5f69d94d21b4 100644 --- a/deps/rabbitmq_management_agent/src/exometer_slide.erl +++ b/deps/rabbitmq_management_agent/src/exometer_slide.erl @@ -73,6 +73,7 @@ -compile(inline). -compile(inline_list_funcs). +-compile({no_auto_import,[ceil/1]}). -type value() :: tuple(). -type internal_value() :: tuple() | drop. From eb19f87dd9357a2576da1ab72ac9589d00ef76d3 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 00:01:17 +0200 Subject: [PATCH 10/19] rabbitmq_stream: add ssl to PLT_APPS --- deps/rabbitmq_stream/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbitmq_stream/Makefile b/deps/rabbitmq_stream/Makefile index 5633bbce9d14..c5e4caac3a8d 100644 --- a/deps/rabbitmq_stream/Makefile +++ b/deps/rabbitmq_stream/Makefile @@ -25,7 +25,7 @@ LOCAL_DEPS = ssl DEPS = rabbit rabbitmq_stream_common osiris ranch TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client amqp10_client -PLT_APPS += rabbitmq_cli elixir +PLT_APPS += rabbitmq_cli elixir ssl DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk From ad0c873c6b5012f3ef8b987baea0332d928626b1 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 00:27:38 +0200 Subject: [PATCH 11/19] rabbitmq_cli: bump temp to 0.4.9 --- deps/rabbitmq_cli/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbitmq_cli/Makefile b/deps/rabbitmq_cli/Makefile index 95d9a672cb12..a9856a95a994 100644 --- a/deps/rabbitmq_cli/Makefile +++ b/deps/rabbitmq_cli/Makefile @@ -21,7 +21,7 @@ TEST_DEPS = amqp amqp_client temp x509 rabbit dep_amqp = hex 3.3.0 dep_csv = hex 3.2.1 dep_json = hex 1.4.1 -dep_temp = hex 0.4.7 +dep_temp = hex 0.4.9 dep_x509 = hex 0.9.0 DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk From 87dac547ff89cddd52ef72ffbadf1f68b5e6918d Mon Sep 17 00:00:00 2001 From: David Ansari Date: Wed, 25 Jun 2025 12:37:10 +0200 Subject: [PATCH 12/19] Skip test case two_nodes_different_otp_version Test case two_nodes_different_otp_version was introduced in https://github.com/rabbitmq/rabbitmq-server/pull/14042. In CI, the code was compiled on OTP 27. The test case then applied the Ra commands on OTP 27 and OTP 26 at runtime. For that to work the test transferred the compiled BEAM modules to the OTP 26 node. Bumping OTP to 28 causes the lower version node (be it OTP 26 or OTP 27) to error when parsing the atom table chunk of the BEAM file that was compiled in OTP 28: ``` corrupt atom table {error,badfile} ``` That's expected as described in https://github.com/erlang/otp/pull/8913#issue-2572291638 since https://github.com/erlang/otp/pull/8913 changes the atom table chunk format in the BEAM files. ``` beam_lib:chunks("deps/rabbit/ebin/lqueue.beam", [atoms]). ``` will parse successfully if the file gets loaded on OTP 28 irrespective of whether the file was compiled with OTP 27 or 28. However, this file fails to load if it is compiled with 28 and loaded on 27. There is the `no_long_atoms` option that we could use just for this test case. However, given that we have a similar test case two_nodes_same_otp_version we skip test case two_nodes_different_otp_version in this commit. Really, the best solution would be to use different OTP versions in RabbitMQ mixed version testing in addition to using different RabbitMQ versions. This way, the test case could just RPC into the different RabbitMQ nodes and apply the Ra commands there. --- deps/rabbit/test/rabbit_fifo_prop_SUITE.erl | 63 ++++++++++++--------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/deps/rabbit/test/rabbit_fifo_prop_SUITE.erl b/deps/rabbit/test/rabbit_fifo_prop_SUITE.erl index fcc35397f2b2..f7010a695581 100644 --- a/deps/rabbit/test/rabbit_fifo_prop_SUITE.erl +++ b/deps/rabbit/test/rabbit_fifo_prop_SUITE.erl @@ -1111,32 +1111,43 @@ two_nodes_same_otp_version(Config0) -> %% Run the log on two Erlang nodes with different OTP versions. two_nodes_different_otp_version(_Config) -> - Node = 'rabbit_fifo_prop@localhost', - case net_adm:ping(Node) of - pong -> - case is_same_otp_version(Node) of - true -> - ct:fail("expected CT node and 'rabbit_fifo_prop@localhost' " - "to have different OTP versions"); - false -> - Prefixes = ["rabbit_fifo", "rabbit_misc", "mc", - "lqueue", "priority_queue", "ra_"], - [begin - Mod = list_to_atom(ModStr), - {Mod, Bin, _File} = code:get_object_code(Mod), - {module, Mod} = erpc:call(Node, code, load_binary, [Mod, ModStr, Bin]) - end - || {ModStr, _FileName, _Loaded} <- code:all_available(), - lists:any(fun(Prefix) -> lists:prefix(Prefix, ModStr) end, Prefixes)], - two_nodes(Node) - end; - pang -> - Reason = {node_down, Node}, - case rabbit_ct_helpers:is_ci() of - true -> - ct:fail(Reason); - false -> - {skip, Reason} + case erlang:system_info(otp_release) of + "28" -> + %% Compiling a BEAM file on OTP 28 and loading it on OTP 26 or 27 + %% causes a "corrupt atom table" error. + %% https://github.com/erlang/otp/pull/8913#issue-2572291638 + {skip, "loading BEAM file compiled on OTP 28 on a lower OTP version is unsupported"}; + _ -> + Node = 'rabbit_fifo_prop@localhost', + case net_adm:ping(Node) of + pong -> + case is_same_otp_version(Node) of + true -> + ct:fail("expected CT node and 'rabbit_fifo_prop@localhost' " + "to have different OTP versions"); + false -> + Prefixes = ["rabbit_fifo", "rabbit_misc", "mc", + "lqueue", "priority_queue", "ra_"], + [begin + Mod = list_to_atom(ModStr), + {Mod, Bin, _File} = code:get_object_code(Mod), + {module, Mod} = erpc:call(Node, code, load_binary, + [Mod, ModStr, Bin]) + end + || {ModStr, _FileName, _Loaded} <- code:all_available(), + lists:any(fun(Prefix) -> + lists:prefix(Prefix, ModStr) + end, Prefixes)], + two_nodes(Node) + end; + pang -> + Reason = {node_down, Node}, + case rabbit_ct_helpers:is_ci() of + true -> + ct:fail(Reason); + false -> + {skip, Reason} + end end end. From 5ea53632f505e1989219cdc095a84bc6f49b89b8 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 13:06:49 +0200 Subject: [PATCH 13/19] Bump erlang.mk to fix x509 0.9.0 compilation --- erlang.mk | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/erlang.mk b/erlang.mk index e6e7ea4ec948..d7cfb7061f49 100644 --- a/erlang.mk +++ b/erlang.mk @@ -17,7 +17,7 @@ ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) export ERLANG_MK_FILENAME -ERLANG_MK_VERSION = e13b4c7 +ERLANG_MK_VERSION = f157f11 ERLANG_MK_WITHOUT = # Make 3.81 and 3.82 are deprecated. @@ -559,6 +559,14 @@ export ERL_LIBS export NO_AUTOPATCH +# Elixir. + +# Elixir is automatically enabled in all cases except when +# an Erlang project uses an Elixir dependency. In that case +# $(ELIXIR) must be set explicitly. +ELIXIR ?= $(if $(filter elixir,$(BUILD_DEPS) $(DEPS)),dep,$(if $(EX_FILES),system,disable)) +export ELIXIR + # Verbosity. dep_verbose_0 = @echo " DEP $1 ($(call query_version,$1))"; @@ -1778,12 +1786,6 @@ endif # Copyright (c) 2024, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -# Elixir is automatically enabled in all cases except when -# an Erlang project uses an Elixir dependency. In that case -# $(ELIXIR) must be set explicitly. -ELIXIR ?= $(if $(filter elixir,$(BUILD_DEPS) $(DEPS)),dep,$(if $(EX_FILES),system,disable)) -export ELIXIR - ifeq ($(ELIXIR),system) # We expect 'elixir' to be on the path. ELIXIR_BIN ?= $(shell readlink -f `which elixir`) @@ -1964,6 +1966,7 @@ endef define compile_ex.erl {ok, _} = application:ensure_all_started(elixir), {ok, _} = application:ensure_all_started(mix), + $(foreach dep,$(LOCAL_DEPS),_ = application:load($(dep)),) ModCode = list_to_atom("Elixir.Code"), ModCode:put_compiler_option(ignore_module_conflict, true), ModComp = list_to_atom("Elixir.Kernel.ParallelCompiler"), From f0705acd19147e9dfda8b7765be773a9fb876474 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 14:46:23 +0200 Subject: [PATCH 14/19] Disable dialyzer for some modules Elixir 1.18 comes with a JSON package which leads to errors like this: ``` Duplicate modules: [["/home/runner/work/_temp/.setup-beam/elixir/bin/../lib/elixir/ebin/Elixir.JSON.Encoder.Float.beam", "/home/runner/work/rabbitmq-server/rabbitmq-server/deps/json/ebin/Elixir.JSON.Encoder.Float.beam"], ``` --- .github/workflows/test-make-type-check.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-make-type-check.yaml b/.github/workflows/test-make-type-check.yaml index d1459bceeb26..57780e4f9788 100644 --- a/.github/workflows/test-make-type-check.yaml +++ b/.github/workflows/test-make-type-check.yaml @@ -17,7 +17,7 @@ jobs: plugin: # These are using plugin-specific test jobs. - rabbit - - rabbitmq_mqtt + # - rabbitmq_mqtt # disabled due to Elixir 1.18 JSON conficts - rabbitmq_peer_discovery_aws # These are from the test-plugin test job. - amqp10_client @@ -57,14 +57,14 @@ jobs: - rabbitmq_shovel - rabbitmq_shovel_management - rabbitmq_shovel_prometheus - - rabbitmq_stomp - - rabbitmq_stream + # - rabbitmq_stomp # disabled due to Elixir 1.18 JSON conficts + # - rabbitmq_stream # disabled due to Elixir 1.18 JSON conficts - rabbitmq_stream_common - rabbitmq_stream_management - rabbitmq_tracing - rabbitmq_trust_store - rabbitmq_web_dispatch - - rabbitmq_web_mqtt + # - rabbitmq_web_mqtt # disabled due to Elixir 1.18 JSON conficts - rabbitmq_web_stomp # This one we do not want to run tests so no corresponding test job. - rabbitmq_ct_helpers From 6def891d42d0d6990928f8cb03c134691fccd1d4 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 15:48:56 +0200 Subject: [PATCH 15/19] Adjust CLI tests for OTP28 --- .../test/ctl/set_permissions_command_test.exs | 2 +- .../set_permissions_globally_command_test.exs | 2 +- .../plugins/disable_plugins_command_test.exs | 194 ++++++++++-------- 3 files changed, 106 insertions(+), 92 deletions(-) diff --git a/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs index 24668713fe28..746d43fc0858 100644 --- a/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs +++ b/deps/rabbitmq_cli/test/ctl/set_permissions_command_test.exs @@ -99,7 +99,7 @@ defmodule SetPermissionsCommandTest do assert @command.run( [context[:user], "^#{context[:user]}-.*", ".*", "*"], context[:opts] - ) == {:error, {:invalid_regexp, ~c"*", {~c"nothing to repeat", 0}}} + ) == {:error, {:invalid_regexp, ~c"*", {~c"quantifier does not follow a repeatable item", 0}}} # asserts that the failed command didn't change anything u = Enum.find(list_permissions(context[:vhost]), fn x -> x[:user] == context[:user] end) diff --git a/deps/rabbitmq_cli/test/ctl/set_permissions_globally_command_test.exs b/deps/rabbitmq_cli/test/ctl/set_permissions_globally_command_test.exs index 2e4698395158..28003ab9116c 100644 --- a/deps/rabbitmq_cli/test/ctl/set_permissions_globally_command_test.exs +++ b/deps/rabbitmq_cli/test/ctl/set_permissions_globally_command_test.exs @@ -100,7 +100,7 @@ defmodule SetPermissionsGloballyCommandTest do assert @command.run( [context[:user], "^#{context[:user]}-.*", ".*", "*"], context[:opts] - ) == {:error, {:invalid_regexp, ~c"*", {~c"nothing to repeat", 0}}} + ) == {:error, {:invalid_regexp, ~c"*", {~c"quantifier does not follow a repeatable item", 0}}} # asserts that the failed command didn't change anything p4 = Enum.find(list_permissions(@vhost1), fn x -> x[:user] == context[:user] end) diff --git a/deps/rabbitmq_cli/test/plugins/disable_plugins_command_test.exs b/deps/rabbitmq_cli/test/plugins/disable_plugins_command_test.exs index 1af98f330518..26a8c787fa2e 100644 --- a/deps/rabbitmq_cli/test/plugins/disable_plugins_command_test.exs +++ b/deps/rabbitmq_cli/test/plugins/disable_plugins_command_test.exs @@ -68,6 +68,24 @@ defmodule DisablePluginsCommandTest do } end + # Helper functions for order-insensitive assertions + defp normalize_result_map(map) when is_map(map) do + map + |> Map.update(:stopped, [], &Enum.sort/1) + |> Map.update(:disabled, [], &Enum.sort/1) + |> Map.update(:set, [], &Enum.sort/1) + end + + defp normalize_stream_result([list, map]) when is_list(list) and is_map(map) do + [Enum.sort(list), normalize_result_map(map)] + end + + defp normalize_stream_result(other), do: other + + defp assert_lists_equal(expected, actual) do + assert Enum.sort(expected) == Enum.sort(actual) + end + test "validate: specifying both --online and --offline is reported as invalid", context do assert match?( {:validation_failure, {:bad_argument, _}}, @@ -104,16 +122,18 @@ defmodule DisablePluginsCommandTest do assert {:stream, test_stream} = @command.run(["rabbitmq_stomp"], Map.merge(context[:opts], %{node: :nonode})) - assert [ - [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], - %{mode: :offline, disabled: [:rabbitmq_stomp], set: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation]} - ] == - Enum.to_list(test_stream) + result = Enum.to_list(test_stream) + expected = [ + [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], + %{mode: :offline, disabled: [:rabbitmq_stomp], set: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation]} + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[:rabbitmq_federation]]} == :file.consult(context[:opts][:enabled_plugins_file]) - assert [:amqp_client, :rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp] == - Enum.sort(:rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, [])) + result = :rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, []) + expected = [:amqp_client, :rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp] + assert_lists_equal(expected, result) end test "in offline mode, writes out enabled plugins and reports implicitly enabled plugin list", @@ -124,15 +144,18 @@ defmodule DisablePluginsCommandTest do Map.merge(context[:opts], %{offline: true, online: false}) ) - assert [ - [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], - %{mode: :offline, disabled: [:rabbitmq_stomp], set: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation]} - ] == Enum.to_list(test_stream) + result = Enum.to_list(test_stream) + expected = [ + [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], + %{mode: :offline, disabled: [:rabbitmq_stomp], set: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation]} + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[:rabbitmq_federation]]} == :file.consult(context[:opts][:enabled_plugins_file]) - assert [:amqp_client, :rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp] == - Enum.sort(:rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, [])) + active_plugins = :rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, []) + expected_active = [:amqp_client, :rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp] + assert_lists_equal(expected_active, active_plugins) end test "in offline mode, removes implicitly enabled plugins when the last explicitly enabled one is removed", @@ -143,10 +166,12 @@ defmodule DisablePluginsCommandTest do Map.merge(context[:opts], %{offline: true, online: false}) ) - assert [ - [:rabbitmq_stomp], - %{mode: :offline, disabled: [:rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_exchange_federation, :rabbitmq_federation], set: [:rabbitmq_stomp]} - ] == Enum.to_list(test_stream0) + result = Enum.to_list(test_stream0) + expected = [ + [:rabbitmq_stomp], + %{mode: :offline, disabled: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], set: [:rabbitmq_stomp]} + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[:rabbitmq_stomp]]} == :file.consult(context[:opts][:enabled_plugins_file]) @@ -156,8 +181,9 @@ defmodule DisablePluginsCommandTest do Map.merge(context[:opts], %{offline: true, online: false}) ) - assert [[], %{mode: :offline, disabled: [:rabbitmq_stomp], set: []}] == - Enum.to_list(test_stream1) + result = Enum.to_list(test_stream1) + expected = [[], %{mode: :offline, disabled: [:rabbitmq_stomp], set: []}] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[]]} = :file.consult(context[:opts][:enabled_plugins_file]) end @@ -165,102 +191,90 @@ defmodule DisablePluginsCommandTest do test "updates plugin list and stops disabled plugins", context do assert {:stream, test_stream0} = @command.run(["rabbitmq_stomp"], context[:opts]) - assert [ - [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], - %{ - mode: :online, - started: [], - stopped: [:rabbitmq_stomp], - disabled: [:rabbitmq_stomp], - set: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation] - } - ] == - Enum.to_list(test_stream0) + result = Enum.to_list(test_stream0) + expected = [ + [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], + %{ + mode: :online, + started: [], + stopped: [:rabbitmq_stomp], + disabled: [:rabbitmq_stomp], + set: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation] + } + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[:rabbitmq_federation]]} == :file.consult(context[:opts][:enabled_plugins_file]) - assert [:amqp_client, :rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation] == - Enum.sort(:rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, [])) + result = :rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, []) + expected = [:amqp_client, :rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation] + assert_lists_equal(expected, result) assert {:stream, test_stream1} = @command.run(["rabbitmq_federation"], context[:opts]) - assert [ - [], - %{ - mode: :online, - started: [], - stopped: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], - disabled: [:rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_exchange_federation, :rabbitmq_federation], - set: [] - } - ] == - Enum.to_list(test_stream1) + result = Enum.to_list(test_stream1) + expected = [ + [], + %{ + mode: :online, + started: [], + stopped: [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation], + disabled: [:rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_exchange_federation, :rabbitmq_federation], + set: [] + } + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[]]} == :file.consult(context[:opts][:enabled_plugins_file]) - assert Enum.empty?( - Enum.sort(:rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, [])) - ) + result = :rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, []) + assert Enum.empty?(result) end test "can disable multiple plugins at once", context do assert {:stream, test_stream} = @command.run(["rabbitmq_stomp", "rabbitmq_federation"], context[:opts]) - [[], m0] = Enum.to_list(test_stream) - - m1 = - m0 - |> Map.update!(:stopped, &Enum.sort/1) - |> Map.update!(:disabled, &Enum.sort/1) - - expected_list = Enum.sort([:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp]) - - assert [ - [], - %{ - mode: :online, - started: [], - stopped: expected_list, - disabled: expected_list, - set: [] - } - ] == [[], m1] + result = Enum.to_list(test_stream) + expected_list = [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp] + expected = [ + [], + %{ + mode: :online, + started: [], + stopped: expected_list, + disabled: expected_list, + set: [] + } + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[]]} == :file.consult(context[:opts][:enabled_plugins_file]) - assert Enum.empty?( - Enum.sort(:rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, [])) - ) + active_plugins = :rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, []) + assert Enum.empty?(active_plugins) end test "disabling a dependency disables all plugins that depend on it", context do assert {:stream, test_stream} = @command.run(["amqp_client"], context[:opts]) - [[], m0] = Enum.to_list(test_stream) - - m1 = - m0 - |> Map.update!(:stopped, &Enum.sort/1) - |> Map.update!(:disabled, &Enum.sort/1) - - expected_list = Enum.sort([:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp]) - - assert [ - [], - %{ - mode: :online, - started: [], - stopped: expected_list, - disabled: expected_list, - set: [] - } - ] == [[], m1] + result = Enum.to_list(test_stream) + expected_list = [:rabbitmq_exchange_federation, :rabbitmq_federation, :rabbitmq_federation_common, :rabbitmq_queue_federation, :rabbitmq_stomp] + expected = [ + [], + %{ + mode: :online, + started: [], + stopped: expected_list, + disabled: expected_list, + set: [] + } + ] + assert normalize_stream_result(expected) == normalize_stream_result(result) assert {:ok, [[]]} == :file.consult(context[:opts][:enabled_plugins_file]) - assert Enum.empty?( - Enum.sort(:rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, [])) - ) + result = :rabbit_misc.rpc_call(context[:opts][:node], :rabbit_plugins, :active, []) + assert Enum.empty?(result) end test "formats enabled plugins mismatch errors", context do From fd1d037874bc6dcb9aa290180b54e599518a6be5 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 16:58:18 +0200 Subject: [PATCH 16/19] Deflake per_user_connection_tracking_SUITE --- .../per_user_connection_tracking_SUITE.erl | 76 ++++++++++--------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/deps/rabbit/test/per_user_connection_tracking_SUITE.erl b/deps/rabbit/test/per_user_connection_tracking_SUITE.erl index 601be3e45227..e4884f8eba60 100644 --- a/deps/rabbit/test/per_user_connection_tracking_SUITE.erl +++ b/deps/rabbit/test/per_user_connection_tracking_SUITE.erl @@ -100,60 +100,64 @@ end_per_testcase(Testcase, Config) -> %% Test cases. %% ------------------------------------------------------------------- single_node_list_of_user(Config) -> - Username = proplists:get_value(rmq_username, Config), - Username2 = <<"guest2">>, + Username1 = list_to_binary(atom_to_list(?FUNCTION_NAME) ++ "-1"), + Username2 = list_to_binary(atom_to_list(?FUNCTION_NAME) ++ "-2"), Vhost = proplists:get_value(rmq_vhost, Config), - rabbit_ct_broker_helpers:add_user(Config, Username2), - rabbit_ct_broker_helpers:set_full_permissions(Config, Username2, Vhost), + [ begin + rabbit_ct_broker_helpers:add_user(Config, U), + rabbit_ct_broker_helpers:set_full_permissions(Config, U, Vhost) + end || U <- [Username1, Username2]], - ?assertEqual(0, count_connections_in(Config, Username)), + ?assertEqual(0, count_connections_in(Config, Username1)), ?assertEqual(0, count_connections_in(Config, Username2)), - [Conn1] = open_connections(Config, [0]), - ?awaitMatch(1, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), - [#tracked_connection{username = Username}] = connections_in(Config, Username), + [Conn1] = open_connections(Config, [{0, Username1}]), + ?awaitMatch(1, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), + [#tracked_connection{username = Username1}] = connections_in(Config, Username1), close_connections([Conn1]), - ?awaitMatch(0, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), + ?awaitMatch(0, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), [Conn2] = open_connections(Config, [{0, Username2}]), ?awaitMatch(1, count_connections_in(Config, Username2), ?AWAIT_TIMEOUT), [#tracked_connection{username = Username2}] = connections_in(Config, Username2), - [Conn3] = open_connections(Config, [0]), - ?awaitMatch(1, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), - [#tracked_connection{username = Username}] = connections_in(Config, Username), + [Conn3] = open_connections(Config, [{0, Username1}]), + ?awaitMatch(1, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), + [#tracked_connection{username = Username1}] = connections_in(Config, Username1), - [Conn4] = open_connections(Config, [0]), + [Conn4] = open_connections(Config, [{0, Username1}]), kill_connections([Conn4]), - ?awaitMatch(1, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), - [#tracked_connection{username = Username}] = connections_in(Config, Username), + ?awaitMatch(1, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), + [#tracked_connection{username = Username1}] = connections_in(Config, Username1), - [Conn5] = open_connections(Config, [0]), - ?awaitMatch(2, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), - [Username, Username] = + [Conn5] = open_connections(Config, [{0, Username1}]), + ?awaitMatch(2, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), + [Username1, Username1] = lists:map(fun (#tracked_connection{username = U}) -> U end, - connections_in(Config, Username)), + connections_in(Config, Username1)), close_connections([Conn2, Conn3, Conn5]), rabbit_ct_broker_helpers:delete_user(Config, Username2), ?awaitMatch(0, length(all_connections(Config)), ?AWAIT_TIMEOUT). single_node_user_deletion_forces_connection_closure(Config) -> - Username = proplists:get_value(rmq_username, Config), - Username2 = <<"guest2">>, + Username1 = list_to_binary(atom_to_list(?FUNCTION_NAME) ++ "-1"), + Username2 = list_to_binary(atom_to_list(?FUNCTION_NAME) ++ "-2"), Vhost = proplists:get_value(rmq_vhost, Config), - rabbit_ct_broker_helpers:add_user(Config, Username2), - rabbit_ct_broker_helpers:set_full_permissions(Config, Username2, Vhost), + [ begin + rabbit_ct_broker_helpers:add_user(Config, U), + rabbit_ct_broker_helpers:set_full_permissions(Config, U, Vhost) + end || U <- [Username1, Username2]], - ?assertEqual(0, count_connections_in(Config, Username)), + ?assertEqual(0, count_connections_in(Config, Username1)), ?assertEqual(0, count_connections_in(Config, Username2)), - [Conn1] = open_connections(Config, [0]), - ?awaitMatch(1, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), + [Conn1] = open_connections(Config, [{0, Username1}]), + ?awaitMatch(1, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), [_Conn2] = open_connections(Config, [{0, Username2}]), ?awaitMatch(1, count_connections_in(Config, Username2), ?AWAIT_TIMEOUT), @@ -162,22 +166,24 @@ single_node_user_deletion_forces_connection_closure(Config) -> ?awaitMatch(0, count_connections_in(Config, Username2), ?AWAIT_TIMEOUT), close_connections([Conn1]), - ?awaitMatch(0, count_connections_in(Config, Username), ?AWAIT_TIMEOUT). + ?awaitMatch(0, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT). cluster_user_deletion_forces_connection_closure(Config) -> - Username = proplists:get_value(rmq_username, Config), - Username2 = <<"guest2">>, + Username1 = list_to_binary(atom_to_list(?FUNCTION_NAME) ++ "-1"), + Username2 = list_to_binary(atom_to_list(?FUNCTION_NAME) ++ "-2"), Vhost = proplists:get_value(rmq_vhost, Config), - rabbit_ct_broker_helpers:add_user(Config, Username2), - rabbit_ct_broker_helpers:set_full_permissions(Config, Username2, Vhost), + [ begin + rabbit_ct_broker_helpers:add_user(Config, U), + rabbit_ct_broker_helpers:set_full_permissions(Config, U, Vhost) + end || U <- [Username1, Username2]], - ?assertEqual(0, count_connections_in(Config, Username)), + ?assertEqual(0, count_connections_in(Config, Username1)), ?assertEqual(0, count_connections_in(Config, Username2)), - [Conn1] = open_connections(Config, [{0, Username}]), - ?awaitMatch(1, count_connections_in(Config, Username), ?AWAIT_TIMEOUT), + [Conn1] = open_connections(Config, [{0, Username1}]), + ?awaitMatch(1, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT), [_Conn2] = open_connections(Config, [{1, Username2}]), ?awaitMatch(1, count_connections_in(Config, Username2), ?AWAIT_TIMEOUT), @@ -186,7 +192,7 @@ cluster_user_deletion_forces_connection_closure(Config) -> ?awaitMatch(0, count_connections_in(Config, Username2), ?AWAIT_TIMEOUT), close_connections([Conn1]), - ?awaitMatch(0, count_connections_in(Config, Username), ?AWAIT_TIMEOUT). + ?awaitMatch(0, count_connections_in(Config, Username1), ?AWAIT_TIMEOUT). %% ------------------------------------------------------------------- %% Helpers From 9099cfb64eb3181e128b77761bbcd861d4a747ef Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 25 Jun 2025 18:20:58 +0200 Subject: [PATCH 17/19] OTP-PUB-KEY -> PKIXAlgs-2009 for OTP28+ --- deps/rabbit_common/src/rabbit_cert_info.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/deps/rabbit_common/src/rabbit_cert_info.erl b/deps/rabbit_common/src/rabbit_cert_info.erl index ae1ed690c9aa..a3e544c62bcd 100644 --- a/deps/rabbit_common/src/rabbit_cert_info.erl +++ b/deps/rabbit_common/src/rabbit_cert_info.erl @@ -109,11 +109,18 @@ find_by_type(Type, {rdnSequence, RDNs}) -> %% Formatting functions %%-------------------------------------------------------------------------- + +-if (?OTP_RELEASE >= 28). +-define(M, 'PKIXAlgs-2009'). +-else. +-define(M, 'OTP-PUB-KEY'). +-endif. + sanitize_other_name(Bin) when is_binary(Bin) -> %% We make a wild assumption about the types here %% but ASN.1 decoding functions in OTP only offer so much and SAN values %% are expected to be "string-like" by RabbitMQ - case 'OTP-PUB-KEY':decode('DirectoryString', Bin) of + case ?M:decode('DirectoryString', Bin) of {ok, {_, Val}} -> Val; Other -> Other end. From 3033154717e4987cd170f13cc71f1d19e7de1766 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Fri, 27 Jun 2025 14:14:48 +0200 Subject: [PATCH 18/19] Cache ActiveMQ to reduce downloads/flakes --- .github/workflows/test-make-target.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/test-make-target.yaml b/.github/workflows/test-make-target.yaml index 715fb510395a..184fb927a02f 100644 --- a/.github/workflows/test-make-target.yaml +++ b/.github/workflows/test-make-target.yaml @@ -33,6 +33,11 @@ jobs: - name: FETCH TAGS run: git fetch --tags + - name: EXTRACT ACTIVEMQ VERSION + if: inputs.plugin == 'amqp10_client' + run: | + awk '/^ACTIVEMQ_VERSION/ {print $1 "=" $3}' deps/amqp10_client/Makefile >> $GITHUB_ENV + - name: SETUP OTP & ELIXIR uses: erlef/setup-beam@v1 with: @@ -99,12 +104,27 @@ jobs: docker run -d --network host --name erlang_low_version erlang:${LOW_ERLANG_VERSION} \ erl -sname rabbit_fifo_prop@localhost -setcookie $(cat ~/.erlang.cookie) -noinput + - name: RESTORE ACTIVEMQ FROM CACHE + if: inputs.plugin == 'amqp10_client' + uses: actions/cache/restore@v4 + id: cache-activemq-restore + with: + path: deps/amqp10_client/test/system_SUITE_data/apache-activemq-${{ env.ACTIVEMQ_VERSION }}-bin.tar.gz + key: activemq-${{ env.ACTIVEMQ_VERSION }} + - name: RUN TESTS if: inputs.plugin != 'rabbitmq_cli' run: | sudo netstat -ntp make -C deps/${{ inputs.plugin }} ${{ inputs.make_target }} RABBITMQ_METADATA_STORE=${{ inputs.metadata_store }} + - name: CACHE ACTIVEMQ + uses: actions/cache/save@v4 + if: inputs.plugin == 'amqp10_client' && steps.cache-activemq-restore.outputs.cache-hit != 'true' + with: + path: deps/amqp10_client/test/system_SUITE_data/apache-activemq-${{ env.ACTIVEMQ_VERSION }}-bin.tar.gz + key: activemq-${{ env.ACTIVEMQ_VERSION }} + # rabbitmq_cli needs a correct broker version for two of its tests. # But setting PROJECT_VERSION makes other plugins fail. - name: RUN TESTS (rabbitmq_cli) From 5cc73d85ec3057822a3a73ea63111dbc8c32e994 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Fri, 27 Jun 2025 16:10:19 +0200 Subject: [PATCH 19/19] [skip ci] Disable force_shrink_member_to_current_member in mixed-version --- deps/rabbit/test/quorum_queue_SUITE.erl | 53 ++++++++++++++----------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/deps/rabbit/test/quorum_queue_SUITE.erl b/deps/rabbit/test/quorum_queue_SUITE.erl index deac2686c12f..db868f95b8ee 100644 --- a/deps/rabbit/test/quorum_queue_SUITE.erl +++ b/deps/rabbit/test/quorum_queue_SUITE.erl @@ -1217,38 +1217,43 @@ single_active_consumer_priority(Config) -> ok. force_shrink_member_to_current_member(Config) -> - [Server0, Server1, Server2] = - rabbit_ct_broker_helpers:get_node_configs(Config, nodename), + case rabbit_ct_helpers:is_mixed_versions() of + true -> + {skip, "Should not run in mixed version environments"}; + _ -> + [Server0, Server1, Server2] = + rabbit_ct_broker_helpers:get_node_configs(Config, nodename), - Ch = rabbit_ct_client_helpers:open_channel(Config, Server0), - QQ = ?config(queue_name, Config), - ?assertEqual({'queue.declare_ok', QQ, 0, 0}, - declare(Ch, QQ, [{<<"x-queue-type">>, longstr, <<"quorum">>}])), + Ch = rabbit_ct_client_helpers:open_channel(Config, Server0), + QQ = ?config(queue_name, Config), + ?assertEqual({'queue.declare_ok', QQ, 0, 0}, + declare(Ch, QQ, [{<<"x-queue-type">>, longstr, <<"quorum">>}])), - RaName = ra_name(QQ), - rabbit_ct_client_helpers:publish(Ch, QQ, 3), - wait_for_messages_ready([Server0], RaName, 3), + RaName = ra_name(QQ), + rabbit_ct_client_helpers:publish(Ch, QQ, 3), + wait_for_messages_ready([Server0], RaName, 3), - {ok, Q0} = rpc:call(Server0, rabbit_amqqueue, lookup, [QQ, <<"/">>]), - #{nodes := Nodes0} = amqqueue:get_type_state(Q0), - ?assertEqual(3, length(Nodes0)), + {ok, Q0} = rpc:call(Server0, rabbit_amqqueue, lookup, [QQ, <<"/">>]), + #{nodes := Nodes0} = amqqueue:get_type_state(Q0), + ?assertEqual(3, length(Nodes0)), - rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_quorum_queue, - force_shrink_member_to_current_member, [<<"/">>, QQ]), + rabbit_ct_broker_helpers:rpc(Config, 0, rabbit_quorum_queue, + force_shrink_member_to_current_member, [<<"/">>, QQ]), - wait_for_messages_ready([Server0], RaName, 3), + wait_for_messages_ready([Server0], RaName, 3), - {ok, Q1} = rpc:call(Server0, rabbit_amqqueue, lookup, [QQ, <<"/">>]), - #{nodes := Nodes1} = amqqueue:get_type_state(Q1), - ?assertEqual(1, length(Nodes1)), + {ok, Q1} = rpc:call(Server0, rabbit_amqqueue, lookup, [QQ, <<"/">>]), + #{nodes := Nodes1} = amqqueue:get_type_state(Q1), + ?assertEqual(1, length(Nodes1)), - %% grow queues back to all nodes - [rpc:call(Server0, rabbit_quorum_queue, grow, [S, <<"/">>, <<".*">>, all]) || S <- [Server1, Server2]], + %% grow queues back to all nodes + [rpc:call(Server0, rabbit_quorum_queue, grow, [S, <<"/">>, <<".*">>, all]) || S <- [Server1, Server2]], - wait_for_messages_ready([Server0], RaName, 3), - {ok, Q2} = rpc:call(Server0, rabbit_amqqueue, lookup, [QQ, <<"/">>]), - #{nodes := Nodes2} = amqqueue:get_type_state(Q2), - ?assertEqual(3, length(Nodes2)). + wait_for_messages_ready([Server0], RaName, 3), + {ok, Q2} = rpc:call(Server0, rabbit_amqqueue, lookup, [QQ, <<"/">>]), + #{nodes := Nodes2} = amqqueue:get_type_state(Q2), + ?assertEqual(3, length(Nodes2)) + end. force_all_queues_shrink_member_to_current_member(Config) -> [Server0, Server1, Server2] =