blob: 1f1199a2612b782fb135e2a7e344face4df315b3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal;
import static java.util.Arrays.stream;
import static java.util.Comparator.naturalOrder;
import static org.apache.geode.distributed.internal.DistributionConfig.DEFAULT_MEMBERSHIP_PORT_RANGE;
import static org.apache.geode.internal.AvailablePort.AVAILABLE_PORTS_LOWER_BOUND;
import static org.apache.geode.internal.AvailablePort.AVAILABLE_PORTS_UPPER_BOUND;
import static org.apache.geode.internal.AvailablePort.MULTICAST;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPortRange;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPortRangeKeepers;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableUDPPort;
import static org.apache.geode.internal.AvailablePortHelper.initializeUniquePortRange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeFalse;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import junitparams.naming.TestCaseName;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
import org.junit.runner.RunWith;
import org.apache.geode.internal.AvailablePort.Keeper;
import org.apache.geode.internal.lang.SystemUtils;
@RunWith(JUnitParamsRunner.class)
public class AvailablePortHelperIntegrationTest {
private Set<ServerSocket> serverSockets;
@Rule
public ErrorCollector errorCollector = new ErrorCollector();
@Before
public void setUp() {
serverSockets = new HashSet<>();
}
@After
public void tearDown() {
for (ServerSocket serverSocket : serverSockets) {
try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close();
}
} catch (IOException e) {
errorCollector.addError(e);
}
}
}
@Test
public void getRandomAvailableTCPPortRange_returnsNoPorts_ifCountIsZero() {
int[] results = getRandomAvailableTCPPortRange(0);
assertThat(results)
.isEmpty();
}
@Test
public void getRandomAvailableTCPPortRange_returnsOnePort_ifCountIsOne() {
int[] results = getRandomAvailableTCPPortRange(1);
assertThat(results)
.hasSize(1);
}
@Test
public void getRandomAvailableTCPPortRange_returnsManyPorts_ifCountIsMany() {
int[] results = getRandomAvailableTCPPortRange(10);
assertThat(results)
.hasSize(10);
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRange_returnsUsablePorts(boolean useMembershipPortRange) {
int[] results = getRandomAvailableTCPPortRange(10, useMembershipPortRange);
stream(results).forEach(port -> assertThatPort(port)
.isUsable());
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRange_returnsUniquePorts(boolean useMembershipPortRange) {
int[] results = getRandomAvailableTCPPortRange(10, useMembershipPortRange);
assertThat(results)
.doesNotHaveDuplicates();
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRange_returnsNaturallyOrderedPorts(
boolean useMembershipPortRange) {
int[] results = getRandomAvailableTCPPortRange(10, useMembershipPortRange);
assertThat(results)
.isSortedAccordingTo(naturalOrder());
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRange_returnsConsecutivePorts(
boolean useMembershipPortRange) {
int[] results = getRandomAvailableTCPPortRange(10, useMembershipPortRange);
assertThatSequence(results)
.isConsecutive();
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRange_returnsPortsInRange(boolean useMembershipPortRange) {
int lower =
useMembershipPortRange ? DEFAULT_MEMBERSHIP_PORT_RANGE[0] : AVAILABLE_PORTS_LOWER_BOUND;
int upper =
useMembershipPortRange ? DEFAULT_MEMBERSHIP_PORT_RANGE[1] : AVAILABLE_PORTS_UPPER_BOUND;
int[] results = getRandomAvailableTCPPortRange(10, useMembershipPortRange);
stream(results).forEach(port ->
assertThat(port)
.isGreaterThanOrEqualTo(lower)
.isLessThanOrEqualTo(upper));
}
@Test
public void getRandomAvailableTCPPortRangeKeepers_returnsNoKeepers_ifCountIsZero() {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(0);
assertThat(results)
.isEmpty();
}
@Test
public void getRandomAvailableTCPPortRangeKeepers_returnsOneKeeper_ifCountIsOne() {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(1);
assertThat(results)
.hasSize(1);
}
@Test
public void getRandomAvailableTCPPortRangeKeepers_returnsManyKeepers_ifCountIsMany() {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(10);
assertThat(results)
.hasSize(10);
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRangeKeepers_returnsUsableKeepers(
boolean useMembershipPortRange) {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(10, useMembershipPortRange);
results.stream().forEach(keeper ->
assertThatKeeper(keeper)
.isUsable());
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRangeKeepers_returnsUniqueKeepers(
boolean useMembershipPortRange) {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(10, useMembershipPortRange);
assertThat(keeperPorts(results))
.doesNotHaveDuplicates();
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRangeKeepers_returnsNaturallyOrderedPorts(
boolean useMembershipPortRange) {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(10, useMembershipPortRange);
assertThat(keeperPorts(results))
.isSortedAccordingTo(naturalOrder());
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRangeKeepers_returnsConsecutivePorts(
boolean useMembershipPortRange) {
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(10, useMembershipPortRange);
assertThatSequence(keeperPorts(results))
.isConsecutive();
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRangeKeepers_returnsPortsInRange(
boolean useMembershipPortRange) {
int lower =
useMembershipPortRange ? DEFAULT_MEMBERSHIP_PORT_RANGE[0] : AVAILABLE_PORTS_LOWER_BOUND;
int upper =
useMembershipPortRange ? DEFAULT_MEMBERSHIP_PORT_RANGE[1] : AVAILABLE_PORTS_UPPER_BOUND;
List<Keeper> results = getRandomAvailableTCPPortRangeKeepers(10, useMembershipPortRange);
keeperPorts(results).forEach(port ->
assertThat(port)
.isGreaterThanOrEqualTo(lower)
.isLessThanOrEqualTo(upper));
}
@Test
public void getRandomAvailableUDPPort_returnsNonZeroUdpPort() {
int udpPort = getRandomAvailableUDPPort();
assertThat(udpPort)
.isNotZero();
}
@Test
public void getRandomAvailableUDPPort_returnsAvailableUdpPort() {
int udpPort = getRandomAvailableUDPPort();
assertThat(AvailablePort.isPortAvailable(udpPort, MULTICAST))
.isTrue();
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPortRange_returnsUniqueRanges(boolean useMembershipPortRange) {
Collection<Integer> previousPorts = new HashSet<>();
for (int i = 0; i < 3; ++i) {
int[] results = getRandomAvailableTCPPortRange(5, useMembershipPortRange);
Collection<Integer> ports = toSet(results);
assertThat(previousPorts)
.doesNotContainAnyElementsOf(ports);
previousPorts.addAll(ports);
}
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void getRandomAvailableTCPPort_returnsUniqueValues(boolean useMembershipPortRange) {
Collection<Integer> previousPorts = new HashSet<>();
for (int i = 0; i < 3; ++i) {
int port = getRandomAvailableTCPPorts(1, useMembershipPortRange)[0];
assertThat(previousPorts)
.doesNotContain(port);
previousPorts.add(port);
}
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void initializeUniquePortRange_returnSamePortsForSameRange(
boolean useMembershipPortRange) {
assumeFalse(
"Windows has ports scattered throughout the range that makes this test difficult to pass consistently",
SystemUtils.isWindows());
for (int i = 0; i < 3; ++i) {
initializeUniquePortRange(i);
int[] previousPorts = getRandomAvailableTCPPorts(3, useMembershipPortRange);
initializeUniquePortRange(i);
int[] ports = getRandomAvailableTCPPorts(3, useMembershipPortRange);
assertThat(ports)
.isEqualTo(previousPorts);
}
}
@Test
@Parameters({"true", "false"})
@TestCaseName("{method}(useMembershipPortRange={0})")
public void initializeUniquePortRange_willReturnUniquePortsForUniqueRanges(
boolean useMembershipPortRange) {
assumeFalse(
"Windows has ports scattered throughout the range that makes this test difficult to pass consistently",
SystemUtils.isWindows());
Collection<Integer> previousPorts = new HashSet<>();
for (int i = 0; i < 3; ++i) {
initializeUniquePortRange(i);
int[] results = getRandomAvailableTCPPorts(5, useMembershipPortRange);
Collection<Integer> ports = toSet(results);
assertThat(previousPorts)
.doesNotContainAnyElementsOf(ports);
previousPorts.addAll(ports);
}
}
private ServerSocket createServerSocket() {
try {
ServerSocket serverSocket = new ServerSocket();
serverSockets.add(serverSocket);
return serverSocket;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private List<Integer> toList(int[] integers) {
return stream(integers)
.boxed()
.collect(Collectors.toList());
}
private Set<Integer> toSet(int[] integers) {
return stream(integers)
.boxed()
.collect(Collectors.toSet());
}
private List<Integer> keeperPorts(List<Keeper> keepers) {
return keepers.stream()
.map(Keeper::getPort)
.collect(Collectors.toList());
}
private PortAssertion assertThatPort(int port) {
return new PortAssertion(port);
}
private KeeperAssertion assertThatKeeper(Keeper keeper) {
return new KeeperAssertion(keeper);
}
private SequenceAssertion assertThatSequence(int[] integers) {
return new SequenceAssertion(toList(integers));
}
private SequenceAssertion assertThatSequence(List<Integer> integers) {
return new SequenceAssertion(integers);
}
private class PortAssertion {
private final int port;
PortAssertion(int port) {
this.port = port;
}
PortAssertion isUsable() {
try {
ServerSocket serverSocket = createServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(port));
assertThat(serverSocket.isBound()).isTrue();
assertThat(serverSocket.isClosed()).isFalse();
serverSocket.close();
assertThat(serverSocket.isClosed()).isTrue();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return this;
}
}
private class KeeperAssertion {
private final Keeper keeper;
KeeperAssertion(Keeper keeper) {
this.keeper = keeper;
}
KeeperAssertion isUsable() {
int port = keeper.getPort();
keeper.release();
assertThatPort(port).isUsable();
return this;
}
}
private class SequenceAssertion {
private final List<Integer> actual;
SequenceAssertion(List<Integer> actual) {
this.actual = actual;
assertThat(actual)
.isNotEmpty();
}
SequenceAssertion isConsecutive() {
int start = actual.get(0);
int end = actual.get(actual.size() - 1);
List<Integer> expected = IntStream.rangeClosed(start, end)
.boxed()
.collect(Collectors.toList());
assertThat(actual)
.isEqualTo(expected);
return this;
}
}
}