You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by bo...@apache.org on 2018/08/06 20:53:37 UTC
[geode] branch develop updated: GEODE-5502: Removed duplicate /
member-specific receivers from cluster configuration
This is an automated email from the ASF dual-hosted git repository.
boglesby pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 2ae2b59 GEODE-5502: Removed duplicate / member-specific receivers from cluster configuration
2ae2b59 is described below
commit 2ae2b591378a2cae8f5dee8f01bc07de8cce6d6e
Author: Barry Oglesby <bo...@users.noreply.github.com>
AuthorDate: Mon Aug 6 13:53:32 2018 -0700
GEODE-5502: Removed duplicate / member-specific receivers from cluster configuration
---
.../InternalConfigurationPersistenceService.java | 62 ++++-
...nternalConfigurationPersistenceServiceTest.java | 128 ++++++++++-
.../test/dunit/standalone/VersionManager.java | 1 +
.../cache/wan/WANRollingUpgradeDUnitTest.java | 43 +++-
...ipleReceiversDefinedInClusterConfiguration.java | 254 +++++++++++++++++++++
5 files changed, 480 insertions(+), 8 deletions(-)
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
index a6d7380..fae9b74 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
@@ -128,7 +128,7 @@ public class InternalConfigurationPersistenceService implements ConfigurationPer
/**
* Name of the region which is used to store the configuration information
*/
- private static final String CONFIG_REGION_NAME = "_ConfigurationRegion";
+ public static final String CONFIG_REGION_NAME = "_ConfigurationRegion";
private final String configDirPath;
private final String configDiskDirPath;
@@ -517,6 +517,7 @@ public class InternalConfigurationPersistenceService implements ConfigurationPer
this.status.set(SharedConfigurationStatus.STARTED);
Region<String, Configuration> configRegion = this.getConfigurationRegion();
lockSharedConfiguration();
+ removeInvalidXmlConfigurations(configRegion);
try {
if (loadSharedConfigFromDir) {
logger.info("Reading cluster configuration from '{}' directory",
@@ -543,6 +544,65 @@ public class InternalConfigurationPersistenceService implements ConfigurationPer
this.status.set(SharedConfigurationStatus.RUNNING);
}
+ void removeInvalidXmlConfigurations(Region<String, Configuration> configRegion)
+ throws IOException, SAXException, ParserConfigurationException, TransformerException {
+ for (Map.Entry<String, Configuration> entry : configRegion.entrySet()) {
+ String group = entry.getKey();
+ Configuration configuration = entry.getValue();
+ String configurationXml = configuration.getCacheXmlContent();
+ if (configurationXml != null && !configurationXml.isEmpty()) {
+ Document document = XmlUtils.createDocumentFromXml(configurationXml);
+ boolean removedInvalidReceivers = removeInvalidGatewayReceivers(document);
+ boolean removedDuplicateReceivers = removeDuplicateGatewayReceivers(document);
+ if (removedInvalidReceivers || removedDuplicateReceivers) {
+ configuration.setCacheXmlContent(XmlUtils.prettyXml(document));
+ configRegion.put(group, configuration);
+ }
+ }
+ }
+ }
+
+ boolean removeInvalidGatewayReceivers(Document document) throws TransformerException {
+ boolean modified = false;
+ NodeList receiverNodes = document.getElementsByTagName("gateway-receiver");
+ for (int i = receiverNodes.getLength() - 1; i >= 0; i--) {
+ Element receiverElement = (Element) receiverNodes.item(i);
+
+ // Check hostname-for-senders
+ String hostNameForSenders = receiverElement.getAttribute("hostname-for-senders");
+ if (StringUtils.isNotBlank(hostNameForSenders)) {
+ receiverElement.getParentNode().removeChild(receiverElement);
+ logger.info("Removed invalid cluster configuration gateway-receiver element="
+ + XmlUtils.prettyXml(receiverElement));
+ modified = true;
+ }
+
+ // Check bind-address
+ String bindAddress = receiverElement.getAttribute("bind-address");
+ if (StringUtils.isNotBlank(bindAddress) && !bindAddress.equals("0.0.0.0")) {
+ receiverElement.getParentNode().removeChild(receiverElement);
+ logger.info("Removed invalid cluster configuration gateway-receiver element="
+ + XmlUtils.prettyXml(receiverElement));
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ boolean removeDuplicateGatewayReceivers(Document document) throws TransformerException {
+ boolean modified = false;
+ NodeList receiverNodes = document.getElementsByTagName("gateway-receiver");
+ while (receiverNodes.getLength() > 1) {
+ Element receiverElement = (Element) receiverNodes.item(0);
+ receiverElement.getParentNode().removeChild(receiverElement);
+ logger.info("Removed duplicate cluster configuration gateway-receiver element="
+ + XmlUtils.prettyXml(receiverElement));
+ modified = true;
+ receiverNodes = document.getElementsByTagName("gateway-receiver");
+ }
+ return modified;
+ }
+
private void persistSecuritySettings(final Region<String, Configuration> configRegion) {
Properties securityProps = this.cache.getDistributedSystem().getSecurityProperties();
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceServiceTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceServiceTest.java
index e658fc9..6dbf018 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceServiceTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceServiceTest.java
@@ -17,6 +17,7 @@
package org.apache.geode.distributed.internal;
+import static junitparams.JUnitParamsRunner.$;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -27,10 +28,19 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.runner.RunWith;
+import org.w3c.dom.Document;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.configuration.CacheConfig;
@@ -41,8 +51,9 @@ import org.apache.geode.internal.config.JAXBServiceTest.ElementOne;
import org.apache.geode.internal.config.JAXBServiceTest.ElementTwo;
import org.apache.geode.internal.lang.SystemPropertyHelper;
import org.apache.geode.management.internal.configuration.domain.Configuration;
+import org.apache.geode.management.internal.configuration.utils.XmlUtils;
-
+@RunWith(JUnitParamsRunner.class)
public class InternalConfigurationPersistenceServiceTest {
private InternalConfigurationPersistenceService service, service2;
private Configuration configuration;
@@ -193,4 +204,119 @@ public class InternalConfigurationPersistenceServiceTest {
assertThat(packages).hasSize(2);
assertThat(packages).contains("org.apache.geode", "io.pivotal");
}
+
+ @Test
+ public void updateGatewayReceiverConfig() {
+ service.updateCacheConfig("cluster", cacheConfig -> {
+ CacheConfig.GatewayReceiver receiver = new CacheConfig.GatewayReceiver();
+ cacheConfig.setGatewayReceiver(receiver);
+ return cacheConfig;
+ });
+
+ System.out.println(configuration.getCacheXmlContent());
+ assertThat(configuration.getCacheXmlContent()).contains("<gateway-receiver/>");
+ }
+
+ @Test
+ public void removeDuplicateGatewayReceiversWithDefaultProperties() throws Exception {
+ Document document =
+ XmlUtils.createDocumentFromXml(getDuplicateReceiversWithDefaultPropertiesXml());
+ System.out.println("Initial document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(2);
+ service.removeDuplicateGatewayReceivers(document);
+ System.out.println("Processed document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(1);
+ }
+
+ @Test
+ public void removeInvalidGatewayReceiversWithDifferentHostNameForSenders() throws Exception {
+ Document document =
+ XmlUtils.createDocumentFromXml(getDuplicateReceiversWithDifferentHostNameForSendersXml());
+ System.out.println("Initial document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(2);
+ service.removeInvalidGatewayReceivers(document);
+ System.out.println("Processed document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(0);
+ }
+
+ @Test
+ public void removeInvalidGatewayReceiversWithDifferentBindAddresses() throws Exception {
+ Document document =
+ XmlUtils.createDocumentFromXml(getDuplicateReceiversWithDifferentBindAddressesXml());
+ System.out.println("Initial document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(2);
+ service.removeInvalidGatewayReceivers(document);
+ System.out.println("Processed document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(0);
+ }
+
+ @Test
+ public void keepValidGatewayReceiversWithDefaultBindAddress() throws Exception {
+ Document document =
+ XmlUtils.createDocumentFromXml(getSingleReceiverWithDefaultBindAddressXml());
+ System.out.println("Initial document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(1);
+ service.removeInvalidGatewayReceivers(document);
+ System.out.println("Processed document:\n" + XmlUtils.prettyXml(document));
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength()).isEqualTo(1);
+ }
+
+ @Test
+ @Parameters(method = "getXmlAndExpectedElements")
+ public void removeInvalidXmlConfiguration(String xml, int expectedInitialElements,
+ int expectFinalElements) throws Exception {
+ Region<String, Configuration> configurationRegion = mock(Region.class);
+ configuration.setCacheXmlContent(xml);
+ System.out.println("Initial xml content:\n" + configuration.getCacheXmlContent());
+ Document document = XmlUtils.createDocumentFromXml(configuration.getCacheXmlContent());
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength())
+ .isEqualTo(expectedInitialElements);
+ Set<Map.Entry<String, Configuration>> configurationEntries = new HashSet<>();
+ configurationEntries.add(new AbstractMap.SimpleEntry<>("cluster", configuration));
+ doReturn(configurationEntries).when(configurationRegion).entrySet();
+ service.removeInvalidXmlConfigurations(configurationRegion);
+ System.out.println("Processed xml content:\n" + configuration.getCacheXmlContent());
+ document = XmlUtils.createDocumentFromXml(configuration.getCacheXmlContent());
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength())
+ .isEqualTo(expectFinalElements);
+ }
+
+ private String getDuplicateReceiversWithDefaultPropertiesXml() {
+ return "<cache>\n<gateway-receiver/>\n<gateway-receiver/>\n</cache>";
+ }
+
+ private String getDuplicateReceiversWithDifferentHostNameForSendersXml() {
+ return "<cache>\n<gateway-receiver hostname-for-senders=\"123.12.12.12\"/>\n<gateway-receiver hostname-for-senders=\"123.12.12.11\"/>\n</cache>";
+ }
+
+ private String getDuplicateReceiversWithDifferentBindAddressesXml() {
+ return "<cache>\n<gateway-receiver bind-address=\"123.12.12.12\"/>\n<gateway-receiver bind-address=\"123.12.12.11\"/>\n</cache>";
+ }
+
+ private String getSingleReceiverWithDefaultBindAddressXml() {
+ return "<cache>\n<gateway-receiver bind-address=\"0.0.0.0\"/>\n</cache>";
+ }
+
+ private String getDuplicateReceiversWithDefaultBindAddressesXml() {
+ return "<cache>\n<gateway-receiver bind-address=\"0.0.0.0\"/>\n<gateway-receiver bind-address=\"0.0.0.0\"/>\n</cache>";
+ }
+
+ private String getValidReceiversXml() {
+ return "<cache>\n<gateway-receiver/>\n</cache>";
+ }
+
+ private String getNoReceiversXml() {
+ return "<cache>\n</cache>";
+ }
+
+ protected Object[] getXmlAndExpectedElements() {
+ return $(
+ new Object[] {getDuplicateReceiversWithDefaultPropertiesXml(), 2, 1},
+ new Object[] {getDuplicateReceiversWithDifferentHostNameForSendersXml(), 2, 0},
+ new Object[] {getDuplicateReceiversWithDifferentBindAddressesXml(), 2, 0},
+ new Object[] {getSingleReceiverWithDefaultBindAddressXml(), 1, 1},
+ new Object[] {getDuplicateReceiversWithDefaultBindAddressesXml(), 2, 1},
+ new Object[] {getValidReceiversXml(), 1, 1},
+ new Object[] {getNoReceiversXml(), 0, 0});
+ }
}
diff --git a/geode-junit/src/main/java/org/apache/geode/test/dunit/standalone/VersionManager.java b/geode-junit/src/main/java/org/apache/geode/test/dunit/standalone/VersionManager.java
index b711193..942a939 100755
--- a/geode-junit/src/main/java/org/apache/geode/test/dunit/standalone/VersionManager.java
+++ b/geode-junit/src/main/java/org/apache/geode/test/dunit/standalone/VersionManager.java
@@ -39,6 +39,7 @@ public class VersionManager {
public static final String GEODE_110 = "110";
public static final String GEODE_120 = "120";
public static final String GEODE_130 = "130";
+ public static final String GEODE_140 = "140";
private static VersionManager instance;
diff --git a/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeDUnitTest.java b/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeDUnitTest.java
index e9c55ba..3263237 100644
--- a/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeDUnitTest.java
+++ b/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeDUnitTest.java
@@ -23,6 +23,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.REMOTE_LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
@@ -72,7 +73,7 @@ import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactor
@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
public abstract class WANRollingUpgradeDUnitTest extends JUnit4CacheTestCase {
@Parameterized.Parameters(name = "from_v{0}")
- public static Collection<String> data() {
+ public static Collection data() {
List<String> result = VersionManager.getInstance().getVersionsWithoutCurrent();
if (result.size() < 1) {
throw new RuntimeException("No older versions of Geode were found to test against");
@@ -89,9 +90,16 @@ public abstract class WANRollingUpgradeDUnitTest extends JUnit4CacheTestCase {
@Rule
public transient GfshCommandRule gfsh = new GfshCommandRule();
- public void startLocator(int port, int distributedSystemId, String locators,
+ void startLocator(int port, int distributedSystemId, String locators,
String remoteLocators) throws IOException {
- Properties props = getLocatorProperties(distributedSystemId, locators, remoteLocators);
+ startLocator(port, distributedSystemId, locators,
+ remoteLocators, false);
+ }
+
+ void startLocator(int port, int distributedSystemId, String locators,
+ String remoteLocators, boolean enableClusterConfiguration) throws IOException {
+ Properties props = getLocatorProperties(distributedSystemId, locators, remoteLocators,
+ enableClusterConfiguration);
Locator.startLocatorAndDS(port, null, props);
}
@@ -108,13 +116,22 @@ public abstract class WANRollingUpgradeDUnitTest extends JUnit4CacheTestCase {
private Properties getLocatorProperties(int distributedSystemId, String locators,
String remoteLocators) {
+ return getLocatorProperties(distributedSystemId, locators,
+ remoteLocators, false);
+ }
+
+
+ private Properties getLocatorProperties(int distributedSystemId, String locators,
+ String remoteLocators, boolean enableClusterConfiguration) {
Properties props = new Properties();
props.setProperty(MCAST_PORT, "0");
props.setProperty(DISTRIBUTED_SYSTEM_ID, String.valueOf(distributedSystemId));
props.setProperty(LOCATORS, locators);
- props.setProperty(REMOTE_LOCATORS, remoteLocators);
+ if (remoteLocators != null) {
+ props.setProperty(REMOTE_LOCATORS, remoteLocators);
+ }
props.setProperty(LOG_LEVEL, DUnitLauncher.logLevel);
- props.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false");
+ props.setProperty(ENABLE_CLUSTER_CONFIGURATION, String.valueOf(enableClusterConfiguration));
return props;
}
@@ -124,9 +141,16 @@ public abstract class WANRollingUpgradeDUnitTest extends JUnit4CacheTestCase {
VM rollLocatorToCurrent(VM rollLocator, int port, int distributedSystemId,
String locators, String remoteLocators) {
+ return rollLocatorToCurrent(rollLocator, port, distributedSystemId,
+ locators, remoteLocators, false);
+ }
+
+ VM rollLocatorToCurrent(VM rollLocator, int port, int distributedSystemId,
+ String locators, String remoteLocators, boolean enableClusterConfiguration) {
rollLocator.invoke(() -> stopLocator());
VM newLocator = Host.getHost(0).getVM(VersionManager.CURRENT_VERSION, rollLocator.getId());
- newLocator.invoke(() -> startLocator(port, distributedSystemId, locators, remoteLocators));
+ newLocator.invoke(() -> startLocator(port, distributedSystemId, locators, remoteLocators,
+ enableClusterConfiguration));
return newLocator;
}
@@ -219,7 +243,14 @@ public abstract class WANRollingUpgradeDUnitTest extends JUnit4CacheTestCase {
}
public void createCache(String locators) {
+ createCache(locators, false, false);
+ }
+
+ public void createCache(String locators, boolean enableClusterConfiguration,
+ boolean useClusterConfiguration) {
Properties props = new Properties();
+ props.setProperty(ENABLE_CLUSTER_CONFIGURATION, String.valueOf(enableClusterConfiguration));
+ props.setProperty(USE_CLUSTER_CONFIGURATION, String.valueOf(useClusterConfiguration));
props.setProperty(MCAST_PORT, "0");
props.setProperty(LOCATORS, locators);
props.setProperty(LOG_LEVEL, DUnitLauncher.logLevel);
diff --git a/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeMultipleReceiversDefinedInClusterConfiguration.java b/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeMultipleReceiversDefinedInClusterConfiguration.java
new file mode 100644
index 0000000..aecd3e5
--- /dev/null
+++ b/geode-wan/src/upgradeTest/java/org/apache/geode/cache/wan/WANRollingUpgradeMultipleReceiversDefinedInClusterConfiguration.java
@@ -0,0 +1,254 @@
+/*
+ * 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.cache.wan;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.awaitility.Awaitility;
+import org.junit.Test;
+import org.junit.runners.Parameterized;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Region;
+import org.apache.geode.distributed.ConfigurationPersistenceService;
+import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
+import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.internal.AvailablePort;
+import org.apache.geode.internal.cache.xmlcache.CacheCreation;
+import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator;
+import org.apache.geode.management.internal.configuration.domain.Configuration;
+import org.apache.geode.management.internal.configuration.utils.XmlUtils;
+import org.apache.geode.test.dunit.DistributedTestUtils;
+import org.apache.geode.test.dunit.Host;
+import org.apache.geode.test.dunit.NetworkUtils;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.standalone.VersionManager;
+
+public class WANRollingUpgradeMultipleReceiversDefinedInClusterConfiguration
+ extends WANRollingUpgradeDUnitTest {
+
+ @Parameterized.Parameter(1)
+ public List<Attribute> attributes;
+
+ @Parameterized.Parameter(2)
+ public int expectedReceiverElements;
+
+ @Parameterized.Parameter(3)
+ public int expectedReceivers;
+
+ @Parameterized.Parameters(name = "from_v{0}; attributes={1}; expectedReceiverCount={2}")
+ public static Collection data() {
+ // Get initial versions to test against
+ List<String> versions = getVersionsToTest();
+
+ // Build up a list of version->attributes->expectedReceivers
+ List<Object[]> result = new ArrayList<>();
+ versions.forEach(version -> {
+ // Add a case for hostname-for-senders
+ addReceiversWithHostNameForSenders(result, version);
+
+ // Add a case for bind-address
+ addReceiversWithBindAddresses(result, version);
+
+ // Add a case for multiple receivers with default attributes
+ addMultipleReceiversWithDefaultAttributes(result, version);
+
+ // Add a case for single receiver with default bind-address
+ addSingleReceiverWithDefaultBindAddress(result, version);
+
+ // Add a case for single receiver with default attributes
+ addSingleReceiverWithDefaultAttributes(result, version);
+ });
+
+ System.out.println("running against these versions and attributes: "
+ + result.stream().map(entry -> Arrays.toString(entry)).collect(
+ Collectors.joining(", ")));
+ return result;
+ }
+
+ private static List<String> getVersionsToTest() {
+ // There is no need to test old versions beyond 130. Individual member configuration is not
+ // saved in cluster configuration and multiple receivers are not supported starting in 140.
+ // Note: This comparison works because '130' < '140'.
+ List<String> result = VersionManager.getInstance().getVersionsWithoutCurrent();
+ result.removeIf(version -> (version.compareTo(VersionManager.GEODE_140) >= 0));
+ if (result.size() < 1) {
+ throw new RuntimeException("No older versions of Geode were found to test against");
+ }
+ return result;
+ }
+
+ private static void addReceiversWithHostNameForSenders(List<Object[]> result, String version) {
+ List<Attribute> attributes = new ArrayList<>();
+ attributes.add(new Attribute("hostname-for-senders", "121.21.21.21"));
+ attributes.add(new Attribute("hostname-for-senders", "121.21.21.22"));
+ result.add(new Object[] {version, attributes, 2, 0});
+ }
+
+ private static void addReceiversWithBindAddresses(List<Object[]> result, String version) {
+ List<Attribute> attributes = new ArrayList<>();
+ attributes.add(new Attribute("bind-address", "121.21.21.21"));
+ attributes.add(new Attribute("bind-address", "121.21.21.22"));
+ result.add(new Object[] {version, attributes, 2, 0});
+ }
+
+ private static void addMultipleReceiversWithDefaultAttributes(List<Object[]> result,
+ String version) {
+ List<Attribute> attributes = new ArrayList<>();
+ attributes.add(Attribute.DEFAULT);
+ attributes.add(Attribute.DEFAULT);
+ result.add(new Object[] {version, attributes, 2, 1});
+ }
+
+ private static void addSingleReceiverWithDefaultAttributes(List<Object[]> result,
+ String version) {
+ List<Attribute> attributes = new ArrayList<>();
+ attributes.add(Attribute.DEFAULT);
+ result.add(new Object[] {version, attributes, 1, 1});
+ }
+
+ private static void addSingleReceiverWithDefaultBindAddress(List<Object[]> result,
+ String version) {
+ List<Attribute> attributes = new ArrayList<>();
+ attributes.add(new Attribute("bind-address", "0.0.0.0"));
+ result.add(new Object[] {version, attributes, 1, 1});
+ }
+
+ @Test
+ public void testMultipleReceiversRemovedDuringRoll() throws Exception {
+ // Get old locator properties
+ VM locator = Host.getHost(0).getVM(oldVersion, 0);
+ String hostName = NetworkUtils.getServerHostName();
+ final int locatorPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
+ DistributedTestUtils.deleteLocatorStateFile(locatorPort);
+ final String locators = hostName + "[" + locatorPort + "]";
+
+ // Start old locator
+ locator.invoke(() -> startLocator(locatorPort, 0,
+ locators, null, true));
+
+ // Wait for configuration configuration to be ready.
+ locator.invoke(
+ () -> Awaitility.await().atMost(65, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS)
+ .until(() -> assertThat(
+ InternalLocator.getLocator().isSharedConfigurationRunning()).isTrue()));
+
+ // Add cluster configuration elements containing multiple receivers
+ locator.invoke(
+ () -> addMultipleGatewayReceiverElementsToClusterConfiguration());
+
+ // Roll old locator to current
+ rollLocatorToCurrent(locator, locatorPort, 0, locators,
+ null, true);
+
+ // Verify cluster configuration contains expected number of receivers
+ locator.invoke(() -> verifyGatewayReceiverClusterConfigurationElements());
+
+ // Start member in current version with cluster configuration enabled
+ VM server = Host.getHost(0).getVM(VersionManager.CURRENT_VERSION, 1);
+ server.invoke(() -> createCache(locators, true, true));
+
+ // Verify member has expected number of receivers
+ server.invoke(() -> verifyGatewayReceivers());
+ }
+
+ private void addMultipleGatewayReceiverElementsToClusterConfiguration()
+ throws Exception {
+ // Create empty xml document
+ CacheCreation creation = new CacheCreation();
+ final StringWriter stringWriter = new StringWriter();
+ final PrintWriter printWriter = new PrintWriter(stringWriter);
+ CacheXmlGenerator.generate(creation, printWriter, true, false, false);
+ printWriter.close();
+ String baseXml = stringWriter.toString();
+ Document document = XmlUtils.createDocumentFromXml(baseXml);
+
+ // Add gateway-receiver for each attribute
+ for (Attribute attribute : attributes) {
+ Node rootNode = document.getDocumentElement();
+ Element receiverElement = document.createElement("gateway-receiver");
+ if (!attribute.name.equals("default")) {
+ receiverElement.setAttribute(attribute.name, attribute.value);
+ }
+ rootNode.appendChild(receiverElement);
+ }
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength())
+ .isEqualTo(expectedReceiverElements);
+
+ // Get configuration region
+ Region<String, Configuration> configurationRegion = CacheFactory.getAnyInstance().getRegion(
+ InternalConfigurationPersistenceService.CONFIG_REGION_NAME);
+
+ // Create a configuration and put into the configuration region
+ Configuration configuration = new Configuration(ConfigurationPersistenceService.CLUSTER_CONFIG);
+ configuration.setCacheXmlContent(XmlUtils.prettyXml(document));
+ configurationRegion.put(ConfigurationPersistenceService.CLUSTER_CONFIG, configuration);
+ }
+
+ private void verifyGatewayReceiverClusterConfigurationElements() throws Exception {
+ // Get configuration region
+ Region<String, Configuration> configurationRegion = CacheFactory.getAnyInstance().getRegion(
+ InternalConfigurationPersistenceService.CONFIG_REGION_NAME);
+
+ // Get the configuration from the region
+ Configuration configuration =
+ configurationRegion.get(ConfigurationPersistenceService.CLUSTER_CONFIG);
+
+ // Verify the configuration contains no gateway-receiver elements
+ Document document = XmlUtils.createDocumentFromXml(configuration.getCacheXmlContent());
+ assertThat(document.getElementsByTagName("gateway-receiver").getLength())
+ .isEqualTo(expectedReceivers);
+ }
+
+ private void verifyGatewayReceivers() {
+ assertThat(CacheFactory.getAnyInstance().getGatewayReceivers().size())
+ .isEqualTo(expectedReceivers);
+ }
+
+ private static class Attribute implements Serializable {
+
+ private String name;
+
+ private String value;
+
+ private static final Attribute DEFAULT = new Attribute("default", "");
+
+ Attribute(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String toString() {
+ return new StringBuilder()
+ .append(this.name)
+ .append("=")
+ .append(this.value)
+ .toString();
+ }
+ }
+}