From 1c9a5c0849ac8a8456d21779de0b0ab08fb7f365 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 5 Oct 2026 18:11:30 -0700 Subject: [PATCH 1/5] Respond with `basic.cancel-ok` to the servers that support it If the server advertises `basic.cancel-ok` response support. The background on this is this: starting with `4.3.0`, a delivery acknowledgement timeout does not result in the channel being closed but rather a `basic.cancel` sent to the client. Between about 2011 and 2026, clients never had the need to respond to such `basic.cancel` because it was originally a client method. Unfortunately, RabbitMQ versions between `4.3.0` and `4.3.6` only clean up the consumer after a `basic.cancel-ok` arrives but older versions cannot handle `basic.cancel-ok`, hence the new capability and the conditional confirmation. --- .../com/rabbitmq/client/ServerCapability.java | 44 ++++++++++++++ .../rabbitmq/client/impl/AMQConnection.java | 16 +++++ .../com/rabbitmq/client/impl/ChannelN.java | 3 + .../impl/AMQConnectionCapabilitiesTest.java | 53 ++++++++++++++++ .../rabbitmq/client/test/ChannelNTest.java | 60 +++++++++++++++++++ 5 files changed, 176 insertions(+) create mode 100644 src/main/java/com/rabbitmq/client/ServerCapability.java create mode 100644 src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java diff --git a/src/main/java/com/rabbitmq/client/ServerCapability.java b/src/main/java/com/rabbitmq/client/ServerCapability.java new file mode 100644 index 0000000000..d05b4702d9 --- /dev/null +++ b/src/main/java/com/rabbitmq/client/ServerCapability.java @@ -0,0 +1,44 @@ +// Copyright (c) 2026 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client; + +/** + * Capabilities a RabbitMQ node advertises in the capabilities table + * of the connection.start server properties. + */ +public enum ServerCapability { + + PUBLISHER_CONFIRMS("publisher_confirms"), + EXCHANGE_EXCHANGE_BINDINGS("exchange_exchange_bindings"), + BASIC_NACK("basic.nack"), + CONSUMER_CANCEL_NOTIFY("consumer_cancel_notify"), + CONNECTION_BLOCKED("connection.blocked"), + CONSUMER_PRIORITIES("consumer_priorities"), + AUTHENTICATION_FAILURE_CLOSE("authentication_failure_close"), + PER_CONSUMER_QOS("per_consumer_qos"), + DIRECT_REPLY_TO("direct_reply_to"), + ACCEPT_CONSUMER_CANCEL_OK("accept_consumer_cancel_ok"); + + private final String name; + + ServerCapability(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 8f7c50c837..5494bb1790 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -215,6 +215,22 @@ public Map getServerProperties() { return _serverProperties; } + public boolean doesServerHaveCapability(ServerCapability capability) { + return doesServerHaveCapability(_serverProperties, capability); + } + + public boolean doesBrokerAcceptClientSentBasicCancelOk() { + return doesServerHaveCapability(ServerCapability.ACCEPT_CONSUMER_CANCEL_OK); + } + + @SuppressWarnings("unchecked") + static boolean doesServerHaveCapability(Map serverProperties, + ServerCapability capability) { + Map capabilities = (Map) + serverProperties.getOrDefault("capabilities", Collections.emptyMap()); + return capabilities.getOrDefault(capability.getName(), false) == true; + } + public AMQConnection(ConnectionParams params, FrameHandler frameHandler) { this(params, frameHandler, new NoOpMetricsCollector(), ObservationCollector.NO_OP); } diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index ea2df2d717..657a571e43 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -394,6 +394,9 @@ private void releaseChannel() { Basic.Cancel m = (Basic.Cancel)method; String consumerTag = m.getConsumerTag(); Consumer callback = _consumers.remove(consumerTag); + if (callback != null && getConnection().doesBrokerAcceptClientSentBasicCancelOk()) { + transmit(new Basic.CancelOk(consumerTag)); + } // Not finding any matching consumer isn't necessarily an indication of an issue anywhere. // Sometimes there's a natural race condition between consumer management on the server and client ends. // E.g. Channel#basicCancel called just before a basic.cancel for the same consumer tag is received. diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java new file mode 100644 index 0000000000..f909a92e51 --- /dev/null +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java @@ -0,0 +1,53 @@ +// Copyright (c) 2026 Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// +// This software, the RabbitMQ Java client library, is triple-licensed under the +// Mozilla Public License 2.0 ("MPL"), the GNU General Public License version 2 +// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see +// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, +// please see LICENSE-APACHE2. +// +// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, +// either express or implied. See the LICENSE file for specific language governing +// rights and limitations of this software. +// +// If you have any questions regarding licensing, please contact us at +// info@rabbitmq.com. + +package com.rabbitmq.client.impl; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.rabbitmq.client.ServerCapability; +import java.util.Map; +import org.junit.jupiter.api.Test; + +public class AMQConnectionCapabilitiesTest { + + @Test + void capabilitySetToTrueIsPresent() { + assertThat(AMQConnection.doesServerHaveCapability( + Map.of("capabilities", Map.of("accept_consumer_cancel_ok", true)), + ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)).isTrue(); + } + + @Test + void capabilitySetToFalseIsAbsent() { + assertThat(AMQConnection.doesServerHaveCapability( + Map.of("capabilities", Map.of("accept_consumer_cancel_ok", false)), + ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)).isFalse(); + } + + @Test + void missingCapabilityIsAbsent() { + assertThat(AMQConnection.doesServerHaveCapability( + Map.of("capabilities", Map.of("consumer_cancel_notify", true)), + ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)).isFalse(); + } + + @Test + void capabilityIsAbsentWithoutCapabilitiesTable() { + assertThat(AMQConnection.doesServerHaveCapability(Map.of(), ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)) + .isFalse(); + } +} diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 1ec24e1c53..d7b8a46afd 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -15,7 +15,9 @@ package com.rabbitmq.client.test; +import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Command; +import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Method; import com.rabbitmq.client.TrafficListener; import com.rabbitmq.client.impl.*; @@ -55,6 +57,41 @@ public void serverBasicCancelForUnknownConsumerDoesNotThrowException() throws Ex channel.processAsync(new AMQCommand(method)); } + @Test + public void serverBasicCancelIsAnsweredWithCancelOkWhenBrokerAcceptsIt() throws Exception { + TrafficListener trafficListener = Mockito.mock(TrafficListener.class); + AMQConnection connection = connectionAcceptingConsumerCancelOk(true, trafficListener); + ChannelN channel = channelWithConsumer(connection, "ctag"); + + channel.processAsync(new AMQCommand(new AMQImpl.Basic.Cancel.Builder().consumerTag("ctag").build())); + + Mockito.verify(trafficListener, Mockito.times(1)).write( + Mockito.argThat(c -> c.getMethod() instanceof AMQP.Basic.CancelOk)); + } + + @Test + public void serverBasicCancelIsNotAnsweredWhenBrokerDoesNotAcceptCancelOk() throws Exception { + TrafficListener trafficListener = Mockito.mock(TrafficListener.class); + AMQConnection connection = connectionAcceptingConsumerCancelOk(false, trafficListener); + ChannelN channel = channelWithConsumer(connection, "ctag"); + + channel.processAsync(new AMQCommand(new AMQImpl.Basic.Cancel.Builder().consumerTag("ctag").build())); + + Mockito.verify(trafficListener, Mockito.never()).write( + Mockito.argThat(c -> c.getMethod() instanceof AMQP.Basic.CancelOk)); + } + + @Test + public void serverBasicCancelForUnknownConsumerIsNotAnsweredWithCancelOk() throws Exception { + TrafficListener trafficListener = Mockito.mock(TrafficListener.class); + AMQConnection connection = connectionAcceptingConsumerCancelOk(true, trafficListener); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + + channel.processAsync(new AMQCommand(new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build())); + + Mockito.verify(trafficListener, Mockito.never()).write(Mockito.any(Command.class)); + } + @Test public void callingBasicCancelForUnknownConsumerDoesNotThrowException() throws Exception { AMQConnection connection = Mockito.mock(AMQConnection.class); @@ -107,6 +144,29 @@ public void confirmSelectOnlySendsRPCCallOnce() throws Exception { Mockito.verify(trafficListener, Mockito.times(1)).write(Mockito.any(Command.class)); } + private AMQConnection connectionAcceptingConsumerCancelOk( + boolean accepts, TrafficListener trafficListener) { + AMQConnection connection = Mockito.mock(AMQConnection.class); + Mockito.when(connection.getTrafficListener()).thenReturn(trafficListener); + Mockito.when(connection.doesBrokerAcceptClientSentBasicCancelOk()).thenReturn(accepts); + return connection; + } + + private ChannelN channelWithConsumer(AMQConnection connection, String consumerTag) throws Exception { + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + new Thread(() -> { + try { + Thread.sleep(15); + channel.handleCompleteInboundCommand( + new AMQCommand(new AMQImpl.Basic.ConsumeOk(consumerTag))); + } catch (Exception e) { + throw new RuntimeException(e); + } + }).start(); + channel.basicConsume("q", false, consumerTag, new DefaultConsumer(channel)); + return channel; + } + interface Consumer { void apply(int value) throws Exception; From 5049c5c3e35cc657225ed2ae125f442821562020 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 5 Oct 2026 19:28:36 -0700 Subject: [PATCH 2/5] JDK 8 compat --- .../java/com/rabbitmq/client/impl/AMQConnection.java | 4 ++-- src/main/java/com/rabbitmq/client/impl/ChannelN.java | 1 + .../client/impl/AMQConnectionCapabilitiesTest.java | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index 5494bb1790..bae6ae81da 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -226,9 +226,9 @@ public boolean doesBrokerAcceptClientSentBasicCancelOk() { @SuppressWarnings("unchecked") static boolean doesServerHaveCapability(Map serverProperties, ServerCapability capability) { - Map capabilities = (Map) + Map capabilities = (Map) serverProperties.getOrDefault("capabilities", Collections.emptyMap()); - return capabilities.getOrDefault(capability.getName(), false) == true; + return Boolean.TRUE.equals(capabilities.get(capability.getName())); } public AMQConnection(ConnectionParams params, FrameHandler frameHandler) { diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 657a571e43..66b089e496 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -395,6 +395,7 @@ private void releaseChannel() { String consumerTag = m.getConsumerTag(); Consumer callback = _consumers.remove(consumerTag); if (callback != null && getConnection().doesBrokerAcceptClientSentBasicCancelOk()) { + // The server will remove the consumer after a short timeout in any case transmit(new Basic.CancelOk(consumerTag)); } // Not finding any matching consumer isn't necessarily an indication of an issue anywhere. diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java index f909a92e51..b07a4a5dd5 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java @@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.rabbitmq.client.ServerCapability; -import java.util.Map; +import java.util.Collections; import org.junit.jupiter.api.Test; public class AMQConnectionCapabilitiesTest { @@ -27,27 +27,27 @@ public class AMQConnectionCapabilitiesTest { @Test void capabilitySetToTrueIsPresent() { assertThat(AMQConnection.doesServerHaveCapability( - Map.of("capabilities", Map.of("accept_consumer_cancel_ok", true)), + Collections.singletonMap("capabilities", Collections.singletonMap("accept_consumer_cancel_ok", true)), ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)).isTrue(); } @Test void capabilitySetToFalseIsAbsent() { assertThat(AMQConnection.doesServerHaveCapability( - Map.of("capabilities", Map.of("accept_consumer_cancel_ok", false)), + Collections.singletonMap("capabilities", Collections.singletonMap("accept_consumer_cancel_ok", false)), ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)).isFalse(); } @Test void missingCapabilityIsAbsent() { assertThat(AMQConnection.doesServerHaveCapability( - Map.of("capabilities", Map.of("consumer_cancel_notify", true)), + Collections.singletonMap("capabilities", Collections.singletonMap("consumer_cancel_notify", true)), ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)).isFalse(); } @Test void capabilityIsAbsentWithoutCapabilitiesTable() { - assertThat(AMQConnection.doesServerHaveCapability(Map.of(), ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)) + assertThat(AMQConnection.doesServerHaveCapability(Collections.emptyMap(), ServerCapability.ACCEPT_CONSUMER_CANCEL_OK)) .isFalse(); } } From 7004178522a0622d5046e13ce71d0b068f90d9b1 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Mon, 5 Oct 2026 22:14:06 -0700 Subject: [PATCH 3/5] Send `basic.cancel-ok` to capable servers even when there's no registered client callback --- .../java/com/rabbitmq/client/impl/ChannelN.java | 2 +- .../com/rabbitmq/client/test/ChannelNTest.java | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/rabbitmq/client/impl/ChannelN.java b/src/main/java/com/rabbitmq/client/impl/ChannelN.java index 66b089e496..e6856f768d 100644 --- a/src/main/java/com/rabbitmq/client/impl/ChannelN.java +++ b/src/main/java/com/rabbitmq/client/impl/ChannelN.java @@ -394,7 +394,7 @@ private void releaseChannel() { Basic.Cancel m = (Basic.Cancel)method; String consumerTag = m.getConsumerTag(); Consumer callback = _consumers.remove(consumerTag); - if (callback != null && getConnection().doesBrokerAcceptClientSentBasicCancelOk()) { + if (getConnection().doesBrokerAcceptClientSentBasicCancelOk()) { // The server will remove the consumer after a short timeout in any case transmit(new Basic.CancelOk(consumerTag)); } diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index d7b8a46afd..1d59833cdd 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -82,13 +82,25 @@ public void serverBasicCancelIsNotAnsweredWhenBrokerDoesNotAcceptCancelOk() thro } @Test - public void serverBasicCancelForUnknownConsumerIsNotAnsweredWithCancelOk() throws Exception { + public void serverBasicCancelForUnknownConsumerIsAnsweredWithCancelOkWhenBrokerAcceptsIt() throws Exception { TrafficListener trafficListener = Mockito.mock(TrafficListener.class); AMQConnection connection = connectionAcceptingConsumerCancelOk(true, trafficListener); ChannelN channel = new ChannelN(connection, 1, consumerWorkService); channel.processAsync(new AMQCommand(new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build())); + Mockito.verify(trafficListener, Mockito.times(1)).write( + Mockito.argThat(c -> c.getMethod() instanceof AMQP.Basic.CancelOk)); + } + + @Test + public void serverBasicCancelForUnknownConsumerIsNotAnsweredWhenBrokerDoesNotAcceptCancelOk() throws Exception { + TrafficListener trafficListener = Mockito.mock(TrafficListener.class); + AMQConnection connection = connectionAcceptingConsumerCancelOk(false, trafficListener); + ChannelN channel = new ChannelN(connection, 1, consumerWorkService); + + channel.processAsync(new AMQCommand(new AMQImpl.Basic.Cancel.Builder().consumerTag("does-not-exist").build())); + Mockito.verify(trafficListener, Mockito.never()).write(Mockito.any(Command.class)); } From 07f413f5403347d0d52affa04098fb13505f0182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= <514737+acogoluegnes@users.noreply.github.com> Date: Tue, 6 Oct 2026 12:04:45 +0200 Subject: [PATCH 4/5] test: fix race condition --- .../java/com/rabbitmq/client/test/ChannelNTest.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java index 1d59833cdd..2a690f14c7 100644 --- a/src/test/java/com/rabbitmq/client/test/ChannelNTest.java +++ b/src/test/java/com/rabbitmq/client/test/ChannelNTest.java @@ -166,15 +166,16 @@ private AMQConnection connectionAcceptingConsumerCancelOk( private ChannelN channelWithConsumer(AMQConnection connection, String consumerTag) throws Exception { ChannelN channel = new ChannelN(connection, 1, consumerWorkService); - new Thread(() -> { - try { - Thread.sleep(15); + // the RPC is enqueued before the request is written, so replying from the write is race-free + TrafficListener trafficListener = connection.getTrafficListener(); + Mockito.doAnswer(invocation -> { + Command command = invocation.getArgument(0); + if (command.getMethod() instanceof AMQP.Basic.Consume) { channel.handleCompleteInboundCommand( new AMQCommand(new AMQImpl.Basic.ConsumeOk(consumerTag))); - } catch (Exception e) { - throw new RuntimeException(e); } - }).start(); + return null; + }).when(trafficListener).write(Mockito.any(Command.class)); channel.basicConsume("q", false, consumerTag, new DefaultConsumer(channel)); return channel; } From 8e097839ec5e2fa4d11a78e5c8e80fcca0c46621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Cogolu=C3=A8gnes?= <514737+acogoluegnes@users.noreply.github.com> Date: Tue, 6 Oct 2026 12:07:57 +0200 Subject: [PATCH 5/5] refactor: make enum and methods package-protected --- src/main/java/com/rabbitmq/client/impl/AMQConnection.java | 2 +- .../com/rabbitmq/client/{ => impl}/ServerCapability.java | 6 +++--- .../rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) rename src/main/java/com/rabbitmq/client/{ => impl}/ServerCapability.java (94%) diff --git a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java index bae6ae81da..382d32499a 100644 --- a/src/main/java/com/rabbitmq/client/impl/AMQConnection.java +++ b/src/main/java/com/rabbitmq/client/impl/AMQConnection.java @@ -215,7 +215,7 @@ public Map getServerProperties() { return _serverProperties; } - public boolean doesServerHaveCapability(ServerCapability capability) { + boolean doesServerHaveCapability(ServerCapability capability) { return doesServerHaveCapability(_serverProperties, capability); } diff --git a/src/main/java/com/rabbitmq/client/ServerCapability.java b/src/main/java/com/rabbitmq/client/impl/ServerCapability.java similarity index 94% rename from src/main/java/com/rabbitmq/client/ServerCapability.java rename to src/main/java/com/rabbitmq/client/impl/ServerCapability.java index d05b4702d9..a35b430601 100644 --- a/src/main/java/com/rabbitmq/client/ServerCapability.java +++ b/src/main/java/com/rabbitmq/client/impl/ServerCapability.java @@ -13,13 +13,13 @@ // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. -package com.rabbitmq.client; +package com.rabbitmq.client.impl; /** * Capabilities a RabbitMQ node advertises in the capabilities table * of the connection.start server properties. */ -public enum ServerCapability { +enum ServerCapability { PUBLISHER_CONFIRMS("publisher_confirms"), EXCHANGE_EXCHANGE_BINDINGS("exchange_exchange_bindings"), @@ -38,7 +38,7 @@ public enum ServerCapability { this.name = name; } - public String getName() { + String getName() { return name; } } diff --git a/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java b/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java index b07a4a5dd5..51a1ba464b 100644 --- a/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java +++ b/src/test/java/com/rabbitmq/client/impl/AMQConnectionCapabilitiesTest.java @@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.rabbitmq.client.ServerCapability; import java.util.Collections; import org.junit.jupiter.api.Test;