| /* |
| * 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}}; |
| } |
| } |