This is an automated email from the ASF dual-hosted git repository.
szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git
The following commit(s) were added to refs/heads/master by this push:
new 54750b3e1 RATIS-1981. Avoid random ports in tests (#996)
54750b3e1 is described below
commit 54750b3e1dd0323071993685d8640f288a67d988
Author: Doroszlai, Attila <[email protected]>
AuthorDate: Wed Dec 20 16:26:43 2023 +0100
RATIS-1981. Avoid random ports in tests (#996)
---
.../main/java/org/apache/ratis/util/NetUtils.java | 68 +++++++++++++++-------
.../java/org/apache/ratis/util/TestNetUtils.java | 25 +++++++-
.../apache/ratis/server/impl/MiniRaftCluster.java | 26 ++++-----
.../datastream/TestNettyDataStreamWithMock.java | 9 +--
.../apache/ratis/grpc/util/TestGrpcZeroCopy.java | 7 +--
.../grpc/util/TestStreamObserverWithTimeout.java | 6 +-
6 files changed, 88 insertions(+), 53 deletions(-)
diff --git a/ratis-common/src/main/java/org/apache/ratis/util/NetUtils.java
b/ratis-common/src/main/java/org/apache/ratis/util/NetUtils.java
index 39d0b76ca..a6ce5af79 100644
--- a/ratis-common/src/main/java/org/apache/ratis/util/NetUtils.java
+++ b/ratis-common/src/main/java/org/apache/ratis/util/NetUtils.java
@@ -20,15 +20,14 @@ package org.apache.ratis.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.Closeable;
import java.io.IOException;
-import java.io.UncheckedIOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
public interface NetUtils {
Logger LOG = LoggerFactory.getLogger(NetUtils.class);
@@ -123,21 +122,11 @@ public interface NetUtils {
* @param count number of unique local addresses to create
* @return {@code count} number of unique local addresses
*/
+ @Deprecated
static List<InetSocketAddress> createLocalServerAddress(int count) {
List<InetSocketAddress> list = new ArrayList<>(count);
- List<ServerSocket> sockets = new ArrayList<>(count);
- try {
- for (int i = 0; i < count; i++) {
- ServerSocket s = new ServerSocket();
- sockets.add(s);
- s.setReuseAddress(true);
- s.bind(new InetSocketAddress(InetAddress.getByName(null), 0), 1);
- list.add((InetSocketAddress) s.getLocalSocketAddress());
- }
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } finally {
- IOUtils.cleanup(null, sockets.toArray(new Closeable[0]));
+ for (int i = 0; i < count; i++) {
+ list.add(new InetSocketAddress(LOCALHOST, getFreePort()));
}
return list;
}
@@ -147,14 +136,9 @@ public interface NetUtils {
* the loopback interface.
* @return unique local address
*/
+ @Deprecated
static InetSocketAddress createLocalServerAddress() {
- try(ServerSocket s = new ServerSocket()) {
- s.setReuseAddress(true);
- s.bind(new InetSocketAddress(InetAddress.getByName(null), 0), 1);
- return (InetSocketAddress) s.getLocalSocketAddress();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ return new InetSocketAddress(LOCALHOST, getFreePort());
}
static String address2String(InetSocketAddress address) {
@@ -167,4 +151,44 @@ public interface NetUtils {
}
return b.append(':').append(address.getPort()).toString();
}
+
+ String LOCALHOST = "localhost";
+
+ static String localhostWithFreePort() {
+ return LOCALHOST + ":" + getFreePort();
+ }
+
+ static int getFreePort() {
+ return PortAllocator.getFreePort();
+ }
+
+ /**
+ * Helper class to get free port avoiding randomness.
+ */
+ final class PortAllocator {
+
+ private static final int MIN_PORT = 15000;
+ private static final int MAX_PORT = 32000;
+ private static final AtomicInteger NEXT_PORT = new AtomicInteger(MIN_PORT);
+
+ private PortAllocator() {
+ // no instances
+ }
+
+ public static synchronized int getFreePort() {
+ while (true) {
+ int port = NEXT_PORT.getAndIncrement();
+ if (port > MAX_PORT) {
+ NEXT_PORT.set(MIN_PORT);
+ port = NEXT_PORT.getAndIncrement();
+ }
+ try (ServerSocket ignored = new ServerSocket(port)) {
+ return port;
+ } catch (IOException e) {
+ // will try next port
+ }
+ }
+ }
+ }
+
}
diff --git a/ratis-common/src/test/java/org/apache/ratis/util/TestNetUtils.java
b/ratis-common/src/test/java/org/apache/ratis/util/TestNetUtils.java
index 6fb85e263..2bed8e30d 100644
--- a/ratis-common/src/test/java/org/apache/ratis/util/TestNetUtils.java
+++ b/ratis-common/src/test/java/org/apache/ratis/util/TestNetUtils.java
@@ -20,17 +20,38 @@ package org.apache.ratis.util;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.io.IOException;
import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
-public class TestNetUtils {
+class TestNetUtils {
@Test
- public void createsUniqueAddresses() {
+ void createsUniqueAddresses() {
for (int i = 0; i < 10; i++) {
List<InetSocketAddress> addresses =
NetUtils.createLocalServerAddress(100);
Assertions.assertEquals(addresses.stream().distinct().collect(Collectors.toList()),
addresses);
}
}
+
+ @Test
+ void returnsUniquePorts() {
+ List<Integer> addresses = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ addresses.add(NetUtils.getFreePort());
+ }
+
Assertions.assertEquals(addresses.stream().distinct().collect(Collectors.toList()),
addresses);
+ }
+
+ @Test
+ void skipsUsedPort() throws IOException {
+ int port = NetUtils.getFreePort();
+ try (ServerSocket ignored = new ServerSocket(port + 1)) {
+ int nextPort = NetUtils.getFreePort();
+ Assertions.assertEquals(port + 2, nextPort);
+ }
+ }
}
diff --git
a/ratis-server/src/test/java/org/apache/ratis/server/impl/MiniRaftCluster.java
b/ratis-server/src/test/java/org/apache/ratis/server/impl/MiniRaftCluster.java
index 795ca6d4f..f6dd6121c 100644
---
a/ratis-server/src/test/java/org/apache/ratis/server/impl/MiniRaftCluster.java
+++
b/ratis-server/src/test/java/org/apache/ratis/server/impl/MiniRaftCluster.java
@@ -64,7 +64,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -229,9 +228,10 @@ public abstract class MiniRaftCluster implements Closeable
{
}
private int getPort(String address) {
- final InetSocketAddress inetAddress = address != null?
- NetUtils.createSocketAddr(address):
NetUtils.createLocalServerAddress();
- return inetAddress.getPort();
+ return Optional.ofNullable(address)
+ .map(NetUtils::createSocketAddr)
+ .map(InetSocketAddress::getPort)
+ .orElseGet(NetUtils::getFreePort);
}
}
@@ -248,14 +248,13 @@ public abstract class MiniRaftCluster implements
Closeable {
}
public static RaftGroup initRaftGroup(Collection<String> ids,
Collection<String> listenerIds) {
- Iterator<InetSocketAddress> addresses =
NetUtils.createLocalServerAddress(4 * (ids.size() +
listenerIds.size())).iterator();
Stream<RaftPeer> peer = ids.stream()
.map(id -> RaftPeer.newBuilder().setId(id))
- .map(p -> assignAddresses(p, addresses))
+ .map(MiniRaftCluster::assignAddresses)
.map(RaftPeer.Builder::build);
Stream<RaftPeer> listener = listenerIds.stream()
.map(id -> RaftPeer.newBuilder().setId(id))
- .map(p -> assignAddresses(p, addresses))
+ .map(MiniRaftCluster::assignAddresses)
.map(p -> p.setStartupRole(RaftProtos.RaftPeerRole.LISTENER))
.map(RaftPeer.Builder::build);
final RaftPeer[] peers = Stream.concat(peer,
listener).toArray(RaftPeer[]::new);
@@ -263,12 +262,12 @@ public abstract class MiniRaftCluster implements
Closeable {
return RaftGroup.valueOf(RaftGroupId.randomId(), peers);
}
- private static RaftPeer.Builder assignAddresses(RaftPeer.Builder builder,
Iterator<InetSocketAddress> addresses) {
+ private static RaftPeer.Builder assignAddresses(RaftPeer.Builder builder) {
return builder
- .setAddress(addresses.next())
- .setAdminAddress(addresses.next())
- .setClientAddress(addresses.next())
- .setDataStreamAddress(addresses.next());
+ .setAddress(NetUtils.localhostWithFreePort())
+ .setAdminAddress(NetUtils.localhostWithFreePort())
+ .setClientAddress(NetUtils.localhostWithFreePort())
+ .setDataStreamAddress(NetUtils.localhostWithFreePort());
}
private final Supplier<File> rootTestDir = JavaUtils.memoize(
@@ -468,11 +467,10 @@ public abstract class MiniRaftCluster implements
Closeable {
if (emptyPeer) {
raftGroup = RaftGroup.valueOf(group.getGroupId(),
Collections.emptyList());
} else {
- Iterator<InetSocketAddress> addresses =
NetUtils.createLocalServerAddress(4 * ids.length).iterator();
final Collection<RaftPeer> newPeers =
StreamSupport.stream(peerIds.spliterator(), false)
.map(id -> RaftPeer.newBuilder().setId(id)
.setStartupRole(startRole))
- .map(p -> assignAddresses(p, addresses))
+ .map(MiniRaftCluster::assignAddresses)
.map(RaftPeer.Builder::build)
.collect(Collectors.toSet());
newPeers.addAll(group.getPeers());
diff --git
a/ratis-test/src/test/java/org/apache/ratis/datastream/TestNettyDataStreamWithMock.java
b/ratis-test/src/test/java/org/apache/ratis/datastream/TestNettyDataStreamWithMock.java
index 64fa59e40..27a1ee102 100644
---
a/ratis-test/src/test/java/org/apache/ratis/datastream/TestNettyDataStreamWithMock.java
+++
b/ratis-test/src/test/java/org/apache/ratis/datastream/TestNettyDataStreamWithMock.java
@@ -19,7 +19,6 @@
package org.apache.ratis.datastream;
import java.io.IOException;
-import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -47,12 +46,10 @@ import static org.mockito.Mockito.when;
@Ignore
public class TestNettyDataStreamWithMock extends DataStreamBaseTest {
static RaftPeer newRaftPeer(RaftServer server) {
- final InetSocketAddress rpc = NetUtils.createLocalServerAddress();
- final int dataStreamPort =
NettyConfigKeys.DataStream.port(server.getProperties());
return RaftPeer.newBuilder()
.setId(server.getId())
- .setAddress(rpc)
-
.setDataStreamAddress(NetUtils.createSocketAddrForHost(rpc.getHostName(),
dataStreamPort))
+ .setAddress(NetUtils.localhostWithFreePort())
+ .setDataStreamAddress(NetUtils.localhostWithFreePort())
.build();
}
@@ -91,7 +88,7 @@ public class TestNettyDataStreamWithMock extends
DataStreamBaseTest {
RaftServer raftServer = mock(RaftServer.class);
RaftPeerId peerId = RaftPeerId.valueOf("s" + i);
RaftProperties properties = new RaftProperties();
- NettyConfigKeys.DataStream.setPort(properties,
NetUtils.createLocalServerAddress().getPort());
+ NettyConfigKeys.DataStream.setPort(properties, NetUtils.getFreePort());
RaftConfigKeys.DataStream.setType(properties,
SupportedDataStreamType.NETTY);
when(raftServer.getProperties()).thenReturn(properties);
diff --git
a/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestGrpcZeroCopy.java
b/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestGrpcZeroCopy.java
index a4592a118..032a9c1db 100644
--- a/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestGrpcZeroCopy.java
+++ b/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestGrpcZeroCopy.java
@@ -29,7 +29,6 @@ import org.apache.ratis.util.TraditionalBinaryPrefix;
import org.junit.Assert;
import org.junit.Test;
-import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@@ -110,11 +109,9 @@ public final class TestGrpcZeroCopy extends BaseTest {
}
void runTestZeroCopy() throws Exception {
- final InetSocketAddress address = NetUtils.createLocalServerAddress();
-
- try (GrpcZeroCopyTestServer server = new
GrpcZeroCopyTestServer(address.getPort())) {
+ try (GrpcZeroCopyTestServer server = new
GrpcZeroCopyTestServer(NetUtils.getFreePort())) {
final int port = server.start();
- try (GrpcZeroCopyTestClient client = new
GrpcZeroCopyTestClient(address.getHostName(), port)) {
+ try (GrpcZeroCopyTestClient client = new
GrpcZeroCopyTestClient(NetUtils.LOCALHOST, port)) {
sendMessages(5, client, server);
sendBinaries(11, client, server);
}
diff --git
a/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestStreamObserverWithTimeout.java
b/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestStreamObserverWithTimeout.java
index 89349cc87..7a32fb96a 100644
---
a/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestStreamObserverWithTimeout.java
+++
b/ratis-test/src/test/java/org/apache/ratis/grpc/util/TestStreamObserverWithTimeout.java
@@ -28,7 +28,6 @@ import org.junit.Assert;
import org.junit.Test;
import org.slf4j.event.Level;
-import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -80,15 +79,14 @@ public class TestStreamObserverWithTimeout extends BaseTest
{
LOG.info("slow = {}, {}", slow, type);
final TimeDuration timeout = ONE_SECOND.multiply(0.5);
final StreamObserverFactory function = type.createFunction(timeout);
- final InetSocketAddress address = NetUtils.createLocalServerAddress();
final List<String> messages = new ArrayList<>();
for (int i = 0; i < 2 * slow; i++) {
messages.add("m" + i);
}
- try (GrpcTestServer server = new GrpcTestServer(address.getPort(), slow,
timeout)) {
+ try (GrpcTestServer server = new GrpcTestServer(NetUtils.getFreePort(),
slow, timeout)) {
final int port = server.start();
- try (GrpcTestClient client = new GrpcTestClient(address.getHostName(),
port, function)) {
+ try (GrpcTestClient client = new GrpcTestClient(NetUtils.LOCALHOST,
port, function)) {
final List<CompletableFuture<String>> futures = new ArrayList<>();
for (String m : messages) {