Merge branch 'master' into KNOX-998-Package_Restructuring # Conflicts: # gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayAppFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayDeployFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayLdapDynamicGroupFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayLdapGroupFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayLdapPosixGroupFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayLocalServiceFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewayMultiFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewaySampleFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/GatewaySslFuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/Knox242FuncTest.java # gateway-test/src/test/java/org/apache/knox/gateway/KnoxCliLdapFuncTestNegative.java # gateway-test/src/test/java/org/apache/knox/gateway/KnoxCliLdapFuncTestPositive.java # gateway-test/src/test/java/org/apache/knox/gateway/KnoxCliSysBindTest.java
Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/912c5360 Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/912c5360 Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/912c5360 Branch: refs/heads/KNOX-998-Package_Restructuring Commit: 912c53602a409e4361a73130e4dbc55a7b73c8ea Parents: a25f8a7 6657f2f Author: Sandeep More <m...@apache.org> Authored: Tue Aug 29 11:02:24 2017 -0400 Committer: Sandeep More <m...@apache.org> Committed: Tue Aug 29 11:02:24 2017 -0400 ---------------------------------------------------------------------- .../apache/knox/gateway/GatewayTestDriver.java | 20 +++++---- .../knox/gateway/GatewayAdminFuncTest.java | 27 +++--------- .../gateway/GatewayAdminTopologyFuncTest.java | 36 +++++----------- .../apache/knox/gateway/GatewayAppFuncTest.java | 26 ++---------- .../knox/gateway/GatewayBasicFuncTest.java | 42 +++++++++++++++++-- .../knox/gateway/GatewayDeployFuncTest.java | 26 +++--------- .../GatewayLdapDynamicGroupFuncTest.java | 44 +++++++------------- .../knox/gateway/GatewayLdapGroupFuncTest.java | 36 +++++----------- .../gateway/GatewayLdapPosixGroupFuncTest.java | 34 ++++++--------- .../gateway/GatewayLocalServiceFuncTest.java | 26 +++--------- .../knox/gateway/GatewayMultiFuncTest.java | 29 ++++--------- .../knox/gateway/GatewaySampleFuncTest.java | 26 +++--------- .../apache/knox/gateway/GatewaySslFuncTest.java | 23 ++-------- .../apache/knox/gateway/Knox242FuncTest.java | 43 +++++++------------ .../gateway/KnoxCliLdapFuncTestNegative.java | 32 ++++---------- .../gateway/KnoxCliLdapFuncTestPositive.java | 32 ++++---------- .../apache/knox/gateway/KnoxCliSysBindTest.java | 32 ++++---------- .../solr/query_response.xml | 20 +++++++++ 18 files changed, 194 insertions(+), 360 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/912c5360/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestDriver.java ---------------------------------------------------------------------- diff --cc gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestDriver.java index 28c0043,0000000..a893cb4 mode 100644,000000..100644 --- a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestDriver.java +++ b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestDriver.java @@@ -1,347 -1,0 +1,351 @@@ +/** + * 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; + +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.knox.gateway.config.GatewayConfig; +import org.apache.knox.gateway.security.ldap.SimpleLdapDirectoryServer; +import org.apache.knox.gateway.services.DefaultGatewayServices; +import org.apache.knox.gateway.services.ServiceLifecycleException; +import org.apache.hadoop.test.mock.MockServer; +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mycila.xmltool.XMLTag; + +/** + * This class was created to reduce much of the duplication and boiler plate that was ending up in the GatewayBasicFuncTest class. + * It basically does a number of different things. + * 1) Creates a GATEWAY_HOME starts a gateway instance and deployes a test topology. + * 2) Provides a registry of mock Hadoop services. + * 3) Provides "bundled" methods for common Hadoop operations to avoid duplication in tests. + * 4) Provides methods to access test resources. + */ +public class GatewayTestDriver { + + private static Logger log = LoggerFactory.getLogger( GatewayTestDriver.class ); + + public Class<?> resourceBaseClass; + public Map<String,Service> services = new HashMap<>(); + public SimpleLdapDirectoryServer ldap; + public TcpTransport ldapTransport; + public boolean useGateway; + public GatewayServer gateway; + public GatewayConfig config; + public String clusterName; + + /** + * Sets the class from which relative test resource names should be resolved. + * @param resourceBaseClass The class from which relative test resource names should be resolved. + */ + public void setResourceBase( Class<?> resourceBaseClass ) { + this.resourceBaseClass = resourceBaseClass; + } + + /** + * Starts an embedded LDAP server of the specified port. + * @param port The desired port the LDAP server should listen on. + * @return The actual port the LDAP server is listening on. + * @throws Exception Thrown if a failure occurs. + */ + public int setupLdap( int port ) throws Exception { + String basedir = System.getProperty("basedir"); + if (basedir == null) { + basedir = new File(".").getCanonicalPath(); + } + Path path = FileSystems.getDefault().getPath(basedir, "/src/test/resources/users.ldif"); + return setupLdap( port, path.toFile() ); + } - ++ + public int setupLdap( int port, File ldifConfig ) throws Exception { + ldapTransport = new TcpTransport( port ); + ldap = new SimpleLdapDirectoryServer( "dc=hadoop,dc=apache,dc=org", ldifConfig, ldapTransport ); + ldap.start(); + log.info( "LDAP port = " + ldapTransport.getAcceptor().getLocalAddress().getPort() ); + return port; + } + + /** + * Adds a mock service to the registry. + */ + public void setupService( String role, String realUrl, String gatewayPath, boolean mock ) throws Exception { + Service service = new Service( role, realUrl, gatewayPath, mock ); + services.put( role, service ); + log.info( role + " port = " + service.server.getPort() ); + } + + /** + * Creates a GATEWAY_HOME, starts a gateway instance and deploys a test topology. + */ + public void setupGateway( GatewayTestConfig config, String cluster, XMLTag topology, boolean use ) throws Exception { + this.useGateway = use; + this.config = config; + this.clusterName = cluster; + + File targetDir = new File( System.getProperty( "user.dir" ), "target" ); + File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() ); + gatewayDir.mkdirs(); + + config.setGatewayHomeDir( gatewayDir.getAbsolutePath() ); + + File topoDir = new File( config.getGatewayTopologyDir() ); + topoDir.mkdirs(); + + File deployDir = new File( config.getGatewayDeploymentDir() ); + deployDir.mkdirs(); + + File descriptor = new File( topoDir, cluster + ".xml" ); + FileOutputStream stream = new FileOutputStream( descriptor ); + topology.toStream( stream ); + stream.close(); + + DefaultGatewayServices srvcs = new DefaultGatewayServices(); + Map<String,String> options = new HashMap<>(); + options.put("persist-master", "false"); + options.put("master", "password"); + try { + srvcs.init(config, options); + } catch (ServiceLifecycleException e) { + e.printStackTrace(); // I18N not required. + } + File stacksDir = new File( config.getGatewayServicesDir() ); + stacksDir.mkdirs(); + //TODO: [sumit] This is a hack for now, need to find a better way to locate the source resources for 'stacks' to be tested + String pathToStacksSource = "gateway-service-definitions/src/main/resources/services"; + File stacksSourceDir = new File( targetDir.getParent(), pathToStacksSource); + if (!stacksSourceDir.exists()) { + stacksSourceDir = new File( targetDir.getParentFile().getParent(), pathToStacksSource); + } + if (!stacksSourceDir.exists()) { + stacksSourceDir = new File( targetDir.getParentFile().getParentFile().getParent(), pathToStacksSource); + } + if (stacksSourceDir.exists()) { + FileUtils.copyDirectoryToDirectory(stacksSourceDir, stacksDir); + } + + gateway = GatewayServer.startGateway( config, srvcs ); + MatcherAssert.assertThat( "Failed to start gateway.", gateway, CoreMatchers.notNullValue() ); + + log.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() ); + } + + public void cleanup() throws Exception { - gateway.stop(); - FileUtils.deleteQuietly( new File( config.getGatewayTopologyDir() ) ); - FileUtils.deleteQuietly( new File( config.getGatewayConfDir() ) ); - FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) ); - FileUtils.deleteQuietly( new File( config.getGatewayDeploymentDir() ) ); - FileUtils.deleteQuietly( new File( config.getGatewayDataDir() ) ); - FileUtils.deleteQuietly( new File( config.getGatewayServicesDir() ) ); ++ if ( gateway != null ) { ++ gateway.stop(); ++ } ++ if ( config != null ) { ++ FileUtils.deleteQuietly( new File( config.getGatewayTopologyDir() ) ); ++ FileUtils.deleteQuietly( new File( config.getGatewayConfDir() ) ); ++ FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) ); ++ FileUtils.deleteQuietly( new File( config.getGatewayDeploymentDir() ) ); ++ FileUtils.deleteQuietly( new File( config.getGatewayDataDir() ) ); ++ FileUtils.deleteQuietly( new File( config.getGatewayServicesDir() ) ); ++ } + + for( Service service : services.values() ) { + service.server.stop(); + } + services.clear(); + + ldap.stop( true ); + } + + public boolean isUseGateway() { + return useGateway; + } + + public MockServer getMock( String serviceRole ) { + Service service = services.get( serviceRole ); + return service.server; + } + + public String getRealUrl( String serviceRole ) { + return getUrl( serviceRole, true ); + } + + public String getUrl( String serviceRole ) { + return getUrl( serviceRole, false ); + } + + private String getLocalHostName() { + String hostName = "localhost"; + try { + hostName = InetAddress.getByName( "127.0.0.1" ).getHostName(); + } catch( UnknownHostException e ) { + // Ignore and use the default. + } + return hostName; + } + + public String getUrl( String serviceRole, boolean real ) { + String url; + String localHostName = getLocalHostName(); + Service service = services.get( serviceRole ); + if( useGateway && !real ) { + url = "http://" + localHostName + ":" + gateway.getAddresses()[0].getPort() + "/" + config.getGatewayPath() + service.gatewayPath; + } else if( service.mock ) { + url = "http://" + localHostName + ":" + service.server.getPort(); + } else { + url = service.realUrl.toASCIIString(); + } + return url; + } + + public String getClusterUrl() { + String url; + String localHostName = getLocalHostName(); + url = "http://" + localHostName + ":" + gateway.getAddresses()[0].getPort() + "/" + config.getGatewayPath() + "/" + clusterName; + return url; + } + + public int getGatewayPort() { + return gateway.getAddresses()[0].getPort(); + } + + public String getRealAddr( String role ) { + String addr; + String localHostName = getLocalHostName(); + Service service = services.get( role ); + if( service.mock ) { + addr = localHostName + ":" + service.server.getPort(); + } else { + addr = service.realUrl.getHost() + ":" + service.realUrl.getPort(); + } + return addr; + } + + public String getLdapUrl() { + return "ldap://localhost:" + ldapTransport.getAcceptor().getLocalAddress().getPort(); + } + + private static class Service { + String role; + URI realUrl; + String gatewayPath; + boolean mock; + MockServer server; + private Service( String role, String realUrl, String gatewayPath, boolean mock ) throws Exception { + this.role = role; + this.realUrl = new URI( realUrl ); + this.gatewayPath = gatewayPath; + this.mock = mock; + this.server = new MockServer( role, true ); + } + } + + public String getResourceBaseName() { + return resourceBaseClass.getName().replaceAll( "\\.", "/" ) + "/"; + } + + public String getResourceName( String resource ) { + return getResourceBaseName() + resource; + } + + public URL getResourceUrl( String resource ) { + URL url = ClassLoader.getSystemResource( getResourceName( resource ) ); + assertThat( "Failed to find test resource " + resource, url, Matchers.notNullValue() ); + return url; + } + + public InputStream getResourceStream( String resource ) throws IOException { + InputStream stream = null; + if( resource.startsWith( "file:/" ) ) { + try { + stream = FileUtils.openInputStream( new File( new URI( resource ) ) ); + } catch( URISyntaxException e ) { + throw new IOException( e ); + } + } else { + stream = ClassLoader.getSystemResourceAsStream( getResourceName( resource ) ); + } + assertThat( "Failed to find test resource " + resource, stream, Matchers.notNullValue() ); + return stream; + } + + public byte[] getResourceBytes( String resource ) throws IOException { + return IOUtils.toByteArray( getResourceStream( resource ) ); + } + + public String getResourceString( String resource, Charset charset ) throws IOException { + return IOUtils.toString( getResourceBytes( resource ), "UTF-8" ); + } + + public void assertComplete() { + // Check to make sure that all interaction were satisfied if for mocked services. + // Otherwise just clear the mock interaction queue. + for( Service service : services.values() ) { + if( service.mock ) { + assertThat( + "Service " + service.role + " has remaining expected interactions.", + service.server.getCount(), Matchers.is(0) ); + } + service.server.reset(); + } + } + + + public void assertNotComplete(String serviceName) { + // Check to make sure that all interaction were satisfied if for mocked services. + // Otherwise just clear the mock interaction queue. + + Service service = services.get(serviceName); + + if(service != null) { + if(service.mock) { + assertThat( + "Service " + service.role + " has remaining expected interactions.", + service.server.getCount(), Matchers.not(0)); + } + service.server.reset(); + } else { + fail(); + } + } + + public void reset() { + for( Service service : services.values() ) { + service.server.reset(); + } + } + + +} http://git-wip-us.apache.org/repos/asf/knox/blob/912c5360/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminFuncTest.java ---------------------------------------------------------------------- diff --cc gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminFuncTest.java index 2ca5fce,0000000..5b0a4e1 mode 100644,000000..100644 --- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminFuncTest.java +++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminFuncTest.java @@@ -1,216 -1,0 +1,199 @@@ +/** + * 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; + +import com.mycila.xmltool.XMLDoc; +import com.mycila.xmltool.XMLTag; - import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.knox.gateway.config.GatewayConfig; - import org.apache.knox.gateway.security.ldap.SimpleLdapDirectoryServer; +import org.apache.knox.gateway.services.DefaultGatewayServices; +import org.apache.knox.gateway.services.ServiceLifecycleException; +import org.apache.hadoop.test.TestUtils; +import org.apache.http.HttpStatus; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.core.MediaType; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; - import java.nio.file.FileSystems; - import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static com.jayway.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +public class GatewayAdminFuncTest { + + private static Class RESOURCE_BASE_CLASS = GatewayAdminFuncTest.class; + private static Logger LOG = LoggerFactory.getLogger( GatewayAdminFuncTest.class ); + + //public static Enumeration<Appender> appenders; + public static GatewayConfig config; + public static GatewayServer gateway; + public static String gatewayUrl; + public static String clusterUrl; - public static SimpleLdapDirectoryServer ldap; - public static TcpTransport ldapTransport; ++ private static GatewayTestDriver driver = new GatewayTestDriver(); + + @BeforeClass + public static void setupSuite() throws Exception { + TestUtils.LOG_ENTER(); + //appenders = NoOpAppender.setUp(); - setupLdap(); ++ driver.setupLdap(0); + setupGateway(); + TestUtils.LOG_EXIT(); + } + + @AfterClass + public static void cleanupSuite() throws Exception { + TestUtils.LOG_ENTER(); + gateway.stop(); - ldap.stop( true ); ++ driver.cleanup(); + //FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) ); + //NoOpAppender.tearDown( appenders ); + TestUtils.LOG_EXIT(); + } + - public static void setupLdap() throws Exception { - String basedir = System.getProperty("basedir"); - if (basedir == null) { - basedir = new File(".").getCanonicalPath(); - } - Path path = FileSystems.getDefault().getPath(basedir, "/src/test/resources/users.ldif"); - ldapTransport = new TcpTransport( 0 ); - ldap = new SimpleLdapDirectoryServer( "dc=hadoop,dc=apache,dc=org", path.toFile(), ldapTransport ); - ldap.start(); - LOG.info( "LDAP port = " + ldapTransport.getPort() ); - } - + public static void setupGateway() throws Exception { + + File targetDir = new File( System.getProperty( "user.dir" ), "target" ); + File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() ); + gatewayDir.mkdirs(); + + GatewayTestConfig testConfig = new GatewayTestConfig(); + config = testConfig; + testConfig.setGatewayHomeDir( gatewayDir.getAbsolutePath() ); + + File topoDir = new File( testConfig.getGatewayTopologyDir() ); + topoDir.mkdirs(); + + File deployDir = new File( testConfig.getGatewayDeploymentDir() ); + deployDir.mkdirs(); + + File descriptor = new File( topoDir, "test-cluster.xml" ); + FileOutputStream stream = new FileOutputStream( descriptor ); + createTopology().toStream( stream ); + stream.close(); + + DefaultGatewayServices srvcs = new DefaultGatewayServices(); + Map<String,String> options = new HashMap<>(); + options.put( "persist-master", "false" ); + options.put( "master", "password" ); + try { + srvcs.init( testConfig, options ); + } catch ( ServiceLifecycleException e ) { + e.printStackTrace(); // I18N not required. + } + gateway = GatewayServer.startGateway( testConfig, srvcs ); + MatcherAssert.assertThat( "Failed to start gateway.", gateway, notNullValue() ); + + LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() ); + + gatewayUrl = "http://localhost:" + gateway.getAddresses()[0].getPort() + "/" + config.getGatewayPath(); + clusterUrl = gatewayUrl + "/test-cluster"; + } + + private static XMLTag createTopology() { + XMLTag xml = XMLDoc.newDocument( true ) + .addRoot( "topology" ) + .addTag( "gateway" ) + .addTag( "provider" ) + .addTag( "role" ).addText( "authentication" ) + .addTag( "name" ).addText( "ShiroProvider" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm" ) - .addTag( "value" ).addText( "KnoxLdapRealm" ).gotoParent() ++ .addTag( "value" ).addText( "org.apache.knox.gateway.shirorealm.KnoxLdapRealm" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.userDnTemplate" ) + .addTag( "value" ).addText( "uid={0},ou=people,dc=hadoop,dc=apache,dc=org" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.url" ) - .addTag( "value" ).addText( "ldap://localhost:" + ldapTransport.getAcceptor().getLocalAddress().getPort() ).gotoParent() ++ .addTag( "value" ).addText( driver.getLdapUrl() ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.authenticationMechanism" ) + .addTag( "value" ).addText( "simple" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "urls./**" ) + .addTag( "value" ).addText( "authcBasic" ).gotoParent().gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "identity-assertion" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "Default" ).gotoParent() + .addTag( "provider" ) + .gotoRoot() + .addTag( "service" ) + .addTag( "role" ).addText( "KNOX" ) + .gotoRoot(); + // System.out.println( "GATEWAY=" + xml.toString() ); + return xml; + } + + public static InputStream getResourceStream( String resource ) throws IOException { + return getResourceUrl( resource ).openStream(); + } + + public static URL getResourceUrl( String resource ) { + URL url = ClassLoader.getSystemResource( getResourceName( resource ) ); + assertThat( "Failed to find test resource " + resource, url, Matchers.notNullValue() ); + return url; + } + + public static String getResourceName( String resource ) { + return getResourceBaseName() + resource; + } + + public static String getResourceBaseName() { + return RESOURCE_BASE_CLASS.getName().replaceAll( "\\.", "/" ) + "/"; + } + + //@Test + public void waitForManualTesting() throws IOException { + System.out.println( clusterUrl ); + System.in.read(); + } + + @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testAdminService() throws ClassNotFoundException { + TestUtils.LOG_ENTER(); + + String username = "guest"; + String password = "guest-password"; + String serviceUrl = clusterUrl + "/api/v1/version"; + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + //.body( is( "{\"hash\":\"unknown\",\"version\":\"unknown\"}" ) ) + .when().get( serviceUrl ); + + TestUtils.LOG_EXIT(); + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/912c5360/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java ---------------------------------------------------------------------- diff --cc gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java index e5973d3,0000000..59c8542 mode 100644,000000..100644 --- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java +++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java @@@ -1,837 -1,0 +1,821 @@@ +/** + * 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; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; - import java.nio.file.FileSystems; - import java.nio.file.Path; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import javax.ws.rs.core.MediaType; + +import com.jayway.restassured.http.ContentType; +import com.mycila.xmltool.XMLDoc; +import com.mycila.xmltool.XMLTag; +import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.knox.gateway.config.GatewayConfig; +import org.apache.knox.gateway.security.ldap.SimpleLdapDirectoryServer; +import org.apache.knox.gateway.services.DefaultGatewayServices; +import org.apache.knox.gateway.services.GatewayServices; +import org.apache.knox.gateway.services.ServiceLifecycleException; +import org.apache.knox.gateway.services.topology.TopologyService; +import org.apache.knox.gateway.topology.Param; +import org.apache.knox.gateway.topology.Provider; +import org.apache.knox.gateway.topology.Service; +import org.apache.knox.gateway.topology.Topology; +import org.apache.knox.gateway.util.XmlUtils; +import org.apache.hadoop.test.TestUtils; +import org.apache.http.HttpStatus; +import org.apache.log4j.Appender; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +import static com.jayway.restassured.RestAssured.given; +import static org.apache.hadoop.test.TestUtils.LOG_ENTER; +import static org.apache.hadoop.test.TestUtils.LOG_EXIT; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.xml.HasXPath.hasXPath; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +public class GatewayAdminTopologyFuncTest { + + private static Class RESOURCE_BASE_CLASS = GatewayAdminTopologyFuncTest.class; + private static Logger LOG = LoggerFactory.getLogger( GatewayAdminTopologyFuncTest.class ); + + public static Enumeration<Appender> appenders; + public static GatewayConfig config; + public static GatewayServer gateway; + public static String gatewayUrl; + public static String clusterUrl; - public static SimpleLdapDirectoryServer ldap; - public static TcpTransport ldapTransport; ++ private static GatewayTestDriver driver = new GatewayTestDriver(); + + @BeforeClass + public static void setupSuite() throws Exception { + //appenders = NoOpAppender.setUp(); - setupLdap(); ++ driver.setupLdap(0); + setupGateway(new GatewayTestConfig()); + } + + @AfterClass + public static void cleanupSuite() throws Exception { + gateway.stop(); - ldap.stop( true ); ++ driver.cleanup(); + //FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) ); + //NoOpAppender.tearDown( appenders ); + } + - public static void setupLdap() throws Exception { - String basedir = System.getProperty("basedir"); - if (basedir == null) { - basedir = new File(".").getCanonicalPath(); - } - Path path = FileSystems.getDefault().getPath(basedir, "/src/test/resources/users.ldif"); - - ldapTransport = new TcpTransport( 0 ); - ldap = new SimpleLdapDirectoryServer( "dc=hadoop,dc=apache,dc=org", path.toFile(), ldapTransport ); - ldap.start(); - LOG.info( "LDAP port = " + ldapTransport.getAcceptor().getLocalAddress().getPort() ); - } - + public static void setupGateway(GatewayTestConfig testConfig) throws Exception { + + File targetDir = new File( System.getProperty( "user.dir" ), "target" ); + File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() ); + gatewayDir.mkdirs(); + + config = testConfig; + testConfig.setGatewayHomeDir( gatewayDir.getAbsolutePath() ); + + File topoDir = new File( testConfig.getGatewayTopologyDir() ); + topoDir.mkdirs(); + + File deployDir = new File( testConfig.getGatewayDeploymentDir() ); + deployDir.mkdirs(); + + File descriptor = new File( topoDir, "admin.xml" ); + FileOutputStream stream = new FileOutputStream( descriptor ); + createKnoxTopology().toStream( stream ); + stream.close(); + + File descriptor2 = new File( topoDir, "test-cluster.xml" ); + FileOutputStream stream2 = new FileOutputStream( descriptor2 ); + createNormalTopology().toStream( stream2 ); + stream.close(); + + DefaultGatewayServices srvcs = new DefaultGatewayServices(); + Map<String,String> options = new HashMap<>(); + options.put( "persist-master", "false" ); + options.put( "master", "password" ); + + try { + srvcs.init( testConfig, options ); + } catch ( ServiceLifecycleException e ) { + e.printStackTrace(); // I18N not required. + } + gateway = GatewayServer.startGateway( testConfig, srvcs ); + MatcherAssert.assertThat( "Failed to start gateway.", gateway, notNullValue() ); + + LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() ); + + gatewayUrl = "http://localhost:" + gateway.getAddresses()[0].getPort() + "/" + config.getGatewayPath(); + clusterUrl = gatewayUrl + "/admin"; + } + + private static XMLTag createNormalTopology() { + XMLTag xml = XMLDoc.newDocument( true ) + .addRoot( "topology" ) + .addTag( "gateway" ) + .addTag( "provider" ) + .addTag( "role" ).addText( "webappsec" ) + .addTag( "name" ).addText( "WebAppSec" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "csrf.enabled" ) + .addTag( "value" ).addText( "true" ).gotoParent().gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "authentication" ) + .addTag( "name" ).addText( "ShiroProvider" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm" ) - .addTag( "value" ).addText( "KnoxLdapRealm" ).gotoParent() ++ .addTag( "value" ).addText( "org.apache.knox.gateway.shirorealm.KnoxLdapRealm" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.userDnTemplate" ) + .addTag( "value" ).addText( "uid={0},ou=people,dc=hadoop,dc=apache,dc=org" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.url" ) - .addTag( "value" ).addText( "ldap://localhost:" + ldapTransport.getAcceptor().getLocalAddress().getPort() ).gotoParent() ++ .addTag( "value" ).addText( driver.getLdapUrl() ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.authenticationMechanism" ) + .addTag( "value" ).addText( "simple" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "urls./**" ) + .addTag( "value" ).addText( "authcBasic" ).gotoParent().gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "identity-assertion" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "Default" ).gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "authorization" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "AclsAuthz" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "webhdfs-acl" ) + .addTag( "value" ).addText( "hdfs;*;*" ).gotoParent() + .gotoRoot() + .addTag( "service" ) + .addTag( "role" ).addText( "WEBHDFS" ) + .addTag( "url" ).addText( "http://localhost:50070/webhdfs/v1" ).gotoParent() + .gotoRoot(); +// System.out.println( "GATEWAY=" + xml.toString() ); + return xml; + } + + private static XMLTag createKnoxTopology() { + XMLTag xml = XMLDoc.newDocument( true ) + .addRoot( "topology" ) + .addTag( "gateway" ) + .addTag( "provider" ) + .addTag( "role" ).addText( "authentication" ) + .addTag( "name" ).addText( "ShiroProvider" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm" ) - .addTag( "value" ).addText( "KnoxLdapRealm" ).gotoParent() ++ .addTag( "value" ).addText( "org.apache.knox.gateway.shirorealm.KnoxLdapRealm" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.userDnTemplate" ) + .addTag( "value" ).addText( "uid={0},ou=people,dc=hadoop,dc=apache,dc=org" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.url" ) - .addTag( "value" ).addText( "ldap://localhost:" + ldapTransport.getAcceptor().getLocalAddress().getPort() ).gotoParent() ++ .addTag( "value" ).addText( driver.getLdapUrl() ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.authenticationMechanism" ) + .addTag( "value" ).addText( "simple" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "urls./**" ) + .addTag( "value" ).addText( "authcBasic" ).gotoParent().gotoParent() + .addTag("provider") + .addTag( "role" ).addText( "authorization" ) + .addTag( "name" ).addText( "AclsAuthz" ) + .addTag( "enabled" ).addText( "true" ) + .addTag("param") + .addTag("name").addText("knox.acl") + .addTag("value").addText("admin;*;*").gotoParent().gotoParent() + .addTag("provider") + .addTag( "role" ).addText( "identity-assertion" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "Default" ).gotoParent() + .gotoRoot() + .addTag( "service" ) + .addTag( "role" ).addText( "KNOX" ) + .gotoRoot(); + // System.out.println( "GATEWAY=" + xml.toString() ); + return xml; + } + + public static InputStream getResourceStream( String resource ) throws IOException { + return getResourceUrl( resource ).openStream(); + } + + public static URL getResourceUrl( String resource ) { + URL url = ClassLoader.getSystemResource( getResourceName( resource ) ); + assertThat( "Failed to find test resource " + resource, url, Matchers.notNullValue() ); + return url; + } + + public static String getResourceName( String resource ) { + return getResourceBaseName() + resource; + } + + public static String getResourceBaseName() { + return RESOURCE_BASE_CLASS.getName().replaceAll( "\\.", "/" ) + "/"; + } + + //@Test + public void waitForManualTesting() throws IOException { + System.in.read(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testTopologyCollection() throws ClassNotFoundException { + LOG_ENTER(); + + String username = "admin"; + String password = "admin-password"; + String serviceUrl = clusterUrl + "/api/v1/topologies"; + String href1 = given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .body("topologies.topology[0].name", not(nullValue())) + .body("topologies.topology[1].name", not(nullValue())) + .body("topologies.topology[0].uri", not(nullValue())) + .body("topologies.topology[1].uri", not(nullValue())) + .body("topologies.topology[0].href", not(nullValue())) + .body("topologies.topology[1].href", not(nullValue())) + .body("topologies.topology[0].timestamp", not(nullValue())) + .body("topologies.topology[1].timestamp", not(nullValue())) + .when().get(serviceUrl).thenReturn().getBody().path("topologies.topology.href[1]"); + + given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + //.log().all() + .body("topologies.topology.href[1]", equalTo(href1)) + .statusCode(HttpStatus.SC_OK) + .when().get(serviceUrl); + + + given() + //.log().all() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType(MediaType.APPLICATION_XML) + .get(serviceUrl); + + + given().auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/json") + .body("topology.name", equalTo("test-cluster")) + .when().get(href1); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testTopologyObject() throws ClassNotFoundException { + LOG_ENTER(); + + String username = "admin"; + String password = "admin-password"; + String serviceUrl = clusterUrl + "/api/v1/topologies"; + String hrefJson = given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .when().get(serviceUrl).thenReturn().getBody().path("topologies.topology[1].href"); + + String timestampJson = given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/json") + .when().get(serviceUrl).andReturn() + .getBody().path("topologies.topology[1].timestamp"); + + given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .body("topology.name", equalTo("test-cluster")) + .body("topology.timestamp", equalTo(Long.parseLong(timestampJson))) + .when() + .get(hrefJson); + + + String hrefXml = given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .when().get(serviceUrl).thenReturn().getBody().path("topologies.topology[1].href"); + + given() + //.log().all() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .when() + .get(hrefXml); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testPositiveAuthorization() throws ClassNotFoundException{ + LOG_ENTER(); + + String adminUser = "admin"; + String adminPass = "admin-password"; + String url = clusterUrl + "/api/v1/topologies"; + + given() + //.log().all() + .auth().preemptive().basic(adminUser, adminPass) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType(ContentType.JSON) + .body("topologies.topology[0].name", not(nullValue())) + .body("topologies.topology[1].name", not(nullValue())) + .body("topologies.topology[0].uri", not(nullValue())) + .body("topologies.topology[1].uri", not(nullValue())) + .body("topologies.topology[0].href", not(nullValue())) + .body("topologies.topology[1].href", not(nullValue())) + .body("topologies.topology[0].timestamp", not(nullValue())) + .body("topologies.topology[1].timestamp", not(nullValue())) + .get(url); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testNegativeAuthorization() throws ClassNotFoundException{ + LOG_ENTER(); + + String guestUser = "guest"; + String guestPass = "guest-password"; + String url = clusterUrl + "/api/v1/topologies"; + + given() + //.log().all() + .auth().basic(guestUser, guestPass) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_FORBIDDEN) + .get(url); + + LOG_EXIT(); + } + + private Topology createTestTopology(){ + Topology topology = new Topology(); + topology.setName("test-topology"); + + try { + topology.setUri(new URI(gatewayUrl + "/" + topology.getName())); + } catch (URISyntaxException ex) { + assertThat(topology.getUri(), not(nullValue())); + } + + Provider identityProvider = new Provider(); + identityProvider.setName("Default"); + identityProvider.setRole("identity-assertion"); + identityProvider.setEnabled(true); + + Provider AuthenicationProvider = new Provider(); + AuthenicationProvider.setName("ShiroProvider"); + AuthenicationProvider.setRole("authentication"); + AuthenicationProvider.setEnabled(true); + + Param ldapMain = new Param(); + ldapMain.setName("main.ldapRealm"); - ldapMain.setValue("KnoxLdapRealm"); ++ ldapMain.setValue("org.apache.knox.gateway.shirorealm.KnoxLdapRealm"); + + Param ldapGroupContextFactory = new Param(); + ldapGroupContextFactory.setName("main.ldapGroupContextFactory"); - ldapGroupContextFactory.setValue("KnoxLdapContextFactory"); ++ ldapGroupContextFactory.setValue("org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory"); + + Param ldapRealmContext = new Param(); + ldapRealmContext.setName("main.ldapRealm.contextFactory"); + ldapRealmContext.setValue("$ldapGroupContextFactory"); + + Param ldapURL = new Param(); + ldapURL.setName("main.ldapRealm.contextFactory.url"); - ldapURL.setValue("ldap://localhost:" + ldapTransport.getAcceptor().getLocalAddress().getPort()); ++ ldapURL.setValue(driver.getLdapUrl()); + + Param ldapUserTemplate = new Param(); + ldapUserTemplate.setName("main.ldapRealm.userDnTemplate"); + ldapUserTemplate.setValue("uid={0},ou=people,dc=hadoop,dc=apache,dc=org"); + + Param authcBasic = new Param(); + authcBasic.setName("urls./**"); + authcBasic.setValue("authcBasic"); + + AuthenicationProvider.addParam(ldapGroupContextFactory); + AuthenicationProvider.addParam(ldapMain); + AuthenicationProvider.addParam(ldapRealmContext); + AuthenicationProvider.addParam(ldapURL); + AuthenicationProvider.addParam(ldapUserTemplate); + AuthenicationProvider.addParam(authcBasic); + + Service testService = new Service(); + testService.setRole("test-service-role"); + + topology.addProvider(AuthenicationProvider); + topology.addProvider(identityProvider); + topology.addService(testService); + topology.setTimestamp(System.nanoTime()); + + return topology; + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testDeployTopology() throws Exception { + LOG_ENTER(); + + Topology testTopology = createTestTopology(); + + String user = "guest"; + String password = "guest-password"; + + String url = gatewayUrl + "/" + testTopology.getName() + "/test-service-path/test-service-resource"; + + GatewayServices srvs = GatewayServer.getGatewayServices(); + + TopologyService ts = srvs.getService(GatewayServices.TOPOLOGY_SERVICE); + try { + ts.stopMonitor(); + + assertThat( testTopology, not( nullValue() ) ); + assertThat( testTopology.getName(), is( "test-topology" ) ); + + given() + //.log().all() + .auth().preemptive().basic( "admin", "admin-password" ).header( "Accept", MediaType.APPLICATION_JSON ).expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ).body( containsString( "ServerVersion" ) ).when().get( gatewayUrl + "/admin/api/v1/version" ); + + given() + //.log().all() + .auth().preemptive().basic( user, password ).expect() + //.log().all() + .statusCode( HttpStatus.SC_NOT_FOUND ).when().get( url ); + + ts.deployTopology( testTopology ); + + given() + //.log().all() + .auth().preemptive().basic( user, password ).expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ).contentType( "text/plain" ).body( is( "test-service-response" ) ).when().get( url ).getBody(); + + ts.deleteTopology( testTopology ); + + given() + //.log().all() + .auth().preemptive().basic( user, password ).expect() + //.log().all() + .statusCode( HttpStatus.SC_NOT_FOUND ).when().get( url ); + } finally { + ts.startMonitor(); + } + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testDeleteTopology() throws ClassNotFoundException { + LOG_ENTER(); + + Topology test = createTestTopology(); + + String username = "admin"; + String password = "admin-password"; + String url = clusterUrl + "/api/v1/topologies/" + test.getName(); + + GatewayServices gs = GatewayServer.getGatewayServices(); + + TopologyService ts = gs.getService(GatewayServices.TOPOLOGY_SERVICE); + + ts.deployTopology(test); + + given() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType(MediaType.APPLICATION_JSON) + .get(url); + + given() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType(MediaType.APPLICATION_JSON) + .delete(url); + + given() + //.log().all() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_NO_CONTENT) + .get(url); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testPutTopology() throws Exception { + LOG_ENTER() ; + + String username = "admin"; + String password = "admin-password"; + String url = clusterUrl + "/api/v1/topologies/test-put"; + + String JsonPut = + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_JSON) + .get(clusterUrl + "/api/v1/topologies/test-cluster") + .getBody().asString(); + + String XML = given() + //.log().all() + .auth().preemptive().basic(username, password) + .contentType(MediaType.APPLICATION_JSON) + .header("Accept", MediaType.APPLICATION_XML) + .body(JsonPut) + .expect() + .statusCode(HttpStatus.SC_OK) + //.log().all() + .put(url).getBody().asString(); + + InputSource source = new InputSource( new StringReader( XML ) ); + Document doc = XmlUtils.readXml( source ); + + assertThat( doc, hasXPath( "/topology/gateway/provider[1]/name", containsString( "WebAppSec" ) ) ); + assertThat( doc, hasXPath( "/topology/gateway/provider[1]/param/name", containsString( "csrf.enabled" ) ) ); + + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(equalTo(XML)) + .get(url) + .getBody().asString(); + + String XmlPut = + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .get(clusterUrl + "/api/v1/topologies/test-cluster") + .getBody().asString(); + + String JSON = given() + //.log().all() + .auth().preemptive().basic(username, password) + .contentType(MediaType.APPLICATION_XML) + .header("Accept", MediaType.APPLICATION_JSON) + .body(XmlPut) + .expect() + .statusCode(HttpStatus.SC_OK) + //.log().all() + .put(url).getBody().asString(); + + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_JSON) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(equalTo(JSON)) + .get(url) + .getBody().asString(); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testXForwardedHeaders() { + LOG_ENTER(); + + String username = "admin"; + String password = "admin-password"; + String url = clusterUrl + "/api/v1/topologies"; + +// X-Forward header values + String port = String.valueOf(777); + String server = "myserver"; + String host = server + ":" + port; + String proto = "protocol"; + String context = "/mycontext"; + String newUrl = proto + "://" + host + context; +// String port = String.valueOf(gateway.getAddresses()[0].getPort()); + +// Case 1: Add in all x-forward headers (host, port, server, context, proto) + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .header("X-Forwarded-Host", host ) + .header("X-Forwarded-Port", port ) + .header("X-Forwarded-Server", server ) + .header("X-Forwarded-Context", context) + .header("X-Forwarded-Proto", proto) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(newUrl)) + .body(containsString("test-cluster")) + .body(containsString("admin")) + .get(url); + + +// Case 2: add in x-forward headers (host, server, proto, context) + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .header("X-Forwarded-Host", host ) + .header("X-Forwarded-Server", server ) + .header("X-Forwarded-Context", context ) + .header("X-Forwarded-Proto", proto ) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(server)) + .body(containsString(context)) + .body(containsString(proto)) + .body(containsString(host)) + .body(containsString("test-cluster")) + .body(containsString("admin")) + .get(url); + +// Case 3: add in x-forward headers (host, proto, port, context) + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .header("X-Forwarded-Host", host ) + .header("X-Forwarded-Port", port ) + .header("X-Forwarded-Context", context ) + .header("X-Forwarded-Proto", proto) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(host)) + .body(containsString(port)) + .body(containsString(context)) + .body(containsString(proto)) + .body(containsString("test-cluster")) + .body(containsString("admin")) + .get(url); + +// Case 4: add in x-forward headers (host, proto, port, context) no port in host. + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .header("X-Forwarded-Host", server) + .header("X-Forwarded-Port", port) + .header("X-Forwarded-Context", context) + .header("X-Forwarded-Proto", proto) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(server)) + .body(containsString(port)) + .body(containsString(context)) + .body(containsString(proto)) + .body(containsString("test-cluster")) + .body(containsString("admin")) + .get(url); + +// Case 5: add in x-forward headers (host, port) + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .header("X-Forwarded-Host", host ) + .header("X-Forwarded-Port", port ) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(host)) + .body(containsString(port)) + .body(containsString("test-cluster")) + .body(containsString("admin")) + .get(url); + +// Case 6: Normal Request + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(url)) + .body(containsString("test-cluster")) + .body(containsString("admin")) + .get(url); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.LONG_TIMEOUT ) + public void testGatewayPathChange() throws Exception { + LOG_ENTER(); + String username = "admin"; + String password = "admin-password"; + String url = clusterUrl + "/api/v1/topologies"; + +// Case 1: Normal Request (No Change in gateway.path). Ensure HTTP OK resp + valid URL. + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(url + "/test-cluster")) + .get(url); + + +// Case 2: Change gateway.path to another String. Ensure HTTP OK resp + valid URL. + try { + gateway.stop(); + + GatewayTestConfig conf = new GatewayTestConfig(); + conf.setGatewayPath("new-gateway-path"); + setupGateway(conf); + + String newUrl = clusterUrl + "/api/v1/topologies"; + + given() + .auth().preemptive().basic(username, password) + .header("Accept", MediaType.APPLICATION_XML) + .expect() + .statusCode(HttpStatus.SC_OK) + .body(containsString(newUrl + "/test-cluster")) + .get(newUrl); + } catch(Exception e){ + fail(e.getMessage()); + } + finally { +// Restart the gateway with old settings. + gateway.stop(); + setupGateway(new GatewayTestConfig()); + } + + LOG_EXIT(); + } + + private static final String CLASS = GatewayAdminTopologyFuncTest.class.getCanonicalName(); + +} http://git-wip-us.apache.org/repos/asf/knox/blob/912c5360/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAppFuncTest.java ---------------------------------------------------------------------- diff --cc gateway-test/src/test/java/org/apache/knox/gateway/GatewayAppFuncTest.java index 4c2bcee,0000000..1a13cf2 mode 100644,000000..100644 --- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAppFuncTest.java +++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAppFuncTest.java @@@ -1,688 -1,0 +1,670 @@@ +/** + * 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; + +import java.io.File; +import java.net.URL; +import java.nio.charset.Charset; - import java.nio.file.FileSystems; - import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.apache.commons.io.FileUtils; +import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.knox.gateway.security.ldap.SimpleLdapDirectoryServer; +import org.apache.knox.gateway.services.DefaultGatewayServices; +import org.apache.knox.gateway.services.GatewayServices; +import org.apache.knox.gateway.services.ServiceLifecycleException; +import org.apache.knox.gateway.services.topology.TopologyService; +import org.apache.hadoop.test.TestUtils; +import org.apache.hadoop.test.mock.MockServer; +import org.apache.http.HttpStatus; +import org.apache.log4j.Appender; +import org.hamcrest.MatcherAssert; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.jayway.restassured.RestAssured.given; +import static org.apache.hadoop.test.TestUtils.LOG_ENTER; +import static org.apache.hadoop.test.TestUtils.LOG_EXIT; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.hasItemInArray; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.assertThat; +import static org.xmlmatchers.transform.XmlConverters.the; +import static org.xmlmatchers.xpath.HasXPath.hasXPath; +import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; + +public class GatewayAppFuncTest { + + private static Logger LOG = LoggerFactory.getLogger( GatewayAppFuncTest.class ); + private static Class DAT = GatewayAppFuncTest.class; + + private static Enumeration<Appender> appenders; + private static GatewayTestConfig config; + private static DefaultGatewayServices services; + private static GatewayServer gateway; + private static int gatewayPort; + private static String gatewayUrl; + private static String clusterUrl; - private static SimpleLdapDirectoryServer ldap; - private static TcpTransport ldapTransport; - private static int ldapPort; + private static Properties params; + private static TopologyService topos; + private static MockServer mockWebHdfs; ++ private static GatewayTestDriver driver = new GatewayTestDriver(); + + @BeforeClass + public static void setupSuite() throws Exception { + LOG_ENTER(); + //appenders = NoOpAppender.setUp(); - setupLdap(); ++ driver.setupLdap(0); + setupGateway(); + LOG_EXIT(); + } + + @AfterClass + public static void cleanupSuite() throws Exception { + LOG_ENTER(); + gateway.stop(); - ldap.stop( true ); ++ driver.cleanup(); + FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) ); + //NoOpAppender.tearDown( appenders ); + LOG_EXIT(); + } + + @After + public void cleanupTest() throws Exception { + FileUtils.cleanDirectory( new File( config.getGatewayTopologyDir() ) ); + FileUtils.cleanDirectory( new File( config.getGatewayDeploymentDir() ) ); + } + - public static void setupLdap() throws Exception { - String basedir = System.getProperty("basedir"); - if (basedir == null) { - basedir = new File(".").getCanonicalPath(); - } - Path path = FileSystems.getDefault().getPath(basedir, "/src/test/resources/users.ldif"); - - ldapTransport = new TcpTransport( 0 ); - ldap = new SimpleLdapDirectoryServer( "dc=hadoop,dc=apache,dc=org", path.toFile(), ldapTransport ); - ldap.start(); - ldapPort = ldapTransport.getAcceptor().getLocalAddress().getPort(); - LOG.info( "LDAP port = " + ldapPort ); - } - + public static void setupGateway() throws Exception { + + File targetDir = new File( System.getProperty( "user.dir" ), "target" ); + File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() ); + gatewayDir.mkdirs(); + + config = new GatewayTestConfig(); + config.setGatewayHomeDir( gatewayDir.getAbsolutePath() ); + + URL svcsFileUrl = TestUtils.getResourceUrl( DAT, "test-svcs/readme.txt" ); + File svcsFile = new File( svcsFileUrl.getFile() ); + File svcsDir = svcsFile.getParentFile(); + config.setGatewayServicesDir( svcsDir.getAbsolutePath() ); + + URL appsFileUrl = TestUtils.getResourceUrl( DAT, "test-apps/readme.txt" ); + File appsFile = new File( appsFileUrl.getFile() ); + File appsDir = appsFile.getParentFile(); + config.setGatewayApplicationsDir( appsDir.getAbsolutePath() ); + + File topoDir = new File( config.getGatewayTopologyDir() ); + topoDir.mkdirs(); + + File deployDir = new File( config.getGatewayDeploymentDir() ); + deployDir.mkdirs(); + + + setupMockServers(); + startGatewayServer(); + } + + public static void setupMockServers() throws Exception { + mockWebHdfs = new MockServer( "WEBHDFS", true ); + } + + public static void startGatewayServer() throws Exception { + services = new DefaultGatewayServices(); + Map<String,String> options = new HashMap<>(); + options.put( "persist-master", "false" ); + options.put( "master", "password" ); + try { + services.init( config, options ); + } catch ( ServiceLifecycleException e ) { + e.printStackTrace(); // I18N not required. + } + topos = services.getService(GatewayServices.TOPOLOGY_SERVICE); + + gateway = GatewayServer.startGateway( config, services ); + MatcherAssert.assertThat( "Failed to start gateway.", gateway, notNullValue() ); + + gatewayPort = gateway.getAddresses()[0].getPort(); + gatewayUrl = "http://localhost:" + gatewayPort + "/" + config.getGatewayPath(); + clusterUrl = gatewayUrl + "/test-topology"; + + LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() ); + + params = new Properties(); - params.put( "LDAP_URL", "ldap://localhost:" + ldapPort ); ++ params.put( "LDAP_URL", driver.getLdapUrl() ); + params.put( "WEBHDFS_URL", "http://localhost:" + mockWebHdfs.getPort() ); + } + + @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testSimpleStaticHelloAppDeployUndeploy() throws Exception { + LOG_ENTER(); + + String topoStr = TestUtils.merge( DAT, "test-static-hello-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + String username = "guest"; + String password = "guest-password"; + String serviceUrl = clusterUrl + "/static-hello-app-path/index.html"; + String body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .contentType( "text/html" ) + .when().get( serviceUrl ).asString(); + assertThat( the(body), hasXPath( "/html/head/title/text()", equalTo("Static Hello Application") ) ); + + serviceUrl = clusterUrl + "/static-hello-app-path/"; + body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .contentType( "text/html" ) + .when().get( serviceUrl ).asString(); + assertThat( the(body), hasXPath( "/html/head/title/text()", equalTo("Static Hello Application") ) ); + + serviceUrl = clusterUrl + "/static-hello-app-path"; + body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .contentType( "text/html" ) + .when().get( serviceUrl ).asString(); + assertThat( the(body), hasXPath( "/html/head/title/text()", equalTo("Static Hello Application") ) ); + + assertThat( "Failed to delete test topology file", FileUtils.deleteQuietly( topoFile ), is(true) ); + topos.reloadTopologies(); + + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( serviceUrl ); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testSimpleDynamicAppDeployUndeploy() throws Exception { + LOG_ENTER(); + + String topoStr = TestUtils.merge( DAT, "test-dynamic-app-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + String username = "guest"; + String password = "guest-password"; + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + assertThat( "Failed to delete test topology file", FileUtils.deleteQuietly( topoFile ), is(true) ); + topos.reloadTopologies(); + + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when() + .get( clusterUrl + "/dynamic-app-path" ); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testNakedAppDeploy() throws Exception { + LOG_ENTER(); + + String topoStr = TestUtils.merge( DAT, "test-naked-app-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + given() + //.log().all() + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( gatewayUrl + "/test-topology/dynamic-app/?null" ) ) + .when().get( gatewayUrl + "/test-topology/dynamic-app" ); + + LOG_EXIT(); + } + + @Test//( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testDefaultAppName() throws Exception { + LOG_ENTER(); + + String topoStr = TestUtils.merge( DAT, "test-default-app-name-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + String username = "guest"; + String password = "guest-password"; + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app/?null" ) ) + .when().get( clusterUrl + "/dynamic-app" ); + + assertThat( "Failed to delete test topology file", FileUtils.deleteQuietly( topoFile ), is(true) ); + topos.reloadTopologies(); + + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when() + .get( clusterUrl + "/dynamic-app" ); + + File deployDir = new File( config.getGatewayDeploymentDir() ); + assertThat( deployDir.listFiles(), is(arrayWithSize(0)) ); + + LOG_EXIT(); + } + + @Test//( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testMultiApps() throws Exception { + LOG_ENTER(); + + String topoStr = TestUtils.merge( DAT, "test-multi-apps-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + String username = "guest"; + String password = "guest-password"; + + String body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .contentType( "text/html" ) + .when().get( clusterUrl + "/static-hello-app-path/index.html" ).asString(); + assertThat( the(body), hasXPath( "/html/head/title/text()", equalTo("Static Hello Application") ) ); + + body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + .contentType( "" ) + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .when().get( clusterUrl + "/static-json-app/one.json" ).asString(); + assertThat( body, sameJSONAs( "{'test-name-one':'test-value-one'}" ) ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + .contentType( "application/xml" ) + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .when().get( clusterUrl + "/test.xml" ).asString(); + assertThat( the(body), hasXPath( "/test" ) ); + + assertThat( FileUtils.deleteQuietly( topoFile ), is(true) ); + topos.reloadTopologies(); + + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/static-hello-app-path/index.html" ); + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/static-json-app/one.json" ); + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/dynamic-app-path" ); + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/test.xml" ); + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testServicesAndApplications() throws Exception { + LOG_ENTER(); + + String topoStr = TestUtils.merge( DAT, "test-svcs-and-apps-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + String username = "guest"; + String password = "guest-password"; + + mockWebHdfs.expect() + .method( "GET" ) + .pathInfo( "/v1/" ) + .queryParam( "op", "GETHOMEDIRECTORY" ) + .queryParam( "user.name", "guest" ) + .respond() + .status( HttpStatus.SC_OK ) + .content( "{\"path\":\"/users/guest\"}", Charset.forName("UTF-8") ) + .contentType( "application/json" ); + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .queryParam( "op", "GETHOMEDIRECTORY" ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .contentType( "application/json" ) + .body( "path", is( "/users/guest") ) + .when().get( clusterUrl + "/webhdfs/v1" ); + assertThat( mockWebHdfs.isEmpty(), is(true) ); + + String body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .contentType( "application/xml" ) + .when().get( clusterUrl + "/static-xml-app/test.xml" ).asString(); + assertThat( the(body), hasXPath( "test" ) ); + + body = given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + .contentType( "" ) + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .when().get( clusterUrl + "/app-two/one.json" ).asString(); + assertThat( body, sameJSONAs( "{'test-name-one':'test-value-one'}" ) ); + + assertThat( FileUtils.deleteQuietly( topoFile ), is(true) ); + topos.reloadTopologies(); + + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/app-one/index.html" ); + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/app-two/one.json" ); + given() + .auth().preemptive().basic( username, password ) + .expect() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .when().get( clusterUrl + "/test.xml" ); + + File deployDir = new File( config.getGatewayDeploymentDir() ); + assertThat( deployDir.listFiles(), is(arrayWithSize(0)) ); + + LOG_EXIT(); + } + + @Test//( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testDeploymentCleanup() throws Exception { + LOG_ENTER(); + + String username = "guest"; + String password = "guest-password"; + + int oldVersionLimit = config.getGatewayDeploymentsBackupVersionLimit(); + + try { + gateway.stop(); + config.setGatewayDeploymentsBackupVersionLimit( 1 ); + startGatewayServer(); + + String topoStr = TestUtils.merge( DAT, "test-dynamic-app-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + topos.reloadTopologies(); + + File deployDir = new File( config.getGatewayDeploymentDir() ); + String[] topoDirs1 = deployDir.list(); + assertThat( topoDirs1, is(arrayWithSize(1)) ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + TestUtils.waitUntilNextSecond(); + FileUtils.touch( topoFile ); + + topos.reloadTopologies(); + String[] topoDirs2 = deployDir.list(); + assertThat( topoDirs2, is(arrayWithSize(2)) ); + assertThat( topoDirs2, hasItemInArray(topoDirs1[0]) ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + TestUtils.waitUntilNextSecond(); + FileUtils.touch( topoFile ); + topos.reloadTopologies(); + + String[] topoDirs3 = deployDir.list(); + assertThat( topoDirs3, is(arrayWithSize(2)) ); + assertThat( topoDirs3, not(hasItemInArray(topoDirs1[0])) ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + } finally { + gateway.stop(); + config.setGatewayDeploymentsBackupAgeLimit( oldVersionLimit ); + startGatewayServer(); + } + + LOG_EXIT(); + } + + @Test( timeout = TestUtils.MEDIUM_TIMEOUT ) + public void testDefaultTopology() throws Exception { + LOG_ENTER(); + + try { + gateway.stop(); + config.setGatewayDeploymentsBackupVersionLimit( 1 ); + startGatewayServer(); + + String topoStr = TestUtils.merge( DAT, "test-dynamic-app-topology.xml", params ); + File topoFile = new File( config.getGatewayTopologyDir(), "test-topology.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + File deployDir = new File( config.getGatewayDeploymentDir() ); + String[] topoDirs = deployDir.list(); + assertThat( topoDirs, is(arrayWithSize(1)) ); + + String username = "guest"; + String password = "guest-password"; + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + topoStr = TestUtils.merge( DAT, "test-dynamic-app-topology.xml", params ); + topoFile = new File( config.getGatewayTopologyDir(), "test-topology-2.xml" ); + FileUtils.writeStringToFile( topoFile, topoStr ); + + topos.reloadTopologies(); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( gatewayUrl + "/test-topology" + "/dynamic-app-path/?null" ) ) + .when().get( gatewayUrl + "/test-topology/dynamic-app-path" ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( gatewayUrl + "/test-topology-2" + "/dynamic-app-path/?null" ) ) + .when().get( gatewayUrl + "/test-topology-2/dynamic-app-path" ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_NOT_FOUND ) + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ); + + gateway.stop(); + config.setDefaultTopologyName( "test-topology" ); + startGatewayServer(); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( gatewayUrl + "/test-topology" + "/dynamic-app-path/?null" ) ) + .when().get( gatewayUrl + "/test-topology/dynamic-app-path" ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .statusCode( HttpStatus.SC_OK ) + .body( is( gatewayUrl + "/test-topology-2" + "/dynamic-app-path/?null" ) ) + .when().get( gatewayUrl + "/test-topology-2/dynamic-app-path" ); + + given() + //.log().all() + .auth().preemptive().basic( username, password ) + .expect() + //.log().all() + .body( is( clusterUrl + "/dynamic-app-path/?null" ) ) + .when().get( clusterUrl + "/dynamic-app-path" ); + + } finally { + gateway.stop(); + config.setDefaultTopologyName( null ); + startGatewayServer(); + } + + LOG_EXIT(); + } + + public static Collection<String> toNames( File[] files ) { + List<String> names = new ArrayList<String>( files.length ); + for( File file : files ) { + names.add( file.getAbsolutePath() ); + } + return names; + + } + +}