blob: c5a573cb101a95405881f756f43ee675f69c97fe [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.distributed.internal;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
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.Test;
import org.junit.runner.RunWith;
import org.w3c.dom.Document;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.configuration.CacheConfig;
import org.apache.geode.cache.configuration.GatewayReceiverConfig;
import org.apache.geode.cache.configuration.JndiBindingsType;
import org.apache.geode.cache.configuration.RegionConfig;
import org.apache.geode.cache.configuration.RegionType;
import org.apache.geode.internal.config.JAXBService;
import org.apache.geode.internal.config.JAXBServiceTest;
import org.apache.geode.internal.config.JAXBServiceTest.ElementOne;
import org.apache.geode.internal.config.JAXBServiceTest.ElementTwo;
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;
private InternalConfigurationPersistenceService service2;
private Configuration configuration;
@Before
public void setUp() throws Exception {
service = spy(new InternalConfigurationPersistenceService(
JAXBService.createWithValidation(CacheConfig.class, ElementOne.class, ElementTwo.class)));
service2 = spy(new InternalConfigurationPersistenceService(
JAXBService.createWithValidation(CacheConfig.class)));
configuration = new Configuration("cluster");
doReturn(configuration).when(service).getConfiguration(any());
doReturn(configuration).when(service2).getConfiguration(any());
doReturn(mock(Region.class)).when(service).getConfigurationRegion();
doReturn(mock(Region.class)).when(service2).getConfigurationRegion();
doReturn(true).when(service).lockSharedConfiguration();
doReturn(true).when(service2).lockSharedConfiguration();
doNothing().when(service).unlockSharedConfiguration();
doNothing().when(service2).unlockSharedConfiguration();
}
@Test
public void updateRegionConfig() {
service.updateCacheConfig("cluster", cacheConfig -> {
RegionConfig regionConfig = new RegionConfig();
regionConfig.setName("regionA");
regionConfig.setType(RegionType.REPLICATE);
cacheConfig.getRegions().add(regionConfig);
return cacheConfig;
});
System.out.println(configuration.getCacheXmlContent());
assertThat(configuration.getCacheXmlContent())
.contains("<region name=\"regionA\" refid=\"REPLICATE\"");
}
@Test
public void jndiBindings() {
service.updateCacheConfig("cluster", cacheConfig -> {
JndiBindingsType.JndiBinding jndiBinding = new JndiBindingsType.JndiBinding();
jndiBinding.setJndiName("jndiOne");
jndiBinding.setJdbcDriverClass("com.sun.ABC");
jndiBinding.setType("SimpleDataSource");
jndiBinding.getConfigProperties()
.add(new JndiBindingsType.JndiBinding.ConfigProperty("test", "test", "test"));
cacheConfig.getJndiBindings().add(jndiBinding);
return cacheConfig;
});
assertThat(configuration.getCacheXmlContent()).containsOnlyOnce("</jndi-bindings>");
assertThat(configuration.getCacheXmlContent()).contains(
"<jndi-binding jdbc-driver-class=\"com.sun.ABC\" jndi-name=\"jndiOne\" type=\"SimpleDataSource\">");
assertThat(configuration.getCacheXmlContent())
.contains("config-property-name>test</config-property-name>");
}
@Test
public void addCustomCacheElement() {
ElementOne customOne = new ElementOne("testOne");
service.updateCacheConfig("cluster", config -> {
config.getCustomCacheElements().add(customOne);
return config;
});
System.out.println(configuration.getCacheXmlContent());
assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
JAXBServiceTest.ElementTwo customTwo = new ElementTwo("testTwo");
service.updateCacheConfig("cluster", config -> {
config.getCustomCacheElements().add(customTwo);
return config;
});
System.out.println(configuration.getCacheXmlContent());
assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
assertThat(configuration.getCacheXmlContent()).contains("custom-two>");
}
@Test
// in case a locator in the cluster doesn't have the plugin installed
public void xmlWithCustomElementsCanBeUnMarshalledByAnotherService() {
service.updateCacheConfig("cluster", config -> {
config.getCustomCacheElements().add(new ElementOne("one"));
config.getCustomCacheElements().add(new ElementTwo("two"));
return config;
});
String prettyXml = configuration.getCacheXmlContent();
System.out.println(prettyXml);
// the xml is sent to another locator with no such plugin installed, it can be parsed
// but the element couldn't be recognized by the locator without the plugin
service2.updateCacheConfig("cluster", cc -> cc);
CacheConfig config = service2.getCacheConfig("cluster");
assertThat(config.findCustomCacheElement("one", ElementOne.class)).isNull();
String uglyXml = configuration.getCacheXmlContent();
System.out.println(uglyXml);
assertThat(uglyXml).isNotEqualTo(prettyXml);
// the xml can be unmarshalled correctly by the first locator
CacheConfig cacheConfig = service.getCacheConfig("cluster");
service.updateCacheConfig("cluster", cc -> cc);
assertThat(cacheConfig.getCustomCacheElements()).hasSize(2);
assertThat(cacheConfig.getCustomCacheElements().get(0)).isInstanceOf(ElementOne.class);
assertThat(cacheConfig.getCustomCacheElements().get(1)).isInstanceOf(ElementTwo.class);
assertThat(configuration.getCacheXmlContent()).isEqualTo(prettyXml);
}
@Test
public void getNonExistingGroupConfigShouldReturnNull() {
assertThat(service.getCacheConfig("non-existing-group")).isNull();
}
@Test
public void getExistingGroupConfigShouldReturnNullIfNoXml() {
Configuration groupConfig = new Configuration("some-new-group");
doReturn(groupConfig).when(service).getConfiguration("some-new-group");
CacheConfig groupCacheConfig = service.getCacheConfig("some-new-group");
assertThat(groupCacheConfig).isNull();
}
@Test
public void updateShouldInsertIfNotExist() {
doCallRealMethod().when(service).updateCacheConfig(any(), any());
doCallRealMethod().when(service).getCacheConfig(any());
Region region = mock(Region.class);
doReturn(region).when(service).getConfigurationRegion();
service.updateCacheConfig("non-existing-group", cc -> cc);
verify(region).put(eq("non-existing-group"), any());
}
@Test
public void updateGatewayReceiverConfig() {
service.updateCacheConfig("cluster", cacheConfig -> {
GatewayReceiverConfig receiver = new GatewayReceiverConfig();
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[] {
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}};
}
}