GEODE-8670: ReconnectDUnitTest is hiding a NullPointerException (#5744)
* GEODE-8670: ReconnectDUnitTest is hiding a NullPointerException
1. Fixed all of the IgnorableException problems in ReconnectDUnitTest
2. Modified InternalLocator to avoid throwing a NullPointerException and
added a test for this change
* fixing invalid test - had to move it to a new class to use SystemOutRule
the rule wasn't working for some reason when I added it to
InternalLocatorIntegrationTest
* removed use of SystemOutRule, which wasn't working in Stress tests
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectDUnitTest.java
index 2bfb534..315a700 100755
--- a/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/cache30/ReconnectDUnitTest.java
@@ -134,7 +134,8 @@
@Override
public final void postSetUp() throws Exception {
- IgnoredException.addIgnoredException("ForcedDisconnectException||Possible loss of quorum");
+ IgnoredException.addIgnoredException("ForcedDisconnectException");
+ IgnoredException.addIgnoredException("Possible loss of quorum");
locatorPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
final int locPort = locatorPort;
Host.getHost(0).getVM(locatorVMNumber).invoke(new SerializableRunnable("start locator") {
@@ -264,8 +265,8 @@
props.put(MAX_NUM_RECONNECT_TRIES, "2");
// props.put("log-file", "autoReconnectVM"+VM.getCurrentVMNum()+"_"+getPID()+".log");
cache = (InternalCache) new CacheFactory(props).create();
- IgnoredException.addIgnoredException(
- "org.apache.geode.ForcedDisconnectException||Possible loss of quorum");
+ IgnoredException.addIgnoredException("org.apache.geode.ForcedDisconnectException");
+ IgnoredException.addIgnoredException("Possible loss of quorum");
Region myRegion = cache.getRegion("root" + SEPARATOR + "myRegion");
ReconnectDUnitTest.savedSystem = cache.getDistributedSystem();
myRegion.put("MyKey1", "MyValue1");
@@ -678,7 +679,8 @@
@Test
public void testReconnectWithRoleLoss() throws TimeoutException, RegionExistsException {
-
+ IgnoredException.addIgnoredException(CacheClosedException.class);
+ IgnoredException.addIgnoredException(DistributedSystemDisconnectedException.class);
final String rr1 = "RoleA";
final String rr2 = "RoleB";
final String[] requiredRoles = {rr1, rr2};
@@ -809,6 +811,7 @@
// for the 2014 8.0 release.
@Test
public void testReconnectWithRequiredRoleRegained() throws Throwable {
+ IgnoredException.addIgnoredException(DistributedSystemDisconnectedException.class);
final String rr1 = "RoleA";
// final String rr2 = "RoleB";
@@ -1115,6 +1118,9 @@
*/
@Test
public void testReconnectFailsDueToBadCacheXML() throws Exception {
+ IgnoredException.addIgnoredException(DistributedSystemDisconnectedException.class);
+ IgnoredException.addIgnoredException("Cause parsing to fail");
+ IgnoredException.addIgnoredException("Exception while initializing an instance");
Host host = getHost(0);
VM vm0 = host.getVM(0);
diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java
index 09efe36..e712508 100644
--- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java
+++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java
@@ -22,14 +22,17 @@
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
+import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Properties;
+import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
@@ -37,13 +40,16 @@
import org.mockito.quality.Strictness;
import org.apache.geode.distributed.Locator;
-import org.apache.geode.internal.logging.InternalLogWriter;
+import org.apache.geode.distributed.internal.membership.gms.membership.GMSJoinLeave;
import org.apache.geode.internal.security.SecurableCommunicationChannel;
import org.apache.geode.logging.internal.LoggingSession;
public class InternalLocatorIntegrationTest {
@Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Rule
public MockitoRule mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@Rule
@@ -52,12 +58,7 @@
private int port;
@Mock
private LoggingSession loggingSession;
- @Mock
private File logFile;
- @Mock
- private InternalLogWriter logWriter;
- @Mock
- private InternalLogWriter securityLogWriter;
private InetAddress bindAddress;
private String hostnameForClients;
@Mock
@@ -69,6 +70,8 @@
@Before
public void setUp() throws IOException {
+ // set a property to tell membership to create a new cluster
+ System.setProperty(GMSJoinLeave.BYPASS_DISCOVERY_PROPERTY, "true");
port = 0;
hostnameForClients = "";
bindAddress = null;
@@ -89,6 +92,24 @@
}
@Test
+ public void startedLocatorDoesNotAttemptReconnect() throws IOException, InterruptedException {
+ // start a locator that's not part of a cluster
+ final boolean joinCluster = false;
+ internalLocator = InternalLocator.startLocator(port, logFile, null,
+ null, bindAddress, joinCluster,
+ distributedSystemProperties, hostnameForClients, workingDirectory);
+ port = internalLocator.getPort();
+ // the locator shouldn't attempt a reconnect because it's not part of a cluster
+ internalLocator.stoppedForReconnect = true;
+ assertThat(internalLocator.attemptReconnect()).isFalse();
+ String output = FileUtils.readFileToString(logFile, Charset.defaultCharset());
+ assertThat(output).isNotEmpty();
+ assertThat(output).contains(InternalLocator.IGNORING_RECONNECT_REQUEST);
+ }
+
+
+
+ @Test
public void constructs() {
when(distributionConfig.getLogFile()).thenReturn(logFile);
when(distributionConfig.getLocators()).thenReturn("");
@@ -97,7 +118,7 @@
assertThatCode(() -> {
internalLocator =
- new InternalLocator(port, loggingSession, logFile, logWriter, securityLogWriter,
+ new InternalLocator(port, loggingSession, logFile, null, null,
bindAddress, hostnameForClients, distributedSystemProperties, distributionConfig,
workingDirectory);
}).doesNotThrowAnyException();
@@ -105,8 +126,8 @@
@Test
public void restartingClusterConfigurationDoesNotThrowException() throws IOException {
- internalLocator = InternalLocator.startLocator(port, logFile, logWriter,
- securityLogWriter, bindAddress, true,
+ internalLocator = InternalLocator.startLocator(port, logFile, null,
+ null, bindAddress, true,
distributedSystemProperties, hostnameForClients, workingDirectory);
port = internalLocator.getPort();
internalLocator.stop(true, true, false);
@@ -119,8 +140,8 @@
@Test
public void startedLocatorIsRunning() throws IOException {
- internalLocator = InternalLocator.startLocator(port, logFile, logWriter,
- securityLogWriter, bindAddress, true,
+ internalLocator = InternalLocator.startLocator(port, logFile, null,
+ null, bindAddress, true,
distributedSystemProperties, hostnameForClients, workingDirectory);
port = internalLocator.getPort();
@@ -129,8 +150,8 @@
@Test
public void startedLocatorHasLocator() throws IOException {
- internalLocator = InternalLocator.startLocator(port, logFile, logWriter,
- securityLogWriter, bindAddress, true,
+ internalLocator = InternalLocator.startLocator(port, logFile, null,
+ null, bindAddress, true,
distributedSystemProperties, hostnameForClients, workingDirectory);
port = internalLocator.getPort();
@@ -139,8 +160,8 @@
@Test
public void stoppedLocatorIsStopped() throws IOException {
- internalLocator = InternalLocator.startLocator(port, logFile, logWriter,
- securityLogWriter, bindAddress, true,
+ internalLocator = InternalLocator.startLocator(port, null, null,
+ null, bindAddress, true,
distributedSystemProperties, hostnameForClients, workingDirectory);
port = internalLocator.getPort();
@@ -151,8 +172,8 @@
@Test
public void stoppedLocatorDoesNotHaveLocator() throws IOException {
- internalLocator = InternalLocator.startLocator(port, logFile, logWriter,
- securityLogWriter, bindAddress, true,
+ internalLocator = InternalLocator.startLocator(port, null, null,
+ null, bindAddress, true,
distributedSystemProperties, hostnameForClients, workingDirectory);
port = internalLocator.getPort();
@@ -170,8 +191,8 @@
// so this would demonstrate that we would throw the exception when we encounter an error when
// calling InternalLocator.startConfigurationPersistenceService
properties.put("load-cluster-configuration-from-dir", "true");
- assertThatThrownBy(() -> InternalLocator.startLocator(port, logFile, logWriter,
- securityLogWriter, bindAddress, true,
+ assertThatThrownBy(() -> InternalLocator.startLocator(port, null, null,
+ null, bindAddress, true,
properties, hostnameForClients, workingDirectory)).isInstanceOf(RuntimeException.class);
assertThat(InternalLocator.hasLocator()).isFalse();
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
index f497776..e011936 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
@@ -156,6 +156,8 @@
*/
public static final String LOCATORS_PREFERRED_AS_COORDINATORS =
GEMFIRE_PREFIX + "disable-floating-coordinator";
+ static final String IGNORING_RECONNECT_REQUEST =
+ "ignoring request to reconnect to the cluster - there is no DistributedSystem available to reconnect.";
/**
* the locator hosted by this JVM. As of 7.0 it is a singleton.
@@ -178,7 +180,8 @@
/**
* whether the locator was stopped during forced-disconnect processing but a reconnect will occur
*/
- private volatile boolean stoppedForReconnect;
+ @VisibleForTesting
+ volatile boolean stoppedForReconnect;
private volatile boolean reconnected;
/**
@@ -1099,12 +1102,18 @@
*
* @return true if able to reconnect the locator to the new distributed system
*/
- private boolean attemptReconnect() throws InterruptedException, IOException {
+ @VisibleForTesting
+ boolean attemptReconnect() throws InterruptedException, IOException {
boolean restarted = false;
if (stoppedForReconnect) {
- logger.info("attempting to restart locator");
boolean tcpServerStarted = false;
InternalDistributedSystem system = internalDistributedSystem;
+ if (system == null) {
+ logger.info(
+ IGNORING_RECONNECT_REQUEST);
+ return false;
+ }
+ logger.info("attempting to restart locator");
long waitTime = system.getConfig().getMaxWaitTimeForReconnect() / 2;
QuorumChecker quorumChecker = null;