This is an automated email from the ASF dual-hosted git repository. zhfeng pushed a commit to branch 3.8.x in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit 532ebde6edfd4705247a2532b8ec8d3e87236878 Author: James Netherton <jamesnether...@gmail.com> AuthorDate: Thu Sep 19 12:58:42 2024 +0100 Avoid UDP port clashes in tests Fixes #6489 --- .../camel/quarkus/test/AvailablePortFinder.java | 64 ++++++++++++++++++---- .../component/netty/udp/NettyUdpTestResource.java | 2 + .../component/syslog/it/SyslogTestResource.java | 3 +- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/AvailablePortFinder.java b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/AvailablePortFinder.java index 4fce970396..c125c45d20 100644 --- a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/AvailablePortFinder.java +++ b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/AvailablePortFinder.java @@ -17,8 +17,7 @@ package org.apache.camel.quarkus.test; import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; +import java.net.DatagramSocket; import java.net.ServerSocket; import java.util.HashMap; import java.util.Map; @@ -51,22 +50,30 @@ public final class AvailablePortFinder { } /** - * Gets the next available port. + * Gets the next available TCP port. * * @throws IllegalStateException if there are no ports available * @return the available port */ public static int getNextAvailable() { + return getNextAvailable(Protocol.TCP); + } + + /** + * Gets the next available port for the given protocol. + * + * @param protocol the network protocol to reserve the port for. Either TCP or UDP + * @throws IllegalStateException if there are no ports available + * @return the available port + */ + public static int getNextAvailable(Protocol protocol) { // Using AvailablePortFinder in native applications can be problematic // E.g The reserved port may be allocated at build time and preserved indefinitely at runtime. I.e it never changes on each execution of the native application logWarningIfNativeApplication(); while (true) { - try (ServerSocket ss = new ServerSocket()) { - ss.setReuseAddress(true); - ss.bind(new InetSocketAddress((InetAddress) null, 0), 1); - - int port = ss.getLocalPort(); + try { + int port = protocol.getPort(); if (!isQuarkusReservedPort(port)) { String callerClassName = getCallerClassName(); String value = RESERVED_PORTS.putIfAbsent(port, callerClassName); @@ -82,20 +89,34 @@ public final class AvailablePortFinder { } /** - * Reserve a list of random and not in use network ports and place them in Map. + * Reserve a list of random and not in use TCP network ports and places them in Map. */ public static Map<String, Integer> reserveNetworkPorts(String... names) { return reserveNetworkPorts(Function.identity(), names); } /** - * Reserve a list of random and not in use network ports and place them in Map. + * Reserve a list of random and not in use network ports for the given protocol and places them in Map. + */ + public static Map<String, Integer> reserveNetworkPorts(Protocol protocol, String... names) { + return reserveNetworkPorts(protocol, Function.identity(), names); + } + + /** + * Reserve a list of random and not in use TCP network ports and places them in Map. */ public static <T> Map<String, T> reserveNetworkPorts(Function<Integer, T> converter, String... names) { + return reserveNetworkPorts(Protocol.TCP, converter, names); + } + + /** + * Reserve a list of random and not in use network ports for the given protocol and places them in Map. + */ + public static <T> Map<String, T> reserveNetworkPorts(Protocol protocol, Function<Integer, T> converter, String... names) { Map<String, T> reservedPorts = new HashMap<>(); for (String name : names) { - reservedPorts.put(name, converter.apply(getNextAvailable())); + reservedPorts.put(name, converter.apply(getNextAvailable(protocol))); } return reservedPorts; @@ -139,4 +160,25 @@ public final class AvailablePortFinder { + "Pass the reserved port to the native application under test with QuarkusTestResource or via an HTTP request"); } } + + public enum Protocol { + TCP, + UDP; + + int getPort() throws IOException { + if (this.equals(TCP)) { + try (ServerSocket socket = new ServerSocket()) { + socket.setReuseAddress(true); + socket.bind(null); + return socket.getLocalPort(); + } + } + + try (DatagramSocket socket = new DatagramSocket()) { + // NOTE: There's no need for socket.bind as it happens during DatagramSocket instantiation + socket.setReuseAddress(true); + return socket.getLocalPort(); + } + } + } } diff --git a/integration-tests/netty/src/test/java/org/apache/camel/quarkus/component/netty/udp/NettyUdpTestResource.java b/integration-tests/netty/src/test/java/org/apache/camel/quarkus/component/netty/udp/NettyUdpTestResource.java index 776c7af0b7..f05caea245 100644 --- a/integration-tests/netty/src/test/java/org/apache/camel/quarkus/component/netty/udp/NettyUdpTestResource.java +++ b/integration-tests/netty/src/test/java/org/apache/camel/quarkus/component/netty/udp/NettyUdpTestResource.java @@ -21,11 +21,13 @@ import java.util.Objects; import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; import org.apache.camel.quarkus.test.AvailablePortFinder; +import org.apache.camel.quarkus.test.AvailablePortFinder.Protocol; public class NettyUdpTestResource implements QuarkusTestResourceLifecycleManager { @Override public Map<String, String> start() { return AvailablePortFinder.reserveNetworkPorts( + Protocol.UDP, Objects::toString, "camel.netty.test-udp-port", "camel.netty.test-codec-udp-port", diff --git a/integration-tests/syslog/src/test/java/org/apache/camel/quarkus/component/syslog/it/SyslogTestResource.java b/integration-tests/syslog/src/test/java/org/apache/camel/quarkus/component/syslog/it/SyslogTestResource.java index d875db16dc..e42d4ff501 100644 --- a/integration-tests/syslog/src/test/java/org/apache/camel/quarkus/component/syslog/it/SyslogTestResource.java +++ b/integration-tests/syslog/src/test/java/org/apache/camel/quarkus/component/syslog/it/SyslogTestResource.java @@ -21,12 +21,13 @@ import java.util.Objects; import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; import org.apache.camel.quarkus.test.AvailablePortFinder; +import org.apache.camel.quarkus.test.AvailablePortFinder.Protocol; public class SyslogTestResource implements QuarkusTestResourceLifecycleManager { @Override public Map<String, String> start() { - return AvailablePortFinder.reserveNetworkPorts(Objects::toString, "camel.netty.rfc5425.port", + return AvailablePortFinder.reserveNetworkPorts(Protocol.UDP, Objects::toString, "camel.netty.rfc5425.port", "camel.netty.rfc3164.port"); }