http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java ---------------------------------------------------------------------- diff --cc gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java index 06da13d,0000000..4187214 mode 100644,000000..100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java @@@ -1,220 -1,0 +1,263 @@@ +package org.apache.knox.gateway.config.impl; + +import org.apache.knox.test.TestUtils; +import org.hamcrest.CoreMatchers; +import org.junit.Test; + +import java.util.List; ++import java.util.concurrent.TimeUnit; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.nullValue; ++import static org.junit.Assert.assertNotEquals; ++import static org.junit.Assert.assertTrue; ++import static org.testng.Assert.assertEquals; ++import static org.testng.Assert.assertFalse; ++import static org.testng.Assert.assertNotNull; + +/** + * 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. + */ +public class GatewayConfigImplTest { + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testHttpServerSettings() { + GatewayConfigImpl config = new GatewayConfigImpl(); + + // Check the defaults. + assertThat( config.getHttpServerRequestBuffer(), is( 16*1024 ) ); + assertThat( config.getHttpServerRequestHeaderBuffer(), is( 8*1024 ) ); + assertThat( config.getHttpServerResponseBuffer(), is( 32*1024 ) ); + assertThat( config.getHttpServerResponseHeaderBuffer(), is( 8*1024 ) ); + + assertThat( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, is( "gateway.httpserver.requestBuffer" ) ); + assertThat( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, is( "gateway.httpserver.requestHeaderBuffer" ) ); + assertThat( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, is( "gateway.httpserver.responseBuffer" ) ); + assertThat( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, is( "gateway.httpserver.responseHeaderBuffer" ) ); + + config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, 32*1024 ); + assertThat( config.getHttpServerRequestBuffer(), is( 32*1024 ) ); + + config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, 4*1024 ); + assertThat( config.getHttpServerRequestHeaderBuffer(), is( 4*1024 ) ); + + config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, 16*1024 ); + assertThat( config.getHttpServerResponseBuffer(), is( 16*1024 ) ); + + config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, 6*1024 ); + assertThat( config.getHttpServerResponseHeaderBuffer(), is( 6*1024 ) ); + + // Restore the defaults. + config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_BUFFER, 16*1024 ); + config.setInt( GatewayConfigImpl.HTTP_SERVER_REQUEST_HEADER_BUFFER, 8*1024 ); + config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_BUFFER, 32*1024 ); + config.setInt( GatewayConfigImpl.HTTP_SERVER_RESPONSE_HEADER_BUFFER, 8*1024 ); + } + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testGetGatewayDeploymentsBackupVersionLimit() { + GatewayConfigImpl config = new GatewayConfigImpl(); + assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(5) ); + + config.setInt( config.DEPLOYMENTS_BACKUP_VERSION_LIMIT, 3 ); + assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(3) ); + + config.setInt( config.DEPLOYMENTS_BACKUP_VERSION_LIMIT, -3 ); + assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(-1) ); + + config.setInt( config.DEPLOYMENTS_BACKUP_VERSION_LIMIT, 0 ); + assertThat( config.getGatewayDeploymentsBackupVersionLimit(), is(0) ); + } + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testGetGatewayDeploymentsBackupAgeLimit() { + GatewayConfigImpl config = new GatewayConfigImpl(); + assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(-1L) ); + + config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "1" ); + assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(86400000L) ); + + config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "2" ); + assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(86400000L*2L) ); + + config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "0" ); + assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(0L) ); + + config.set( config.DEPLOYMENTS_BACKUP_AGE_LIMIT, "X" ); + assertThat( config.getGatewayDeploymentsBackupAgeLimit(), is(-1L) ); + } + + + @Test + public void testSSLCiphers() { + GatewayConfigImpl config = new GatewayConfigImpl(); + List<String> list; + + list = config.getIncludedSSLCiphers(); + assertThat( list, is(nullValue()) ); + + config.set( "ssl.include.ciphers", "none" ); + assertThat( config.getIncludedSSLCiphers(), is(nullValue()) ); + + config.set( "ssl.include.ciphers", "" ); + assertThat( config.getIncludedSSLCiphers(), is(nullValue()) ); + + config.set( "ssl.include.ciphers", "ONE" ); + assertThat( config.getIncludedSSLCiphers(), is(hasItems("ONE")) ); + + config.set( "ssl.include.ciphers", " ONE " ); + assertThat( config.getIncludedSSLCiphers(), is(hasItems("ONE")) ); + + config.set( "ssl.include.ciphers", "ONE,TWO" ); + assertThat( config.getIncludedSSLCiphers(), is(hasItems("ONE","TWO")) ); + + config.set( "ssl.include.ciphers", "ONE,TWO,THREE" ); + assertThat( config.getIncludedSSLCiphers(), is(hasItems("ONE","TWO","THREE")) ); + + config.set( "ssl.include.ciphers", " ONE , TWO , THREE " ); + assertThat( config.getIncludedSSLCiphers(), is(hasItems("ONE","TWO","THREE")) ); + + list = config.getExcludedSSLCiphers(); + assertThat( list, is(nullValue()) ); + + config.set( "ssl.exclude.ciphers", "none" ); + assertThat( config.getExcludedSSLCiphers(), is(nullValue()) ); + + config.set( "ssl.exclude.ciphers", "" ); + assertThat( config.getExcludedSSLCiphers(), is(nullValue()) ); + + config.set( "ssl.exclude.ciphers", "ONE" ); + assertThat( config.getExcludedSSLCiphers(), is(hasItems("ONE")) ); + + config.set( "ssl.exclude.ciphers", " ONE " ); + assertThat( config.getExcludedSSLCiphers(), is(hasItems("ONE")) ); + + config.set( "ssl.exclude.ciphers", "ONE,TWO" ); + assertThat( config.getExcludedSSLCiphers(), is(hasItems("ONE","TWO")) ); + + config.set( "ssl.exclude.ciphers", "ONE,TWO,THREE" ); + assertThat( config.getExcludedSSLCiphers(), is(hasItems("ONE","TWO","THREE")) ); + + config.set( "ssl.exclude.ciphers", " ONE , TWO , THREE " ); + assertThat( config.getExcludedSSLCiphers(), is(hasItems("ONE","TWO","THREE")) ); + } + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testGlobalRulesServices() { + GatewayConfigImpl config = new GatewayConfigImpl(); + List<String> list; + + list = config.getGlobalRulesServices(); + assertThat( list, is(notNullValue()) ); + + assertThat( list, is( CoreMatchers.hasItems("NAMENODE","JOBTRACKER", "WEBHDFS", "WEBHCAT", "OOZIE", "WEBHBASE", "HIVE", "RESOURCEMANAGER"))); + + + config.set( GatewayConfigImpl.GLOBAL_RULES_SERVICES, "none" ); + assertThat( config.getGlobalRulesServices(), is( CoreMatchers.hasItems("NAMENODE","JOBTRACKER", "WEBHDFS", "WEBHCAT", "OOZIE", "WEBHBASE", "HIVE", "RESOURCEMANAGER")) ); + + config.set( GatewayConfigImpl.GLOBAL_RULES_SERVICES, "" ); + assertThat( config.getGlobalRulesServices(), is( CoreMatchers.hasItems("NAMENODE","JOBTRACKER", "WEBHDFS", "WEBHCAT", "OOZIE", "WEBHBASE", "HIVE", "RESOURCEMANAGER")) ); + + config.set( GatewayConfigImpl.GLOBAL_RULES_SERVICES, "ONE" ); + assertThat( config.getGlobalRulesServices(), is(hasItems("ONE")) ); + + config.set( GatewayConfigImpl.GLOBAL_RULES_SERVICES, "ONE,TWO,THREE" ); + assertThat( config.getGlobalRulesServices(), is(hasItems("ONE","TWO","THREE")) ); + + config.set( GatewayConfigImpl.GLOBAL_RULES_SERVICES, " ONE , TWO , THREE " ); + assertThat( config.getGlobalRulesServices(), is(hasItems("ONE","TWO","THREE")) ); + } + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testMetricsSettings() { + GatewayConfigImpl config = new GatewayConfigImpl(); + //test defaults + assertThat(config.isMetricsEnabled(), is(false)); + assertThat(config.isJmxMetricsReportingEnabled(), is(false)); + assertThat(config.isGraphiteMetricsReportingEnabled(), is(false)); + assertThat(config.getGraphiteHost(), is("localhost")); + assertThat(config.getGraphitePort(), is(32772)); + } + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testGatewayIdleTimeout() { + GatewayConfigImpl config = new GatewayConfigImpl(); + long idleTimeout = 0l; + + idleTimeout = config.getGatewayIdleTimeout(); + assertThat( idleTimeout, is(300000L)); + + config.set( GatewayConfigImpl.GATEWAY_IDLE_TIMEOUT, "15000" ); + idleTimeout = config.getGatewayIdleTimeout(); + assertThat( idleTimeout, is(15000L)); + } + + @Test( timeout = TestUtils.SHORT_TIMEOUT ) + public void testGatewayServerHeaderEnabled() { + GatewayConfigImpl config = new GatewayConfigImpl(); + boolean serverHeaderEnabled = true; + + serverHeaderEnabled = config.isGatewayServerHeaderEnabled(); + assertThat( serverHeaderEnabled, is(true)); + + config.set( GatewayConfigImpl.SERVER_HEADER_ENABLED, "false"); + serverHeaderEnabled = config.isGatewayServerHeaderEnabled(); + assertThat( serverHeaderEnabled, is(false)); + } + ++ ++ @Test ++ public void testGetRemoteConfigurationRegistryNames() { ++ GatewayConfigImpl config = new GatewayConfigImpl(); ++ ++ List<String> registryNames = config.getRemoteRegistryConfigurationNames(); ++ assertNotNull(registryNames); ++ assertTrue(registryNames.isEmpty()); ++ ++ config.set(GatewayConfigImpl.CONFIG_REGISTRY_PREFIX + ".test1", ++ "type=ZooKeeper;address=host1:2181;authType=digest;principal=itsme;credentialAlias=testAlias"); ++ registryNames = config.getRemoteRegistryConfigurationNames(); ++ assertNotNull(registryNames); ++ assertFalse(registryNames.isEmpty()); ++ assertEquals(1, registryNames.size()); ++ ++ config.set(GatewayConfigImpl.CONFIG_REGISTRY_PREFIX + ".test2", ++ "type=ZooKeeper;address=host2:2181,host3:2181,host4:2181"); ++ registryNames = config.getRemoteRegistryConfigurationNames(); ++ assertNotNull(registryNames); ++ assertFalse(registryNames.isEmpty()); ++ assertEquals(registryNames.size(), 2); ++ } ++ ++ ++ @Test ++ public void testHTTPDefaultTimeouts() { ++ final GatewayConfigImpl config = new GatewayConfigImpl(); ++ ++ assertNotEquals(config.getHttpClientConnectionTimeout(), -1); ++ assertNotEquals(config.getHttpClientSocketTimeout(), -1); ++ ++ assertEquals(TimeUnit.SECONDS.toMillis(20), config.getHttpClientConnectionTimeout()); ++ assertEquals(TimeUnit.SECONDS.toMillis(20), config.getHttpClientSocketTimeout()); ++ ++ } ++ +}
http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java ---------------------------------------------------------------------- diff --cc gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java index 408d396,0000000..60cf633 mode 100644,000000..100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java @@@ -1,610 -1,0 +1,618 @@@ +/** + * 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.knox.gateway.services.topology; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.monitor.FileAlterationListener; +import org.apache.commons.io.monitor.FileAlterationMonitor; +import org.apache.commons.io.monitor.FileAlterationObserver; +import org.apache.knox.gateway.config.GatewayConfig; +import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService; +import org.apache.knox.gateway.services.security.AliasService; +import org.apache.knox.test.TestUtils; +import org.apache.knox.gateway.topology.Param; +import org.apache.knox.gateway.topology.Provider; +import org.apache.knox.gateway.topology.Topology; +import org.apache.knox.gateway.topology.TopologyEvent; +import org.apache.knox.gateway.topology.TopologyListener; +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.easymock.EasyMock.anyObject; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class DefaultTopologyServiceTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + private File createDir() throws IOException { + return TestUtils.createTempDir(this.getClass().getSimpleName() + "-"); + } + + private File createFile(File parent, String name, String resource, long timestamp) throws IOException { + File file = new File(parent, name); + if (!file.exists()) { + FileUtils.touch(file); + } + InputStream input = ClassLoader.getSystemResourceAsStream(resource); + OutputStream output = FileUtils.openOutputStream(file); + IOUtils.copy(input, output); + //KNOX-685: output.flush(); + input.close(); + output.close(); + file.setLastModified(timestamp); + assertTrue("Failed to create test file " + file.getAbsolutePath(), file.exists()); + assertTrue("Failed to populate test file " + file.getAbsolutePath(), file.length() > 0); + + return file; + } + + @Test + public void testGetTopologies() throws Exception { + + File dir = createDir(); + File topologyDir = new File(dir, "topologies"); + ++ File descriptorsDir = new File(dir, "descriptors"); ++ descriptorsDir.mkdirs(); ++ ++ File sharedProvidersDir = new File(dir, "shared-providers"); ++ sharedProvidersDir.mkdirs(); ++ + long time = topologyDir.lastModified(); + try { + createFile(topologyDir, "one.xml", "org/apache/knox/gateway/topology/file/topology-one.xml", time); + + TestTopologyListener topoListener = new TestTopologyListener(); + FileAlterationMonitor monitor = new FileAlterationMonitor(Long.MAX_VALUE); + + TopologyService provider = new DefaultTopologyService(); + Map<String, String> c = new HashMap<>(); + + GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.expect(config.getGatewayTopologyDir()).andReturn(topologyDir.getAbsolutePath()).anyTimes(); - EasyMock.expect(config.getGatewayConfDir()).andReturn(topologyDir.getParentFile().getAbsolutePath()).anyTimes(); ++ EasyMock.expect(config.getGatewayConfDir()).andReturn(descriptorsDir.getParentFile().getAbsolutePath()).anyTimes(); ++ EasyMock.expect(config.getGatewayProvidersConfigDir()).andReturn(sharedProvidersDir.getAbsolutePath()).anyTimes(); ++ EasyMock.expect(config.getGatewayDescriptorsDir()).andReturn(descriptorsDir.getAbsolutePath()).anyTimes(); + EasyMock.replay(config); + + provider.init(config, c); + + provider.addTopologyChangeListener(topoListener); + + provider.reloadTopologies(); + + Collection<Topology> topologies = provider.getTopologies(); + assertThat(topologies, notNullValue()); + assertThat(topologies.size(), is(1)); + Topology topology = topologies.iterator().next(); + assertThat(topology.getName(), is("one")); + assertThat(topology.getTimestamp(), is(time)); + assertThat(topoListener.events.size(), is(1)); + topoListener.events.clear(); + + // Add a file to the directory. + File two = createFile(topologyDir, "two.xml", + "org/apache/knox/gateway/topology/file/topology-two.xml", 1L); + provider.reloadTopologies(); + topologies = provider.getTopologies(); + assertThat(topologies.size(), is(2)); + Set<String> names = new HashSet<>(Arrays.asList("one", "two")); + Iterator<Topology> iterator = topologies.iterator(); + topology = iterator.next(); + assertThat(names, hasItem(topology.getName())); + names.remove(topology.getName()); + topology = iterator.next(); + assertThat(names, hasItem(topology.getName())); + names.remove(topology.getName()); + assertThat(names.size(), is(0)); + assertThat(topoListener.events.size(), is(1)); + List<TopologyEvent> events = topoListener.events.get(0); + assertThat(events.size(), is(1)); + TopologyEvent event = events.get(0); + assertThat(event.getType(), is(TopologyEvent.Type.CREATED)); + assertThat(event.getTopology(), notNullValue()); + + // Update a file in the directory. + two = createFile(topologyDir, "two.xml", + "org/apache/knox/gateway/topology/file/topology-three.xml", 2L); + provider.reloadTopologies(); + topologies = provider.getTopologies(); + assertThat(topologies.size(), is(2)); + names = new HashSet<>(Arrays.asList("one", "two")); + iterator = topologies.iterator(); + topology = iterator.next(); + assertThat(names, hasItem(topology.getName())); + names.remove(topology.getName()); + topology = iterator.next(); + assertThat(names, hasItem(topology.getName())); + names.remove(topology.getName()); + assertThat(names.size(), is(0)); + + // Remove a file from the directory. + two.delete(); + provider.reloadTopologies(); + topologies = provider.getTopologies(); + assertThat(topologies.size(), is(1)); + topology = topologies.iterator().next(); + assertThat(topology.getName(), is("one")); + assertThat(topology.getTimestamp(), is(time)); + + } finally { + FileUtils.deleteQuietly(dir); + } + } + + /** + * KNOX-1014 + * + * Test the lifecycle relationship between simple descriptors and topology files. + * + * N.B. This test depends on the DummyServiceDiscovery extension being configured: + * org.apache.knox.gateway.topology.discovery.test.extension.DummyServiceDiscovery + */ + @Test + public void testSimpleDescriptorsTopologyGeneration() throws Exception { + + File dir = createDir(); + File topologyDir = new File(dir, "topologies"); + topologyDir.mkdirs(); + + File descriptorsDir = new File(dir, "descriptors"); + descriptorsDir.mkdirs(); + + File sharedProvidersDir = new File(dir, "shared-providers"); + sharedProvidersDir.mkdirs(); + + try { + TestTopologyListener topoListener = new TestTopologyListener(); + FileAlterationMonitor monitor = new FileAlterationMonitor(Long.MAX_VALUE); + + TopologyService provider = new DefaultTopologyService(); + Map<String, String> c = new HashMap<>(); + + GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.expect(config.getGatewayTopologyDir()).andReturn(topologyDir.getAbsolutePath()).anyTimes(); + EasyMock.expect(config.getGatewayConfDir()).andReturn(descriptorsDir.getParentFile().getAbsolutePath()).anyTimes(); + EasyMock.replay(config); + + provider.init(config, c); + provider.addTopologyChangeListener(topoListener); + provider.reloadTopologies(); + + + // Add a simple descriptor to the descriptors dir to verify topology generation and loading (KNOX-1006) + AliasService aliasService = EasyMock.createNiceMock(AliasService.class); + EasyMock.expect(aliasService.getPasswordFromAliasForGateway(anyObject(String.class))).andReturn(null).anyTimes(); + EasyMock.replay(aliasService); + DefaultTopologyService.DescriptorsMonitor dm = + new DefaultTopologyService.DescriptorsMonitor(topologyDir, aliasService); + + // Listener to simulate the topologies directory monitor, to notice when a topology has been deleted + provider.addTopologyChangeListener(new TestTopologyDeleteListener((DefaultTopologyService)provider)); + + // Write out the referenced provider config first + File provCfgFile = createFile(sharedProvidersDir, + "ambari-cluster-policy.xml", + "org/apache/knox/gateway/topology/file/ambari-cluster-policy.xml", + System.currentTimeMillis()); + try { + // Create the simple descriptor in the descriptors dir + File simpleDesc = createFile(descriptorsDir, + "four.json", + "org/apache/knox/gateway/topology/file/simple-topology-four.json", + System.currentTimeMillis()); + + // Trigger the topology generation by noticing the simple descriptor + dm.onFileChange(simpleDesc); + + // Load the generated topology + provider.reloadTopologies(); + Collection<Topology> topologies = provider.getTopologies(); + assertThat(topologies.size(), is(1)); + Iterator<Topology> iterator = topologies.iterator(); + Topology topology = iterator.next(); + assertThat("four", is(topology.getName())); + int serviceCount = topology.getServices().size(); + assertEquals("Expected the same number of services as are declared in the simple dscriptor.", 10, serviceCount); + + // Overwrite the simple descriptor with a different set of services, and check that the changes are + // propagated to the associated topology + simpleDesc = createFile(descriptorsDir, + "four.json", + "org/apache/knox/gateway/topology/file/simple-descriptor-five.json", + System.currentTimeMillis()); + dm.onFileChange(simpleDesc); + provider.reloadTopologies(); + topologies = provider.getTopologies(); + topology = topologies.iterator().next(); + assertNotEquals(serviceCount, topology.getServices().size()); + assertEquals(6, topology.getServices().size()); + + // Delete the simple descriptor, and make sure that the associated topology file is deleted + simpleDesc.delete(); + dm.onFileDelete(simpleDesc); + provider.reloadTopologies(); + topologies = provider.getTopologies(); + assertTrue(topologies.isEmpty()); + + // Delete a topology file, and make sure that the associated simple descriptor is deleted + // Overwrite the simple descriptor with a different set of services, and check that the changes are + // propagated to the associated topology + simpleDesc = createFile(descriptorsDir, + "deleteme.json", + "org/apache/knox/gateway/topology/file/simple-descriptor-five.json", + System.currentTimeMillis()); + dm.onFileChange(simpleDesc); + provider.reloadTopologies(); + topologies = provider.getTopologies(); + assertFalse(topologies.isEmpty()); + topology = topologies.iterator().next(); + assertEquals("deleteme", topology.getName()); + File topologyFile = new File(topologyDir, topology.getName() + ".xml"); + assertTrue(topologyFile.exists()); + topologyFile.delete(); + provider.reloadTopologies(); + assertFalse("Simple descriptor should have been deleted because the associated topology was.", + simpleDesc.exists()); + + } finally { + provCfgFile.delete(); + } + } finally { + FileUtils.deleteQuietly(dir); + } + } + + /** + * KNOX-1014 + * + * Test the lifecycle relationship between provider configuration files, simple descriptors, and topology files. + * + * N.B. This test depends on the DummyServiceDiscovery extension being configured: + * org.apache.knox.gateway.topology.discovery.test.extension.DummyServiceDiscovery + */ + @Test + public void testTopologiesUpdateFromProviderConfigChange() throws Exception { + File dir = createDir(); + File topologyDir = new File(dir, "topologies"); + topologyDir.mkdirs(); + + File descriptorsDir = new File(dir, "descriptors"); + descriptorsDir.mkdirs(); + + File sharedProvidersDir = new File(dir, "shared-providers"); + sharedProvidersDir.mkdirs(); + + try { + TestTopologyListener topoListener = new TestTopologyListener(); + FileAlterationMonitor monitor = new FileAlterationMonitor(Long.MAX_VALUE); + + TopologyService ts = new DefaultTopologyService(); + Map<String, String> c = new HashMap<>(); + + GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.expect(config.getGatewayTopologyDir()).andReturn(topologyDir.getAbsolutePath()).anyTimes(); + EasyMock.expect(config.getGatewayConfDir()).andReturn(descriptorsDir.getParentFile().getAbsolutePath()).anyTimes(); + EasyMock.replay(config); + + ts.init(config, c); + ts.addTopologyChangeListener(topoListener); + ts.reloadTopologies(); + + java.lang.reflect.Field dmField = ts.getClass().getDeclaredField("descriptorsMonitor"); + dmField.setAccessible(true); + DefaultTopologyService.DescriptorsMonitor dm = (DefaultTopologyService.DescriptorsMonitor) dmField.get(ts); + + // Write out the referenced provider configs first + createFile(sharedProvidersDir, + "provider-config-one.xml", + "org/apache/knox/gateway/topology/file/provider-config-one.xml", + System.currentTimeMillis()); + + // Create the simple descriptor, which depends on provider-config-one.xml + File simpleDesc = createFile(descriptorsDir, + "six.json", + "org/apache/knox/gateway/topology/file/simple-descriptor-six.json", + System.currentTimeMillis()); + + // "Notice" the simple descriptor change, and generate a topology based on it + dm.onFileChange(simpleDesc); + + // Load the generated topology + ts.reloadTopologies(); + Collection<Topology> topologies = ts.getTopologies(); + assertThat(topologies.size(), is(1)); + Iterator<Topology> iterator = topologies.iterator(); + Topology topology = iterator.next(); + assertFalse("The Shiro provider is disabled in provider-config-one.xml", + topology.getProvider("authentication", "ShiroProvider").isEnabled()); + + // Overwrite the referenced provider configuration with a different ShiroProvider config, and check that the + // changes are propagated to the associated topology + File providerConfig = createFile(sharedProvidersDir, + "provider-config-one.xml", + "org/apache/knox/gateway/topology/file/ambari-cluster-policy.xml", + System.currentTimeMillis()); + + // "Notice" the simple descriptor change as a result of the referenced config change + dm.onFileChange(simpleDesc); + + // Load the generated topology + ts.reloadTopologies(); + topologies = ts.getTopologies(); + assertFalse(topologies.isEmpty()); + topology = topologies.iterator().next(); + assertTrue("The Shiro provider is enabled in ambari-cluster-policy.xml", + topology.getProvider("authentication", "ShiroProvider").isEnabled()); + + // Delete the provider configuration, and make sure that the associated topology file is unaffected. + // The topology file should not be affected because the simple descriptor handling will fail to resolve the + // referenced provider configuration. + providerConfig.delete(); // Delete the file + dm.onFileChange(simpleDesc); // The provider config deletion will trigger a descriptor change notification + ts.reloadTopologies(); + topologies = ts.getTopologies(); + assertFalse(topologies.isEmpty()); + assertTrue("The Shiro provider is enabled in ambari-cluster-policy.xml", + topology.getProvider("authentication", "ShiroProvider").isEnabled()); + + } finally { + FileUtils.deleteQuietly(dir); + } + } + + /** + * KNOX-1039 + */ + @Test + public void testConfigurationCRUDAPI() throws Exception { + File dir = createDir(); + File topologyDir = new File(dir, "topologies"); + topologyDir.mkdirs(); + + File descriptorsDir = new File(dir, "descriptors"); + descriptorsDir.mkdirs(); + + File sharedProvidersDir = new File(dir, "shared-providers"); + sharedProvidersDir.mkdirs(); + + try { + TestTopologyListener topoListener = new TestTopologyListener(); + FileAlterationMonitor monitor = new FileAlterationMonitor(Long.MAX_VALUE); + + TopologyService ts = new DefaultTopologyService(); + Map<String, String> c = new HashMap<>(); + + GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.expect(config.getGatewayTopologyDir()).andReturn(topologyDir.getAbsolutePath()).anyTimes(); + EasyMock.expect(config.getGatewayConfDir()).andReturn(descriptorsDir.getParentFile().getAbsolutePath()).anyTimes(); + EasyMock.replay(config); + + ts.init(config, c); + ts.addTopologyChangeListener(topoListener); + ts.reloadTopologies(); + + java.lang.reflect.Field dmField = ts.getClass().getDeclaredField("descriptorsMonitor"); + dmField.setAccessible(true); + DefaultTopologyService.DescriptorsMonitor dm = (DefaultTopologyService.DescriptorsMonitor) dmField.get(ts); + + final String simpleDescName = "six.json"; + final String provConfOne = "provider-config-one.xml"; + final String provConfTwo = "ambari-cluster-policy.xml"; + + // "Deploy" the referenced provider configs first + boolean isDeployed = + ts.deployProviderConfiguration(provConfOne, + FileUtils.readFileToString(new File(ClassLoader.getSystemResource( + "org/apache/knox/gateway/topology/file/provider-config-one.xml").toURI()))); + assertTrue(isDeployed); + File provConfOneFile = new File(sharedProvidersDir, provConfOne); + assertTrue(provConfOneFile.exists()); + + isDeployed = + ts.deployProviderConfiguration(provConfTwo, + FileUtils.readFileToString(new File(ClassLoader.getSystemResource( + "org/apache/knox/gateway/topology/file/ambari-cluster-policy.xml").toURI()))); + assertTrue(isDeployed); + File provConfTwoFile = new File(sharedProvidersDir, provConfTwo); + assertTrue(provConfTwoFile.exists()); + + // Validate the provider configurations known by the topology service + Collection<File> providerConfigurations = ts.getProviderConfigurations(); + assertNotNull(providerConfigurations); + assertEquals(2, providerConfigurations.size()); + assertTrue(providerConfigurations.contains(provConfOneFile)); + assertTrue(providerConfigurations.contains(provConfTwoFile)); + + // "Deploy" the simple descriptor, which depends on provConfOne + isDeployed = + ts.deployDescriptor(simpleDescName, + FileUtils.readFileToString(new File(ClassLoader.getSystemResource( + "org/apache/knox/gateway/topology/file/simple-descriptor-six.json").toURI()))); + assertTrue(isDeployed); + File simpleDesc = new File(descriptorsDir, simpleDescName); + assertTrue(simpleDesc.exists()); + + // Validate the simple descriptors known by the topology service + Collection<File> descriptors = ts.getDescriptors(); + assertNotNull(descriptors); + assertEquals(1, descriptors.size()); + assertTrue(descriptors.contains(simpleDesc)); + + // "Notice" the simple descriptor, so the provider configuration dependency relationship is recorded + dm.onFileChange(simpleDesc); + + // Attempt to delete the referenced provConfOne + assertFalse("Should not be able to delete a provider configuration that is referenced by one or more descriptors", + ts.deleteProviderConfiguration(FilenameUtils.getBaseName(provConfOne))); + + // Overwrite the simple descriptor with content that changes the provider config reference to provConfTwo + isDeployed = + ts.deployDescriptor(simpleDescName, + FileUtils.readFileToString(new File(ClassLoader.getSystemResource( + "org/apache/knox/gateway/topology/file/simple-descriptor-five.json").toURI()))); + assertTrue(isDeployed); + assertTrue(simpleDesc.exists()); + ts.getProviderConfigurations(); + + // "Notice" the simple descriptor, so the provider configuration dependency relationship is updated + dm.onFileChange(simpleDesc); + + // Attempt to delete the referenced provConfOne + assertTrue("Should be able to delete the provider configuration, now that it's not referenced by any descriptors", + ts.deleteProviderConfiguration(FilenameUtils.getBaseName(provConfOne))); + + // Re-validate the provider configurations known by the topology service + providerConfigurations = ts.getProviderConfigurations(); + assertNotNull(providerConfigurations); + assertEquals(1, providerConfigurations.size()); + assertFalse(providerConfigurations.contains(provConfOneFile)); + assertTrue(providerConfigurations.contains(provConfTwoFile)); + + // Attempt to delete the referenced provConfTwo + assertFalse("Should not be able to delete a provider configuration that is referenced by one or more descriptors", + ts.deleteProviderConfiguration(FilenameUtils.getBaseName(provConfTwo))); + + // Delete the referencing simple descriptor + assertTrue(ts.deleteDescriptor(FilenameUtils.getBaseName(simpleDescName))); + assertFalse(simpleDesc.exists()); + + // Re-validate the simple descriptors known by the topology service + descriptors = ts.getDescriptors(); + assertNotNull(descriptors); + assertTrue(descriptors.isEmpty()); + + // "Notice" the simple descriptor, so the provider configuration dependency relationship is updated + dm.onFileDelete(simpleDesc); + + // Attempt to delete the referenced provConfTwo + assertTrue("Should be able to delete the provider configuration, now that it's not referenced by any descriptors", + ts.deleteProviderConfiguration(FilenameUtils.getBaseName(provConfTwo))); + + // Re-validate the provider configurations known by the topology service + providerConfigurations = ts.getProviderConfigurations(); + assertNotNull(providerConfigurations); + assertTrue(providerConfigurations.isEmpty()); + + } finally { + FileUtils.deleteQuietly(dir); + } + } + + private void kickMonitor(FileAlterationMonitor monitor) { + for (FileAlterationObserver observer : monitor.getObservers()) { + observer.checkAndNotify(); + } + } + + + @Test + public void testProviderParamsOrderIsPreserved() { + + Provider provider = new Provider(); + String names[] = {"ldapRealm=", + "ldapContextFactory", + "ldapRealm.contextFactory", + "ldapGroupRealm", + "ldapGroupRealm.contextFactory", + "ldapGroupRealm.contextFactory.systemAuthenticationMechanism" + }; + + Param param = null; + for (String name : names) { + param = new Param(); + param.setName(name); + param.setValue(name); + provider.addParam(param); + + } + Map<String, String> params = provider.getParams(); + Set<String> keySet = params.keySet(); + Iterator<String> iter = keySet.iterator(); + int i = 0; + while (iter.hasNext()) { + assertTrue(iter.next().equals(names[i++])); + } + + } + + private class TestTopologyListener implements TopologyListener { + + ArrayList<List<TopologyEvent>> events = new ArrayList<List<TopologyEvent>>(); + + @Override + public void handleTopologyEvent(List<TopologyEvent> events) { + this.events.add(events); + } + + } + + + private class TestTopologyDeleteListener implements TopologyListener { + + FileAlterationListener delegate; + + TestTopologyDeleteListener(FileAlterationListener delegate) { + this.delegate = delegate; + } + + @Override + public void handleTopologyEvent(List<TopologyEvent> events) { + for (TopologyEvent event : events) { + if (event.getType().equals(TopologyEvent.Type.DELETED)) { + delegate.onFileDelete(new File(event.getTopology().getUri())); + } + } + } + + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java ---------------------------------------------------------------------- diff --cc gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java index df31f3d,0000000..2622f13 mode 100644,000000..100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java @@@ -1,681 -1,0 +1,690 @@@ +/** + * 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.knox.gateway.topology.simple; + +import java.io.File; +import java.io.FileWriter; +import java.io.Writer; +import java.util.*; + +import org.junit.Test; +import static org.junit.Assert.*; + + +public class SimpleDescriptorFactoryTest { + + private enum FileType { + JSON, - YAML ++ YAML, ++ YML + } + + @Test + public void testParseJSONSimpleDescriptor() throws Exception { + testParseSimpleDescriptor(FileType.JSON); + } + + @Test + public void testParseYAMLSimpleDescriptor() throws Exception { ++ testParseSimpleDescriptor(FileType.YML); + testParseSimpleDescriptor(FileType.YAML); + } + + @Test + public void testParseJSONSimpleDescriptorWithServiceParams() throws Exception { + testParseSimpleDescriptorWithServiceParams(FileType.JSON); + } + + @Test + public void testParseYAMLSimpleDescriptorWithServiceParams() throws Exception { ++ testParseSimpleDescriptorWithServiceParams(FileType.YML); + testParseSimpleDescriptorWithServiceParams(FileType.YAML); + } + + @Test + public void testParseJSONSimpleDescriptorWithApplications() throws Exception { + testParseSimpleDescriptorWithApplications(FileType.JSON); + } + + @Test + public void testParseYAMLSimpleDescriptorApplications() throws Exception { ++ testParseSimpleDescriptorWithApplications(FileType.YML); + testParseSimpleDescriptorWithApplications(FileType.YAML); + } + + + @Test + public void testParseJSONSimpleDescriptorWithServicesAndApplications() throws Exception { + testParseSimpleDescriptorWithServicesAndApplications(FileType.JSON); + } + + @Test + public void testParseYAMLSimpleDescriptorWithServicesAndApplications() throws Exception { ++ testParseSimpleDescriptorWithServicesAndApplications(FileType.YML); + testParseSimpleDescriptorWithServicesAndApplications(FileType.YAML); + } + + + private void testParseSimpleDescriptor(FileType type) throws Exception { + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; + final String discoveryUser = "joeblow"; + final String providerConfig = "ambari-cluster-policy.xml"; + final String clusterName = "myCluster"; + + final Map<String, List<String>> services = new HashMap<>(); + services.put("NODEMANAGER", null); + services.put("JOBTRACKER", null); + services.put("RESOURCEMANAGER", null); + services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org")); + services.put("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080")); + + String fileName = "test-topology." + getFileExtensionForType(type); + File testFile = null; + try { + testFile = writeDescriptorFile(type, + fileName, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services); + SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); + validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (testFile != null) { + try { + testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + + private void testParseSimpleDescriptorWithServiceParams(FileType type) throws Exception { + + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; + final String discoveryUser = "admin"; + final String providerConfig = "ambari-cluster-policy.xml"; + final String clusterName = "myCluster"; + + final Map<String, List<String>> services = new HashMap<>(); + services.put("NODEMANAGER", null); + services.put("JOBTRACKER", null); + services.put("RESOURCEMANAGER", null); + services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org")); + services.put("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080")); + services.put("KNOXSSO", null); + services.put("KNOXTOKEN", null); + services.put("CustomRole", Collections.singletonList("http://c6402.ambari.apache.org:1234")); + + final Map<String, Map<String, String>> serviceParams = new HashMap<>(); + Map<String, String> knoxSSOParams = new HashMap<>(); + knoxSSOParams.put("knoxsso.cookie.secure.only", "true"); + knoxSSOParams.put("knoxsso.token.ttl", "100000"); + serviceParams.put("KNOXSSO", knoxSSOParams); + + Map<String, String> knoxTokenParams = new HashMap<>(); + knoxTokenParams.put("knox.token.ttl", "36000000"); + knoxTokenParams.put("knox.token.audiences", "tokenbased"); + knoxTokenParams.put("knox.token.target.url", "https://localhost:8443/gateway/tokenbased"); + serviceParams.put("KNOXTOKEN", knoxTokenParams); + + Map<String, String> customRoleParams = new HashMap<>(); + customRoleParams.put("custom.param.1", "value1"); + customRoleParams.put("custom.param.2", "value2"); + serviceParams.put("CustomRole", customRoleParams); + + String fileName = "test-topology." + getFileExtensionForType(type); + File testFile = null; + try { + testFile = writeDescriptorFile(type, + fileName, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services, + serviceParams); + SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); + validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services, serviceParams); + } finally { + if (testFile != null) { + try { + testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + + private void testParseSimpleDescriptorWithApplications(FileType type) throws Exception { + + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; + final String discoveryUser = "admin"; + final String providerConfig = "ambari-cluster-policy.xml"; + final String clusterName = "myCluster"; + + final Map<String, List<String>> apps = new HashMap<>(); + apps.put("app-one", null); + apps.put("appTwo", null); + apps.put("thirdApps", null); + apps.put("appfour", Arrays.asList("http://host1:1234", "http://host2:5678", "http://host1:1357")); + apps.put("AppFive", Collections.singletonList("http://host5:8080")); + + final Map<String, Map<String, String>> appParams = new HashMap<>(); + Map<String, String> oneParams = new HashMap<>(); + oneParams.put("appone.cookie.secure.only", "true"); + oneParams.put("appone.token.ttl", "100000"); + appParams.put("app-one", oneParams); + Map<String, String> fiveParams = new HashMap<>(); + fiveParams.put("myproperty", "true"); + fiveParams.put("anotherparam", "100000"); + appParams.put("AppFive", fiveParams); + + String fileName = "test-topology." + getFileExtensionForType(type); + File testFile = null; + try { + testFile = writeDescriptorFile(type, + fileName, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + null, + null, + apps, + appParams); + SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); + validateSimpleDescriptor(sd, + discoveryType, + discoveryAddress, + providerConfig, + clusterName, + null, + null, + apps, + appParams); + } finally { + if (testFile != null) { + try { + testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + + private void testParseSimpleDescriptorWithServicesAndApplications(FileType type) throws Exception { + + final String discoveryType = "AMBARI"; + final String discoveryAddress = "http://c6401.ambari.apache.org:8080"; + final String discoveryUser = "admin"; + final String providerConfig = "ambari-cluster-policy.xml"; + final String clusterName = "myCluster"; + + final Map<String, List<String>> services = new HashMap<>(); + services.put("NODEMANAGER", null); + services.put("JOBTRACKER", null); + services.put("RESOURCEMANAGER", null); + services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org")); + services.put("AMBARIUI", Collections.singletonList("http://c6401.ambari.apache.org:8080")); + services.put("KNOXSSO", null); + services.put("KNOXTOKEN", null); + services.put("CustomRole", Collections.singletonList("http://c6402.ambari.apache.org:1234")); + + final Map<String, Map<String, String>> serviceParams = new HashMap<>(); + Map<String, String> knoxSSOParams = new HashMap<>(); + knoxSSOParams.put("knoxsso.cookie.secure.only", "true"); + knoxSSOParams.put("knoxsso.token.ttl", "100000"); + serviceParams.put("KNOXSSO", knoxSSOParams); + + Map<String, String> knoxTokenParams = new HashMap<>(); + knoxTokenParams.put("knox.token.ttl", "36000000"); + knoxTokenParams.put("knox.token.audiences", "tokenbased"); + knoxTokenParams.put("knox.token.target.url", "https://localhost:8443/gateway/tokenbased"); + serviceParams.put("KNOXTOKEN", knoxTokenParams); + + Map<String, String> customRoleParams = new HashMap<>(); + customRoleParams.put("custom.param.1", "value1"); + customRoleParams.put("custom.param.2", "value2"); + serviceParams.put("CustomRole", customRoleParams); + + final Map<String, List<String>> apps = new HashMap<>(); + apps.put("app-one", null); + apps.put("appTwo", null); + apps.put("thirdApps", null); + apps.put("appfour", Arrays.asList("http://host1:1234", "http://host2:5678", "http://host1:1357")); + apps.put("AppFive", Collections.singletonList("http://host5:8080")); + + final Map<String, Map<String, String>> appParams = new HashMap<>(); + Map<String, String> oneParams = new HashMap<>(); + oneParams.put("appone.cookie.secure.only", "true"); + oneParams.put("appone.token.ttl", "100000"); + appParams.put("app-one", oneParams); + Map<String, String> fiveParams = new HashMap<>(); + fiveParams.put("myproperty", "true"); + fiveParams.put("anotherparam", "100000"); + appParams.put("AppFive", fiveParams); + + String fileName = "test-topology." + getFileExtensionForType(type); + File testFile = null; + try { + testFile = writeDescriptorFile(type, + fileName, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services, + serviceParams, + apps, + appParams); + SimpleDescriptor sd = SimpleDescriptorFactory.parse(testFile.getAbsolutePath()); + validateSimpleDescriptor(sd, + discoveryType, + discoveryAddress, + providerConfig, + clusterName, + services, + serviceParams, + apps, + appParams); + } finally { + if (testFile != null) { + try { + testFile.delete(); + } catch (Exception e) { + // Ignore + } + } + } + } + + private String getFileExtensionForType(FileType type) { + String extension = null; + switch (type) { + case JSON: + extension = "json"; + break; - case YAML: ++ case YML: + extension = "yml"; + break; ++ case YAML: ++ extension = "yaml"; ++ break; + } + return extension; + } + + private File writeDescriptorFile(FileType type, + String path, + String discoveryType, + String discoveryAddress, + String discoveryUser, + String providerConfig, + String clusterName, + Map<String, List<String>> services) throws Exception { + return writeDescriptorFile(type, + path, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services, + null); + } + + private File writeDescriptorFile(FileType type, + String path, + String discoveryType, + String discoveryAddress, + String discoveryUser, + String providerConfig, + String clusterName, + Map<String, List<String>> services, + Map<String, Map<String, String>> serviceParams) throws Exception { + return writeDescriptorFile(type, + path, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services, + serviceParams, + null, + null); + } + + + private File writeDescriptorFile(FileType type, + String path, + String discoveryType, + String discoveryAddress, + String discoveryUser, + String providerConfig, + String clusterName, + Map<String, List<String>> services, + Map<String, Map<String, String>> serviceParams, + Map<String, List<String>> apps, + Map<String, Map<String, String>> appParams) throws Exception { + File result = null; + switch (type) { + case JSON: + result = writeJSON(path, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services, + serviceParams, + apps, + appParams); + break; + case YAML: ++ case YML: + result = writeYAML(path, + discoveryType, + discoveryAddress, + discoveryUser, + providerConfig, + clusterName, + services, + serviceParams, + apps, + appParams); + break; + } + return result; + } + + + private File writeJSON(String path, + String discoveryType, + String discoveryAddress, + String discoveryUser, + String providerConfig, + String clusterName, + Map<String, List<String>> services, + Map<String, Map<String, String>> serviceParams, + Map<String, List<String>> apps, + Map<String, Map<String, String>> appParams) throws Exception { + File f = new File(path); + + Writer fw = new FileWriter(f); + fw.write("{" + "\n"); + fw.write("\"discovery-type\":\"" + discoveryType + "\",\n"); + fw.write("\"discovery-address\":\"" + discoveryAddress + "\",\n"); + fw.write("\"discovery-user\":\"" + discoveryUser + "\",\n"); + fw.write("\"provider-config-ref\":\"" + providerConfig + "\",\n"); + fw.write("\"cluster\":\"" + clusterName + "\""); + + if (services != null && !services.isEmpty()) { + fw.write(",\n\"services\":[\n"); + writeServiceOrApplicationJSON(fw, services, serviceParams); + fw.write("]\n"); + } + + if (apps != null && !apps.isEmpty()) { + fw.write(",\n\"applications\":[\n"); + writeServiceOrApplicationJSON(fw, apps, appParams); + fw.write("]\n"); + } + + fw.write("}\n"); + fw.flush(); + fw.close(); + + return f; + } + + private void writeServiceOrApplicationJSON(Writer fw, + Map<String, List<String>> elementURLs, + Map<String, Map<String, String>> elementParams) throws Exception { + if (elementURLs != null) { + int i = 0; + for (String name : elementURLs.keySet()) { + fw.write("{\"name\":\"" + name + "\""); + + // Service params + if (elementParams != null && !elementParams.isEmpty()) { + Map<String, String> params = elementParams.get(name); + if (params != null && !params.isEmpty()) { + fw.write(",\n\"params\":{\n"); + Iterator<String> paramNames = params.keySet().iterator(); + while (paramNames.hasNext()) { + String paramName = paramNames.next(); + String paramValue = params.get(paramName); + fw.write("\"" + paramName + "\":\"" + paramValue + "\""); + fw.write(paramNames.hasNext() ? ",\n" : ""); + } + fw.write("\n}"); + } + } + + // Service URLs + List<String> urls = elementURLs.get(name); + if (urls != null) { + fw.write(",\n\"urls\":["); + Iterator<String> urlIter = urls.iterator(); + while (urlIter.hasNext()) { + fw.write("\"" + urlIter.next() + "\""); + if (urlIter.hasNext()) { + fw.write(", "); + } + } + fw.write("]\n"); + } + + fw.write("}"); + if (i++ < elementURLs.size() - 1) { + fw.write(","); + } + fw.write("\n"); + } + } + } + + private File writeYAML(String path, + String discoveryType, + String discoveryAddress, + String discoveryUser, + String providerConfig, + String clusterName, + Map<String, List<String>> services, + Map<String, Map<String, String>> serviceParams, + Map<String, List<String>> apps, + Map<String, Map<String, String>> appParams) throws Exception { + + File f = new File(path); + + Writer fw = new FileWriter(f); + fw.write("---" + "\n"); + fw.write("discovery-type: " + discoveryType + "\n"); + fw.write("discovery-address: " + discoveryAddress + "\n"); + fw.write("discovery-user: " + discoveryUser + "\n"); + fw.write("provider-config-ref: " + providerConfig + "\n"); + fw.write("cluster: " + clusterName+ "\n"); + + if (services != null && !services.isEmpty()) { + fw.write("services:\n"); + writeServiceOrApplicationYAML(fw, services, serviceParams); + } + + if (apps != null && !apps.isEmpty()) { + fw.write("applications:\n"); + writeServiceOrApplicationYAML(fw, apps, appParams); + } + + fw.flush(); + fw.close(); + + return f; + } + + private void writeServiceOrApplicationYAML(Writer fw, + Map<String, List<String>> elementURLs, + Map<String, Map<String, String>> elementParams) throws Exception { + for (String name : elementURLs.keySet()) { + fw.write(" - name: " + name + "\n"); + + // Service params + if (elementParams != null && !elementParams.isEmpty()) { + if (elementParams.containsKey(name)) { + Map<String, String> params = elementParams.get(name); + fw.write(" params:\n"); + for (String paramName : params.keySet()) { + fw.write(" " + paramName + ": " + params.get(paramName) + "\n"); + } + } + } + + // Service URLs + List<String> urls = elementURLs.get(name); + if (urls != null) { + fw.write(" urls:\n"); + for (String url : urls) { + fw.write(" - " + url + "\n"); + } + } + } + } + + + private void validateSimpleDescriptor(SimpleDescriptor sd, + String discoveryType, + String discoveryAddress, + String providerConfig, + String clusterName, + Map<String, List<String>> expectedServices) { + validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, expectedServices, null); + } + + + private void validateSimpleDescriptor(SimpleDescriptor sd, + String discoveryType, + String discoveryAddress, + String providerConfig, + String clusterName, + Map<String, List<String>> expectedServices, + Map<String, Map<String, String>> expectedServiceParameters) { + validateSimpleDescriptor(sd, + discoveryType, + discoveryAddress, + providerConfig, + clusterName, + expectedServices, + expectedServiceParameters, + null, + null); + } + + private void validateSimpleDescriptor(SimpleDescriptor sd, + String discoveryType, + String discoveryAddress, + String providerConfig, + String clusterName, + Map<String, List<String>> expectedServices, + Map<String, Map<String, String>> expectedServiceParameters, + Map<String, List<String>> expectedApps, + Map<String, Map<String, String>> expectedAppParameters) { + assertNotNull(sd); + assertEquals(discoveryType, sd.getDiscoveryType()); + assertEquals(discoveryAddress, sd.getDiscoveryAddress()); + assertEquals(providerConfig, sd.getProviderConfig()); + assertEquals(clusterName, sd.getClusterName()); + + List<SimpleDescriptor.Service> actualServices = sd.getServices(); + + if (expectedServices == null) { + assertTrue(actualServices.isEmpty()); + } else { + assertEquals(expectedServices.size(), actualServices.size()); + + for (SimpleDescriptor.Service actualService : actualServices) { + assertTrue(expectedServices.containsKey(actualService.getName())); + assertEquals(expectedServices.get(actualService.getName()), actualService.getURLs()); + + // Validate service parameters + if (expectedServiceParameters != null) { + if (expectedServiceParameters.containsKey(actualService.getName())) { + Map<String, String> expectedParams = expectedServiceParameters.get(actualService.getName()); + + Map<String, String> actualServiceParams = actualService.getParams(); + assertNotNull(actualServiceParams); + + // Validate the size of the service parameter set + assertEquals(expectedParams.size(), actualServiceParams.size()); + + // Validate the parameter contents + for (String paramName : actualServiceParams.keySet()) { + assertTrue(expectedParams.containsKey(paramName)); + assertEquals(expectedParams.get(paramName), actualServiceParams.get(paramName)); + } + } + } + } + } + + List<SimpleDescriptor.Application> actualApps = sd.getApplications(); + + if (expectedApps == null) { + assertTrue(actualApps.isEmpty()); + } else { + assertEquals(expectedApps.size(), actualApps.size()); + + for (SimpleDescriptor.Application actualApp : actualApps) { + assertTrue(expectedApps.containsKey(actualApp.getName())); + assertEquals(expectedApps.get(actualApp.getName()), actualApp.getURLs()); + + // Validate service parameters + if (expectedServiceParameters != null) { + if (expectedAppParameters.containsKey(actualApp.getName())) { + Map<String, String> expectedParams = expectedAppParameters.get(actualApp.getName()); + + Map<String, String> actualAppParams = actualApp.getParams(); + assertNotNull(actualAppParams); + + // Validate the size of the service parameter set + assertEquals(expectedParams.size(), actualAppParams.size()); + + // Validate the parameter contents + for (String paramName : actualAppParams.keySet()) { + assertTrue(expectedParams.containsKey(paramName)); + assertEquals(expectedParams.get(paramName), actualAppParams.get(paramName)); + } + } + } + } + } + } + +}