http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java
----------------------------------------------------------------------
diff --cc 
gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java
index 4c4d419,0000000..902327c
mode 100644,000000..100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/util/KnoxCLITest.java
@@@ -1,649 -1,0 +1,1032 @@@
 +/**
 + * 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.util;
 +
 +import com.mycila.xmltool.XMLDoc;
 +import com.mycila.xmltool.XMLTag;
 +import org.apache.commons.io.FileUtils;
++import org.apache.knox.conf.Configuration;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.services.GatewayServices;
++import 
org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
++import 
org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 +import org.apache.knox.gateway.services.security.AliasService;
 +import org.apache.knox.gateway.services.security.MasterService;
++import org.apache.knox.test.TestUtils;
 +import org.junit.Before;
 +import org.junit.Test;
 +
 +import java.io.ByteArrayOutputStream;
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.io.PrintStream;
 +import java.net.URL;
 +import java.util.UUID;
 +
 +import static org.hamcrest.CoreMatchers.containsString;
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.CoreMatchers.not;
 +import static org.hamcrest.CoreMatchers.notNullValue;
 +import static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertFalse;
 +import static org.junit.Assert.assertNotNull;
++import static org.junit.Assert.assertNull;
 +import static org.junit.Assert.assertThat;
 +import static org.junit.Assert.assertTrue;
 +
 +/**
 + * @author larry
 + *
 + */
 +public class KnoxCLITest {
 +  private final ByteArrayOutputStream outContent = new 
ByteArrayOutputStream();
 +  private final ByteArrayOutputStream errContent = new 
ByteArrayOutputStream();
 +
 +  @Before
 +  public void setup() throws Exception {
 +    System.setOut(new PrintStream(outContent));
 +    System.setErr(new PrintStream(errContent));
 +  }
 +
 +  @Test
-   public void testSuccessfulAlaisLifecycle() throws Exception {
++  public void testRemoteConfigurationRegistryClientService() throws Exception 
{
++    outContent.reset();
++
++    KnoxCLI cli = new KnoxCLI();
++    Configuration config = new GatewayConfigImpl();
++    // Configure a client for the test local filesystem registry 
implementation
++    config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=/test");
++    cli.setConf(config);
++
++    // This is only to get the gateway services initialized
++    cli.run(new String[]{"version"});
++
++    RemoteConfigurationRegistryClientService service =
++                                   
cli.getGatewayServices().getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE);
++    assertNotNull(service);
++    RemoteConfigurationRegistryClient client = service.get("test_client");
++    assertNotNull(client);
++
++    assertNull(service.get("bogus"));
++  }
++
++  @Test
++  public void testListRemoteConfigurationRegistryClients() throws Exception {
++    outContent.reset();
++
++    KnoxCLI cli = new KnoxCLI();
++    String[] args = { "list-registry-clients", "--master","master" };
++
++    Configuration config = new GatewayConfigImpl();
++    cli.setConf(config);
++
++    // Test with no registry clients configured
++    int rc = cli.run(args);
++    assertEquals(0, rc);
++    assertTrue(outContent.toString(), outContent.toString().isEmpty());
++
++    // Test with a single client configured
++    // Configure a client for the test local filesystem registry 
implementation
++    config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=/test1");
++    cli.setConf(config);
++    outContent.reset();
++    rc = cli.run(args);
++    assertEquals(0, rc);
++    assertTrue(outContent.toString(), 
outContent.toString().contains("test_client"));
++
++    // Configure another client for the test local filesystem registry 
implementation
++    config.set("gateway.remote.config.registry.another_client", 
"type=LocalFileSystem;address=/test2");
++    cli.setConf(config);
++    outContent.reset();
++    rc = cli.run(args);
++    assertEquals(0, rc);
++    assertTrue(outContent.toString(), 
outContent.toString().contains("test_client"));
++    assertTrue(outContent.toString(), 
outContent.toString().contains("another_client"));
++  }
++
++  @Test
++  public void testRemoteConfigurationRegistryGetACLs() throws Exception {
++    outContent.reset();
++
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++
++      final String providerConfigName = "my-provider-config.xml";
++      final String providerConfigContent = "<gateway/>\n";
++      final File testProviderConfig = new File(testRoot, providerConfigName);
++      final String[] uploadArgs = {"upload-provider-config", 
testProviderConfig.getAbsolutePath(),
++                                   "--registry-client", "test_client",
++                                   "--master", "master"};
++      FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
++
++
++      final String[] args = {"get-registry-acl", 
"/knox/config/shared-providers",
++                             "--registry-client", "test_client",
++                             "--master", "master"};
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      int rc = cli.run(uploadArgs);
++      assertEquals(0, rc);
++
++      // Run the test command
++      rc = cli.run(args);
++
++      // Validate the result
++      assertEquals(0, rc);
++      String result = outContent.toString();
++      assertEquals(result, 3, result.split("\n").length);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++
++  @Test
++  public void testRemoteConfigurationRegistryUploadProviderConfig() throws 
Exception {
++    outContent.reset();
++
++    final String providerConfigName = "my-provider-config.xml";
++    final String providerConfigContent = "<gateway/>\n";
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++      final File testProviderConfig = new File(testRoot, providerConfigName);
++
++      final String[] args = {"upload-provider-config", 
testProviderConfig.getAbsolutePath(),
++                             "--registry-client", "test_client",
++                             "--master", "master"};
++
++      FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      // Run the test command
++      int rc = cli.run(args);
++
++      // Validate the result
++      assertEquals(0, rc);
++      File registryFile = new File(testRegistry, 
"knox/config/shared-providers/" + providerConfigName);
++      assertTrue(registryFile.exists());
++      assertEquals(FileUtils.readFileToString(registryFile), 
providerConfigContent);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++
++  @Test
++  public void 
testRemoteConfigurationRegistryUploadProviderConfigWithDestinationOverride() 
throws Exception {
++    outContent.reset();
++
++    final String providerConfigName = "my-provider-config.xml";
++    final String entryName = "my-providers.xml";
++    final String providerConfigContent = "<gateway/>\n";
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++      final File testProviderConfig = new File(testRoot, providerConfigName);
++
++      final String[] args = {"upload-provider-config", 
testProviderConfig.getAbsolutePath(),
++                             "--entry-name", entryName,
++                             "--registry-client", "test_client",
++                             "--master", "master"};
++
++      FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      // Run the test command
++      int rc = cli.run(args);
++
++      // Validate the result
++      assertEquals(0, rc);
++      assertFalse((new File(testRegistry, "knox/config/shared-providers/" + 
providerConfigName)).exists());
++      File registryFile = new File(testRegistry, 
"knox/config/shared-providers/" + entryName);
++      assertTrue(registryFile.exists());
++      assertEquals(FileUtils.readFileToString(registryFile), 
providerConfigContent);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++
++  @Test
++  public void testRemoteConfigurationRegistryUploadDescriptor() throws 
Exception {
++    outContent.reset();
++
++    final String descriptorName = "my-topology.json";
++    final String descriptorContent = testDescriptorContentJSON;
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++      final File testDescriptor = new File(testRoot, descriptorName);
++
++      final String[] args = {"upload-descriptor", 
testDescriptor.getAbsolutePath(),
++                             "--registry-client", "test_client",
++                             "--master", "master"};
++
++      FileUtils.writeStringToFile(testDescriptor, descriptorContent);
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      // Run the test command
++      int rc = cli.run(args);
++
++      // Validate the result
++      assertEquals(0, rc);
++      File registryFile = new File(testRegistry, "knox/config/descriptors/" + 
descriptorName);
++      assertTrue(registryFile.exists());
++      assertEquals(FileUtils.readFileToString(registryFile), 
descriptorContent);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++  @Test
++  public void 
testRemoteConfigurationRegistryUploadDescriptorWithDestinationOverride() throws 
Exception {
++    outContent.reset();
++
++    final String descriptorName = "my-topology.json";
++    final String entryName = "different-topology.json";
++    final String descriptorContent = testDescriptorContentJSON;
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++      final File testDescriptor = new File(testRoot, descriptorName);
++
++      final String[] args = {"upload-descriptor", 
testDescriptor.getAbsolutePath(),
++                             "--entry-name", entryName,
++                             "--registry-client", "test_client",
++                             "--master", "master"};
++
++      FileUtils.writeStringToFile(testDescriptor, descriptorContent);
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      // Run the test command
++      int rc = cli.run(args);
++
++      // Validate the result
++      assertEquals(0, rc);
++      assertFalse((new File(testRegistry, "knox/config/descriptors/" + 
descriptorName)).exists());
++      File registryFile = new File(testRegistry, "knox/config/descriptors/" + 
entryName);
++      assertTrue(registryFile.exists());
++      assertEquals(FileUtils.readFileToString(registryFile), 
descriptorContent);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++  @Test
++  public void testRemoteConfigurationRegistryDeleteProviderConfig() throws 
Exception {
++    outContent.reset();
++
++    // Create a provider config
++    final String providerConfigName = "my-provider-config.xml";
++    final String providerConfigContent = "<gateway/>\n";
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++      final File testProviderConfig = new File(testRoot, providerConfigName);
++
++      final String[] createArgs = {"upload-provider-config", 
testProviderConfig.getAbsolutePath(),
++                                   "--registry-client", "test_client",
++                                   "--master", "master"};
++
++      FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      // Run the test command
++      int rc = cli.run(createArgs);
++
++      // Validate the result
++      assertEquals(0, rc);
++      File registryFile = new File(testRegistry, 
"knox/config/shared-providers/" + providerConfigName);
++      assertTrue(registryFile.exists());
++
++      outContent.reset();
++
++      // Delete the created provider config
++      final String[] deleteArgs = {"delete-provider-config", 
providerConfigName,
++                                   "--registry-client", "test_client",
++                                   "--master", "master"};
++      rc = cli.run(deleteArgs);
++      assertEquals(0, rc);
++      assertFalse(registryFile.exists());
++
++      // Try to delete a provider config that does not exist
++      rc = cli.run(new String[]{"delete-provider-config", 
"imaginary-providers.xml",
++                                "--registry-client", "test_client",
++                                "--master", "master"});
++      assertEquals(0, rc);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++  @Test
++  public void testRemoteConfigurationRegistryDeleteDescriptor() throws 
Exception {
++    outContent.reset();
++
++    final String descriptorName = "my-topology.json";
++    final String descriptorContent = testDescriptorContentJSON;
++
++    final File testRoot = TestUtils.createTempDir(this.getClass().getName());
++    try {
++      final File testRegistry = new File(testRoot, "registryRoot");
++      final File testDescriptor = new File(testRoot, descriptorName);
++
++      final String[] createArgs = {"upload-descriptor", 
testDescriptor.getAbsolutePath(),
++                             "--registry-client", "test_client",
++                             "--master", "master"};
++
++      FileUtils.writeStringToFile(testDescriptor, descriptorContent);
++
++      KnoxCLI cli = new KnoxCLI();
++      Configuration config = new GatewayConfigImpl();
++      // Configure a client for the test local filesystem registry 
implementation
++      config.set("gateway.remote.config.registry.test_client", 
"type=LocalFileSystem;address=" + testRegistry);
++      cli.setConf(config);
++
++      // Run the test command
++      int rc = cli.run(createArgs);
++
++      // Validate the result
++      assertEquals(0, rc);
++      File registryFile = new File(testRegistry, "knox/config/descriptors/" + 
descriptorName);
++      assertTrue(registryFile.exists());
++
++      outContent.reset();
++
++      // Delete the created provider config
++      final String[] deleteArgs = {"delete-descriptor", descriptorName,
++                                   "--registry-client", "test_client",
++                                   "--master", "master"};
++      rc = cli.run(deleteArgs);
++      assertEquals(0, rc);
++      assertFalse(registryFile.exists());
++
++      // Try to delete a descriptor that does not exist
++      rc = cli.run(new String[]{"delete-descriptor", "bogus.json",
++                                "--registry-client", "test_client",
++                                "--master", "master"});
++      assertEquals(0, rc);
++    } finally {
++      FileUtils.forceDelete(testRoot);
++    }
++  }
++
++  @Test
++  public void testSuccessfulAliasLifecycle() throws Exception {
 +    outContent.reset();
 +    String[] args1 = {"create-alias", "alias1", "--value", "testvalue1", 
"--master", "master"};
 +    int rc = 0;
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(new GatewayConfigImpl());
 +    rc = cli.run(args1);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("alias1 
has been successfully " +
 +        "created."));
 +
 +    outContent.reset();
 +    String[] args2 = {"list-alias", "--master", 
 +        "master"};
 +    rc = cli.run(args2);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("alias1"));
 +
 +    outContent.reset();
 +    String[] args4 = {"delete-alias", "alias1", "--master", 
 +      "master"};
 +    rc = cli.run(args4);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("alias1 
has been successfully " +
 +        "deleted."));
 +
 +    outContent.reset();
 +    rc = cli.run(args2);
 +    assertEquals(0, rc);
 +    assertFalse(outContent.toString(), 
outContent.toString().contains("alias1"));
 +  }
 +  
 +  @Test
 +  public void testListAndDeleteOfAliasForInvalidClusterName() throws 
Exception {
 +    outContent.reset();
 +    String[] args1 =
 +        { "create-alias", "alias1", "--cluster", "cluster1", "--value", 
"testvalue1", "--master",
 +            "master" };
 +    int rc = 0;
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(new GatewayConfigImpl());
 +    rc = cli.run(args1);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains(
 +      "alias1 has been successfully " + "created."));
 +
 +    outContent.reset();
 +    String[] args2 = { "list-alias", "--cluster", "Invalidcluster1", 
"--master", "master" };
 +    rc = cli.run(args2);
 +    assertEquals(0, rc);
 +    System.out.println(outContent.toString());
 +    assertTrue(outContent.toString(),
 +      outContent.toString().contains("Invalid cluster name provided: 
Invalidcluster1"));
 +
 +    outContent.reset();
 +    String[] args4 =
 +        { "delete-alias", "alias1", "--cluster", "Invalidcluster1", 
"--master", "master" };
 +    rc = cli.run(args4);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(),
 +      outContent.toString().contains("Invalid cluster name provided: 
Invalidcluster1"));
 +
 +  }
 +
 +  @Test
 +  public void testDeleteOfNonExistAliasFromUserDefinedCluster() throws 
Exception {
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(new GatewayConfigImpl());
 +    try {
 +      int rc = 0;
 +      outContent.reset();
 +      String[] args1 =
 +          { "create-alias", "alias1", "--cluster", "cluster1", "--value", 
"testvalue1", "--master",
 +              "master" };
 +      cli.run(args1);
 +
 +      // Delete invalid alias from the cluster
 +      outContent.reset();
 +      String[] args2 = { "delete-alias", "alias2", "--cluster", "cluster1", 
"--master", "master" };
 +      rc = cli.run(args2);
 +      assertEquals(0, rc);
 +      assertTrue(outContent.toString().contains("No such alias exists in the 
cluster."));
 +    } finally {
 +      outContent.reset();
 +      String[] args1 = { "delete-alias", "alias1", "--cluster", "cluster1", 
"--master", "master" };
 +      cli.run(args1);
 +    }
 +  }
 +
 +  @Test
 +  public void testDeleteOfNonExistAliasFromDefaultCluster() throws Exception {
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(new GatewayConfigImpl());
 +    try {
 +      int rc = 0;
 +      outContent.reset();
 +      String[] args1 = { "create-alias", "alias1", "--value", "testvalue1", 
"--master", "master" };
 +      cli.run(args1);
 +
 +      // Delete invalid alias from the cluster
 +      outContent.reset();
 +      String[] args2 = { "delete-alias", "alias2", "--master", "master" };
 +      rc = cli.run(args2);
 +      assertEquals(0, rc);
 +      assertTrue(outContent.toString().contains("No such alias exists in the 
cluster."));
 +    } finally {
 +      outContent.reset();
 +      String[] args1 = { "delete-alias", "alias1", "--master", "master" };
 +      cli.run(args1);
 +    }
 +  }
 +
 +  @Test
 +  public void testForInvalidArgument() throws Exception {
 +    outContent.reset();
 +    String[] args1 = { "--value", "testvalue1", "--master", "master" };
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(new GatewayConfigImpl());
 +    int rc = cli.run(args1);
 +    assertEquals(-2, rc);
 +    assertTrue(outContent.toString().contains("ERROR: Invalid Command"));
 +  }
 +
 +  @Test
 +  public void testListAndDeleteOfAliasForValidClusterName() throws Exception {
 +    outContent.reset();
 +    String[] args1 =
 +        { "create-alias", "alias1", "--cluster", "cluster1", "--value", 
"testvalue1", "--master",
 +            "master" };
 +    int rc = 0;
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(new GatewayConfigImpl());
 +    rc = cli.run(args1);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains(
 +      "alias1 has been successfully " + "created."));
 +
 +    outContent.reset();
 +    String[] args2 = { "list-alias", "--cluster", "cluster1", "--master", 
"master" };
 +    rc = cli.run(args2);
 +    assertEquals(0, rc);
 +    System.out.println(outContent.toString());
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("alias1"));
 +
 +    outContent.reset();
 +    String[] args4 =
 +        { "delete-alias", "alias1", "--cluster", "cluster1", "--master", 
"master" };
 +    rc = cli.run(args4);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains(
 +      "alias1 has been successfully " + "deleted."));
 +
 +    outContent.reset();
 +    rc = cli.run(args2);
 +    assertEquals(0, rc);
 +    assertFalse(outContent.toString(), 
outContent.toString().contains("alias1"));
 +
 +  }
 +
 +  @Test
 +  public void testGatewayAndClusterStores() throws Exception {
 +    GatewayConfigImpl config = new GatewayConfigImpl();
 +    FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) );
 +
 +    outContent.reset();
 +    String[] gwCreateArgs = {"create-alias", "alias1", "--value", 
"testvalue1", "--master", "master"};
 +    int rc = 0;
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +    rc = cli.run(gwCreateArgs);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("alias1 
has been successfully " +
 +        "created."));
 +
 +    AliasService as = 
cli.getGatewayServices().getService(GatewayServices.ALIAS_SERVICE);
 +
 +    outContent.reset();
 +    String[] clusterCreateArgs = {"create-alias", "alias2", "--value", 
"testvalue1", "--cluster", "test", 
 +        "--master", "master"};
 +    cli = new KnoxCLI();
 +    cli.setConf( config );
 +    rc = cli.run(clusterCreateArgs);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("alias2 
has been successfully " +
 +        "created."));
 +
 +    outContent.reset();
 +    String[] args2 = {"list-alias", "--master", "master"};
 +    cli = new KnoxCLI();
 +    rc = cli.run(args2);
 +    assertEquals(0, rc);
 +    assertFalse(outContent.toString(), 
outContent.toString().contains("alias2"));
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("alias1"));
 +
 +    char[] passwordChars = as.getPasswordFromAliasForCluster("test", 
"alias2");
 +    assertNotNull(passwordChars);
 +    assertTrue(new String(passwordChars), "testvalue1".equals(new 
String(passwordChars)));
 +
 +    outContent.reset();
 +    String[] args1 = {"list-alias", "--cluster", "test", "--master", 
"master"};
 +    cli = new KnoxCLI();
 +    rc = cli.run(args1);
 +    assertEquals(0, rc);
 +    assertFalse(outContent.toString(), 
outContent.toString().contains("alias1"));
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("alias2"));
 +
 +    outContent.reset();
 +    String[] args4 = {"delete-alias", "alias1", "--master", "master"};
 +    cli = new KnoxCLI();
 +    rc = cli.run(args4);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("alias1 
has been successfully " +
 +        "deleted."));
 +    
 +    outContent.reset();
 +    String[] args5 = {"delete-alias", "alias2", "--cluster", "test", 
"--master", "master"};
 +    cli = new KnoxCLI();
 +    rc = cli.run(args5);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("alias2 
has been successfully " +
 +        "deleted."));
 +  }
 +
 +  private void createTestMaster() throws Exception {
 +    outContent.reset();
 +    String[] args = new String[]{ "create-master", "--master", "master", 
"--force" };
 +    KnoxCLI cli = new KnoxCLI();
 +    int rc = cli.run(args);
 +    assertThat( rc, is( 0 ) );
 +    MasterService ms = cli.getGatewayServices().getService("MasterService");
 +    String master = String.copyValueOf( ms.getMasterSecret() );
 +    assertThat( master, is( "master" ) );
 +    assertThat( outContent.toString(), containsString( "Master secret has 
been persisted to disk." ) );
 +  }
 +
 +  @Test
 +  public void testCreateSelfSignedCert() throws Exception {
 +    GatewayConfigImpl config = new GatewayConfigImpl();
 +    FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) );
 +    createTestMaster();
 +    outContent.reset();
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +    String[] gwCreateArgs = {"create-cert", "--hostname", "hostname1", 
"--master", "master"};
 +    int rc = 0;
 +    rc = cli.run(gwCreateArgs);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("gateway-identity has been successfully " +
 +        "created."));
 +  }
 +
 +  @Test
 +  public void testExportCert() throws Exception {
 +    GatewayConfigImpl config = new GatewayConfigImpl();
 +    FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) );
 +    createTestMaster();
 +    outContent.reset();
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +    String[] gwCreateArgs = {"create-cert", "--hostname", "hostname1", 
"--master", "master"};
 +    int rc = 0;
 +    rc = cli.run(gwCreateArgs);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("gateway-identity has been successfully " +
 +        "created."));
 +
 +    outContent.reset();
 +    String[] gwCreateArgs2 = {"export-cert", "--type", "PEM"};
 +    rc = 0;
 +    rc = cli.run(gwCreateArgs2);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("Certificate gateway-identity has been 
successfully exported to"));
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("gateway-identity.pem"));
 +
 +    outContent.reset();
 +    String[] gwCreateArgs2_5 = {"export-cert"};
 +    rc = 0;
 +    rc = cli.run(gwCreateArgs2_5);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("Certificate gateway-identity has been 
successfully exported to"));
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("gateway-identity.pem"));
 +
 +    outContent.reset();
 +    String[] gwCreateArgs3 = {"export-cert", "--type", "JKS"};
 +    rc = 0;
 +    rc = cli.run(gwCreateArgs3);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("Certificate gateway-identity has been 
successfully exported to"));
 +    assertTrue(outContent.toString(), 
outContent.toString().contains("gateway-client-trust.jks"));
 +
 +    outContent.reset();
 +    String[] gwCreateArgs4 = {"export-cert", "--type", "invalid"};
 +    rc = 0;
 +    rc = cli.run(gwCreateArgs4);
 +    assertEquals(0, rc);
 +    assertTrue(outContent.toString(), outContent.toString().contains("Invalid 
type for export file provided."));
 +  }
 +
 +  @Test
 +  public void testCreateMaster() throws Exception {
 +    GatewayConfigImpl config = new GatewayConfigImpl();
 +    FileUtils.deleteQuietly( new File( config.getGatewaySecurityDir() ) );
 +    outContent.reset();
 +    String[] args = {"create-master", "--master", "master"};
 +    int rc = 0;
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +    rc = cli.run(args);
 +    assertEquals(0, rc);
 +    MasterService ms = cli.getGatewayServices().getService("MasterService");
 +    // assertTrue(ms.getClass().getName(), 
ms.getClass().getName().equals("kjdfhgjkhfdgjkh"));
 +    assertTrue( new String( ms.getMasterSecret() ), "master".equals( new 
String( ms.getMasterSecret() ) ) );
 +    assertTrue(outContent.toString(), outContent.toString().contains("Master 
secret has been persisted to disk."));
 +  }
 +
 +  @Test
 +  public void testCreateMasterGenerate() throws Exception {
 +    String[] args = {"create-master", "--generate" };
 +    int rc = 0;
 +    GatewayConfigImpl config = new GatewayConfigImpl();
 +    File masterFile = new File( config.getGatewaySecurityDir(), "master" );
 +
 +    // Need to delete the master file so that the change isn't ignored.
 +    if( masterFile.exists() ) {
 +      assertThat( "Failed to delete existing master file.", 
masterFile.delete(), is( true ) );
 +    }
 +    outContent.reset();
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(config);
 +    rc = cli.run(args);
 +    assertThat( rc, is( 0 ) );
 +    MasterService ms = cli.getGatewayServices().getService("MasterService");
 +    String master = String.copyValueOf( ms.getMasterSecret() );
 +    assertThat( master.length(), is( 36 ) );
 +    assertThat( master.indexOf( '-' ), is( 8 ) );
 +    assertThat( master.indexOf( '-', 9 ), is( 13 ) );
 +    assertThat( master.indexOf( '-', 14 ), is( 18 ) );
 +    assertThat( master.indexOf( '-', 19 ), is( 23 ) );
 +    assertThat( UUID.fromString( master ), notNullValue() );
 +    assertThat( outContent.toString(), containsString( "Master secret has 
been persisted to disk." ) );
 +
 +    // Need to delete the master file so that the change isn't ignored.
 +    if( masterFile.exists() ) {
 +      assertThat( "Failed to delete existing master file.", 
masterFile.delete(), is( true ) );
 +    }
 +    outContent.reset();
 +    cli = new KnoxCLI();
 +    rc = cli.run(args);
 +    ms = cli.getGatewayServices().getService("MasterService");
 +    String master2 = String.copyValueOf( ms.getMasterSecret() );
 +    assertThat( master2.length(), is( 36 ) );
 +    assertThat( UUID.fromString( master2 ), notNullValue() );
 +    assertThat( master2, not( is( master ) ) );
 +    assertThat( rc, is( 0 ) );
 +    assertThat(outContent.toString(), containsString("Master secret has been 
persisted to disk."));
 +  }
 +
 +  @Test
 +  public void testCreateMasterForce() throws Exception {
 +    GatewayConfigImpl config = new GatewayConfigImpl();
 +    File masterFile = new File( config.getGatewaySecurityDir(), "master" );
 +
 +    // Need to delete the master file so that the change isn't ignored.
 +    if( masterFile.exists() ) {
 +      assertThat( "Failed to delete existing master file.", 
masterFile.delete(), is( true ) );
 +    }
 +
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf(config);
 +    MasterService ms;
 +    int rc = 0;
 +    outContent.reset();
 +
 +    String[] args = { "create-master", "--master", "test-master-1" };
 +
 +    rc = cli.run(args);
 +    assertThat( rc, is( 0 ) );
 +    ms = cli.getGatewayServices().getService("MasterService");
 +    String master = String.copyValueOf( ms.getMasterSecret() );
 +    assertThat( master, is( "test-master-1" ) );
 +    assertThat( outContent.toString(), containsString( "Master secret has 
been persisted to disk." ) );
 +
 +    outContent.reset();
 +    rc = cli.run(args);
 +    assertThat( rc, is(0 ) );
 +    assertThat( outContent.toString(), containsString( "Master secret is 
already present on disk." ) );
 +
 +    outContent.reset();
 +    args = new String[]{ "create-master", "--master", "test-master-2", 
"--force" };
 +    rc = cli.run(args);
 +    assertThat( rc, is( 0 ) );
 +    ms = cli.getGatewayServices().getService("MasterService");
 +    master = String.copyValueOf( ms.getMasterSecret() );
 +    assertThat( master, is( "test-master-2" ) );
 +    assertThat( outContent.toString(), containsString( "Master secret has 
been persisted to disk." ) );
 +  }
 +
 +  @Test
 +  public void testListTopology() throws Exception {
 +
 +    GatewayConfigMock config = new GatewayConfigMock();
 +    URL topoURL = 
ClassLoader.getSystemResource("conf-demo/conf/topologies/admin.xml");
 +    config.setConfDir( new 
File(topoURL.getFile()).getParentFile().getParent() );
 +    String args[] = {"list-topologies", "--master", "knox"};
 +
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +
 +    cli.run( args );
 +    assertThat(outContent.toString(), containsString("sandbox"));
 +    assertThat(outContent.toString(), containsString("admin"));
 +  }
 +
 +  private class GatewayConfigMock extends GatewayConfigImpl{
 +    private String confDir;
 +    public void setConfDir(String location) {
 +      confDir = location;
 +    }
 +
 +    @Override
 +    public String getGatewayConfDir(){
 +      return confDir;
 +    }
 +  }
 +
 +  private static XMLTag createBadTopology() {
 +    XMLTag xml = XMLDoc.newDocument(true)
 +        .addRoot( "topology" )
 +        .addTag( "gateway" )
 +
 +        .addTag( "provider" )
 +        .addTag( "role" ).addText( "authentication" )
 +        .addTag( "name" ).addText( "ShiroProvider" )
 +        .addTag( "enabled" ).addText( "123" )
 +        .addTag( "param" )
 +        .addTag( "name" ).addText( "" )
 +        .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:8443"; ).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( "vvv" )
 +        .addTag( "name" ).addText( "Default" ).gotoParent()
 +        .addTag( "provider" )
 +        .gotoRoot()
 +        .addTag( "service" )
 +        .addTag( "role" ).addText( "test-service-role" )
 +        .gotoRoot();
 +    return xml;
 +  }
 +
 +  private static XMLTag createGoodTopology() {
 +    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( 
"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:8443";).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( "test-service-role" )
 +        .gotoRoot();
 +    return xml;
 +  }
 +
 +  private File writeTestTopology( String name, XMLTag xml ) throws 
IOException {
 +    // Create the test topology.
 +
 +    GatewayConfigMock config = new GatewayConfigMock();
 +    URL topoURL = 
ClassLoader.getSystemResource("conf-demo/conf/topologies/admin.xml");
 +    config.setConfDir( new 
File(topoURL.getFile()).getParentFile().getParent() );
 +
 +    File tempFile = new File( config.getGatewayTopologyDir(), name + ".xml." 
+ UUID.randomUUID() );
 +    FileOutputStream stream = new FileOutputStream( tempFile );
 +    xml.toStream( stream );
 +    stream.close();
 +    File descriptor = new File( config.getGatewayTopologyDir(), name + ".xml" 
);
 +    tempFile.renameTo( descriptor );
 +    return descriptor;
 +  }
 +
 +  @Test
 +  public void testValidateTopology() throws Exception {
 +
 +    GatewayConfigMock config = new GatewayConfigMock();
 +    URL topoURL = 
ClassLoader.getSystemResource("conf-demo/conf/topologies/admin.xml");
 +    config.setConfDir( new 
File(topoURL.getFile()).getParentFile().getParent() );
 +    String args[] = {"validate-topology", "--master", "knox", "--cluster", 
"sandbox"};
 +
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +    cli.run( args );
 +
 +    assertThat(outContent.toString(), 
containsString(config.getGatewayTopologyDir()));
 +    assertThat(outContent.toString(), containsString("sandbox"));
 +    assertThat(outContent.toString(), containsString("success"));
 +    outContent.reset();
 +
 +
 +    String args2[] = {"validate-topology", "--master", "knox", "--cluster", 
"NotATopology"};
 +    cli.run(args2);
 +
 +    assertThat(outContent.toString(), containsString("NotATopology"));
 +    assertThat(outContent.toString(), containsString("does not exist"));
 +    outContent.reset();
 +
 +    String args3[] = {"validate-topology", "--master", "knox", "--path", 
config.getGatewayTopologyDir() + "/admin.xml"};
 +    cli.run(args3);
 +
 +    assertThat(outContent.toString(), containsString("admin"));
 +    assertThat(outContent.toString(), containsString("success"));
 +    outContent.reset();
 +
 +    String args4[] = {"validate-topology", "--master", "knox", "--path", 
"not/a/path"};
 +    cli.run(args4);
 +    assertThat(outContent.toString(), containsString("does not exist"));
 +    assertThat(outContent.toString(), containsString("not/a/path"));
 +  }
 +
 +  @Test
 +  public void testValidateTopologyOutput() throws Exception {
 +
 +    File bad = writeTestTopology( "test-cluster-bad", createBadTopology() );
 +    File good = writeTestTopology( "test-cluster-good", createGoodTopology() 
);
 +
 +    GatewayConfigMock config = new GatewayConfigMock();
 +    URL topoURL = 
ClassLoader.getSystemResource("conf-demo/conf/topologies/admin.xml");
 +    config.setConfDir( new 
File(topoURL.getFile()).getParentFile().getParent() );
 +    String args[] = {"validate-topology", "--master", "knox", "--cluster", 
"test-cluster-bad"};
 +
 +    KnoxCLI cli = new KnoxCLI();
 +    cli.setConf( config );
 +    cli.run( args );
 +
 +    assertThat(outContent.toString(), 
containsString(config.getGatewayTopologyDir()));
 +    assertThat(outContent.toString(), containsString("test-cluster-bad"));
 +    assertThat(outContent.toString(), containsString("unsuccessful"));
 +    assertThat(outContent.toString(), containsString("Invalid content"));
 +    assertThat(outContent.toString(), containsString("Line"));
 +
 +
 +    outContent.reset();
 +
 +    String args2[] = {"validate-topology", "--master", "knox", "--cluster", 
"test-cluster-good"};
 +
 +    cli.run(args2);
 +
 +    assertThat(outContent.toString(), 
containsString(config.getGatewayTopologyDir()));
 +    assertThat(outContent.toString(), containsString("success"));
 +    assertThat(outContent.toString(), containsString("test-cluster-good"));
 +
 +
 +  }
 +
++  private static final String testDescriptorContentJSON = "{\n" +
++                                                          "  
\"discovery-address\":\"http://localhost:8080\",\n"; +
++                                                          "  
\"discovery-user\":\"maria_dev\",\n" +
++                                                          "  
\"discovery-pwd-alias\":\"sandbox.discovery.password\",\n" +
++                                                          "  
\"provider-config-ref\":\"my-provider-config\",\n" +
++                                                          "  
\"cluster\":\"Sandbox\",\n" +
++                                                          "  
\"services\":[\n" +
++                                                          "    
{\"name\":\"NAMENODE\"},\n" +
++                                                          "    
{\"name\":\"JOBTRACKER\"},\n" +
++                                                          "    
{\"name\":\"WEBHDFS\"},\n" +
++                                                          "    
{\"name\":\"WEBHCAT\"},\n" +
++                                                          "    
{\"name\":\"OOZIE\"},\n" +
++                                                          "    
{\"name\":\"WEBHBASE\"},\n" +
++                                                          "    
{\"name\":\"HIVE\"},\n" +
++                                                          "    
{\"name\":\"RESOURCEMANAGER\"}\n" +
++                                                          "  ]\n" +
++                                                          "}";
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
----------------------------------------------------------------------
diff --cc 
gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
index 3aceadd,0000000..2ca5ede
mode 100644,000000..100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/BadUrlTest.java
@@@ -1,309 -1,0 +1,320 @@@
 +/**
 + * 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.websockets;
 +
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.net.URI;
 +import java.net.URL;
 +import java.util.ArrayList;
++import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.concurrent.TimeUnit;
 +
 +import javax.websocket.CloseReason;
 +import javax.websocket.ContainerProvider;
 +import javax.websocket.WebSocketContainer;
 +
 +import org.apache.commons.io.FileUtils;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentFactory;
 +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.TopologyEvent;
 +import org.apache.knox.gateway.topology.TopologyListener;
 +import org.apache.knox.test.TestUtils;
 +import org.easymock.EasyMock;
 +import org.eclipse.jetty.server.Server;
 +import org.eclipse.jetty.server.ServerConnector;
 +import org.eclipse.jetty.server.handler.ContextHandler;
 +import org.eclipse.jetty.server.handler.HandlerCollection;
 +import org.hamcrest.CoreMatchers;
 +import org.junit.AfterClass;
 +import org.junit.Assert;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +
 +import com.mycila.xmltool.XMLDoc;
 +import com.mycila.xmltool.XMLTag;
 +
 +/**
 + * Test for bad URLs.
 + * <p>
 + * This test will set up a bad URL through the topology, so this test case 
will
 + * attempt to test the bad url case and also the plumbing around it.
 + * @since 0.10
 + */
 +public class BadUrlTest {
 +
 +  /**
 +   * Non-existant backend websocket server
 +   */
 +  private static String BACKEND = "http://localhost:9999";;
 +
 +  /**
 +   * Mock Gateway server
 +   */
 +  private static Server gatewayServer;
 +
 +  /**
 +   * Mock gateway config
 +   */
 +  private static GatewayConfig gatewayConfig;
 +
 +  private static GatewayServices services;
 +
 +  /**
 +   * URI for gateway server
 +   */
 +  private static URI serverUri;
 +
 +  private static File topoDir;
 +
 +  public BadUrlTest() {
 +    super();
 +  }
 +
 +  @BeforeClass
 +  public static void startServers() throws Exception {
 +
 +    startGatewayServer();
 +
 +  }
 +
 +  @AfterClass
 +  public static void stopServers() {
 +    try {
 +      gatewayServer.stop();
 +    } catch (final Exception e) {
 +      e.printStackTrace(System.err);
 +    }
 +
 +    /* Cleanup the created files */
 +    FileUtils.deleteQuietly(topoDir);
 +
 +  }
 +
 +  /**
 +   * Test websocket proxying through gateway.
 +   *
 +   * @throws Exception
 +   */
 +
 +  @Test
 +  public void testBadUrl() throws Exception {
 +    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
 +
 +    WebsocketClient client = new WebsocketClient();
 +
 +    container.connectToServer(client,
 +        new URI(serverUri.toString() + "gateway/websocket/ws"));
 +
 +    client.awaitClose(CloseReason.CloseCodes.UNEXPECTED_CONDITION.getCode(),
 +        1000, TimeUnit.MILLISECONDS);
 +
 +    Assert.assertThat(client.close.getCloseCode().getCode(),
 +        
CoreMatchers.is(CloseReason.CloseCodes.UNEXPECTED_CONDITION.getCode()));
 +
 +  }
 +
 +
 +  /**
 +   * Start Gateway Server.
 +   *
 +   * @throws Exception
 +   */
 +  private static void startGatewayServer() throws Exception {
 +    gatewayServer = new Server();
 +    final ServerConnector connector = new ServerConnector(gatewayServer);
 +    gatewayServer.addConnector(connector);
 +
 +    /* workaround so we can add our handler later at runtime */
 +    HandlerCollection handlers = new HandlerCollection(true);
 +
 +    /* add some initial handlers */
 +    ContextHandler context = new ContextHandler();
 +    context.setContextPath("/");
 +    handlers.addHandler(context);
 +
 +    gatewayServer.setHandler(handlers);
 +
 +    // Start Server
 +    gatewayServer.start();
 +
 +    String host = connector.getHost();
 +    if (host == null) {
 +      host = "localhost";
 +    }
 +    int port = connector.getLocalPort();
 +    serverUri = new URI(String.format("ws://%s:%d/", host, port));
 +
 +    /* Setup websocket handler */
 +    setupGatewayConfig(BACKEND);
 +
 +    final GatewayWebsocketHandler gatewayWebsocketHandler = new 
GatewayWebsocketHandler(
 +        gatewayConfig, services);
 +    handlers.addHandler(gatewayWebsocketHandler);
 +    gatewayWebsocketHandler.start();
 +  }
 +
 +  /**
 +   * Initialize the configs and components required for this test.
 +   *
 +   * @param backend
 +   * @throws IOException
 +   */
 +  private static void setupGatewayConfig(final String backend)
 +      throws IOException {
 +    services = new DefaultGatewayServices();
 +
 +    topoDir = createDir();
 +    URL serviceUrl = ClassLoader.getSystemResource("websocket-services");
 +
 +    final File descriptor = new File(topoDir, "websocket.xml");
 +    final FileOutputStream stream = new FileOutputStream(descriptor);
 +    createKnoxTopology(backend).toStream(stream);
 +    stream.close();
 +
 +    final TestTopologyListener topoListener = new TestTopologyListener();
 +
 +    final Map<String, String> options = new HashMap<>();
 +    options.put("persist-master", "false");
 +    options.put("master", "password");
 +
 +    gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class);
 +    EasyMock.expect(gatewayConfig.getGatewayTopologyDir())
 +        .andReturn(topoDir.toString()).anyTimes();
 +
++    EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir())
++            .andReturn(topoDir.getAbsolutePath() + 
"/shared-providers").anyTimes();
++
++    EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir())
++            .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes();
++
 +    EasyMock.expect(gatewayConfig.getGatewayServicesDir())
 +        .andReturn(serviceUrl.getFile()).anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048")
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
 +        .andReturn(topoDir.toString()).anyTimes();
 +
 +    /* Websocket configs */
 +    EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageSize())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageSize())
 +        
.andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageBufferSize())
 +        .andReturn(
 +            GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageBufferSize())
 +        .andReturn(
 +            
GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketInputBufferSize())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_INPUT_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketAsyncWriteTimeout())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout())
 +        
.andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes();
 +
++    EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames())
++            .andReturn(Collections.emptyList())
++            .anyTimes();
++
 +    EasyMock.replay(gatewayConfig);
 +
 +    try {
 +      services.init(gatewayConfig, options);
 +    } catch (ServiceLifecycleException e) {
 +      e.printStackTrace();
 +    }
 +
 +    DeploymentFactory.setGatewayServices(services);
 +    final TopologyService monitor = services
 +        .getService(GatewayServices.TOPOLOGY_SERVICE);
 +    monitor.addTopologyChangeListener(topoListener);
 +    monitor.reloadTopologies();
 +
 +  }
 +
 +  private static File createDir() throws IOException {
 +    return TestUtils
 +        .createTempDir(WebsocketEchoTest.class.getSimpleName() + "-");
 +  }
 +
 +  /**
 +   * Intentionally add bad URL
 +   *
 +   * @param backend
 +   * @return
 +   */
 +  private static XMLTag createKnoxTopology(final String backend) {
 +    XMLTag xml = 
XMLDoc.newDocument(true).addRoot("topology").addTag("service")
 +        .addTag("role").addText("WEBSOCKET").addTag("url").addText(backend)
 +        .gotoParent().gotoRoot();
 +    // System.out.println( "GATEWAY=" + xml.toString() );
 +    return xml;
 +  }
 +
 +  private static class TestTopologyListener implements TopologyListener {
 +
 +    public ArrayList<List<TopologyEvent>> events = new 
ArrayList<List<TopologyEvent>>();
 +
 +    @Override
 +    public void handleTopologyEvent(List<TopologyEvent> events) {
 +      this.events.add(events);
 +
 +      synchronized (this) {
 +        for (TopologyEvent event : events) {
 +          if (!event.getType().equals(TopologyEvent.Type.DELETED)) {
 +
 +            /* for this test we only care about this part */
 +            DeploymentFactory.createDeployment(gatewayConfig,
 +                event.getTopology());
 +
 +          }
 +        }
 +
 +      }
 +
 +    }
 +
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
----------------------------------------------------------------------
diff --cc 
gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
index 268e14b,0000000..64ad87c
mode 100644,000000..100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java
@@@ -1,388 -1,0 +1,399 @@@
 +/**
 + * 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.websockets;
 +
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.MatcherAssert.assertThat;
 +
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.net.URI;
 +import java.net.URL;
 +import java.util.ArrayList;
++import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.concurrent.TimeUnit;
 +
 +import javax.websocket.ContainerProvider;
 +import javax.websocket.Session;
 +import javax.websocket.WebSocketContainer;
 +
 +import org.apache.commons.io.FileUtils;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentFactory;
 +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.TopologyEvent;
 +import org.apache.knox.gateway.topology.TopologyListener;
 +import org.apache.knox.test.TestUtils;
 +import org.easymock.EasyMock;
 +import org.eclipse.jetty.server.Server;
 +import org.eclipse.jetty.server.ServerConnector;
 +import org.eclipse.jetty.server.handler.ContextHandler;
 +import org.eclipse.jetty.server.handler.HandlerCollection;
 +import org.junit.AfterClass;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +
 +import com.mycila.xmltool.XMLDoc;
 +import com.mycila.xmltool.XMLTag;
 +
 +/**
 + * A basic test that attempts to proxy websocket connections through Knox
 + * gateway.
 + * <p>
 + * The way the test is set up is as follows: <br/>
 + * <ul>
 + * <li>A Mock Websocket server is setup which simply echos the responses sent 
by
 + * client.
 + * <li>Knox Gateway is set up with websocket handler
 + * {@link GatewayWebsocketHandler} that can proxy the requests.
 + * <li>Appropriate Topology and service definition files are set up with the
 + * address of the Websocket server.
 + * <li>A mock client is setup to connect to gateway.
 + * </ul>
 + * 
 + * The test is to confirm whether the message is sent all the way to the 
backend
 + * Websocket server through Knox and back.
 + * 
 + * 
 + * @since 0.10
 + */
 +public class WebsocketEchoTest {
 +
 +  /**
 +   * Simulate backend websocket
 +   */
 +  private static Server backendServer;
 +  /**
 +   * URI for backend websocket server
 +   */
 +  private static URI backendServerUri;
 +
 +  /**
 +   * Mock Gateway server
 +   */
 +  private static Server gatewayServer;
 +
 +  /**
 +   * Mock gateway config
 +   */
 +  private static GatewayConfig gatewayConfig;
 +
 +  private static GatewayServices services;
 +
 +  /**
 +   * URI for gateway server
 +   */
 +  private static URI serverUri;
 +
 +  private static File topoDir;
 +
 +  public WebsocketEchoTest() {
 +    super();
 +  }
 +
 +  @BeforeClass
 +  public static void startServers() throws Exception {
 +
 +    startWebsocketServer();
 +    startGatewayServer();
 +
 +  }
 +
 +  @AfterClass
 +  public static void stopServers() {
 +    try {
 +      gatewayServer.stop();
 +      backendServer.stop();
 +    } catch (final Exception e) {
 +      e.printStackTrace(System.err);
 +    }
 +
 +    /* Cleanup the created files */
 +    FileUtils.deleteQuietly(topoDir);
 +
 +  }
 +
 +  /**
 +   * Test direct connection to websocket server without gateway
 +   * 
 +   * @throws Exception
 +   */
 +  @Test
 +  public void testDirectEcho() throws Exception {
 +
 +    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
 +    WebsocketClient client = new WebsocketClient();
 +
 +    Session session = container.connectToServer(client, backendServerUri);
 +
 +    session.getBasicRemote().sendText("Echo");
 +    client.messageQueue.awaitMessages(1, 1000, TimeUnit.MILLISECONDS);
 +
 +  }
 +
 +  /**
 +   * Test websocket proxying through gateway.
 +   * 
 +   * @throws Exception
 +   */
 +  @Test
 +  public void testGatewayEcho() throws Exception {
 +    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
 +
 +    WebsocketClient client = new WebsocketClient();
 +    Session session = container.connectToServer(client,
 +        new URI(serverUri.toString() + "gateway/websocket/ws"));
 +
 +    session.getBasicRemote().sendText("Echo");
 +    client.messageQueue.awaitMessages(1, 1000, TimeUnit.MILLISECONDS);
 +
 +    assertThat(client.messageQueue.get(0), is("Echo"));
 +
 +  }
 +
 +  /**
 +   * Test websocket rewrite rules proxying through gateway.
 +   *
 +   * @throws Exception
 +   */
 +  @Test
 +  public void testGatewayRewriteEcho() throws Exception {
 +    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
 +
 +    WebsocketClient client = new WebsocketClient();
 +    Session session = container.connectToServer(client,
 +            new URI(serverUri.toString() + 
"gateway/websocket/123foo456bar/channels"));
 +
 +    session.getBasicRemote().sendText("Echo");
 +    client.messageQueue.awaitMessages(1, 1000, TimeUnit.MILLISECONDS);
 +
 +    assertThat(client.messageQueue.get(0), is("Echo"));
 +
 +  }
 +
 +  /**
 +   * Start Mock Websocket server that acts as backend.
 +   * 
 +   * @throws Exception
 +   */
 +  private static void startWebsocketServer() throws Exception {
 +
 +    backendServer = new Server();
 +    ServerConnector connector = new ServerConnector(backendServer);
 +    backendServer.addConnector(connector);
 +
 +    final WebsocketEchoHandler handler = new WebsocketEchoHandler();
 +
 +    ContextHandler context = new ContextHandler();
 +    context.setContextPath("/");
 +    context.setHandler(handler);
 +    backendServer.setHandler(context);
 +
 +    // Start Server
 +    backendServer.start();
 +
 +    String host = connector.getHost();
 +    if (host == null) {
 +      host = "localhost";
 +    }
 +    int port = connector.getLocalPort();
 +    backendServerUri = new URI(String.format("ws://%s:%d/ws", host, port));
 +
 +  }
 +
 +  /**
 +   * Start Gateway Server.
 +   * 
 +   * @throws Exception
 +   */
 +  private static void startGatewayServer() throws Exception {
 +    gatewayServer = new Server();
 +    final ServerConnector connector = new ServerConnector(gatewayServer);
 +    gatewayServer.addConnector(connector);
 +
 +    /* workaround so we can add our handler later at runtime */
 +    HandlerCollection handlers = new HandlerCollection(true);
 +
 +    /* add some initial handlers */
 +    ContextHandler context = new ContextHandler();
 +    context.setContextPath("/");
 +    handlers.addHandler(context);
 +
 +    gatewayServer.setHandler(handlers);
 +
 +    // Start Server
 +    gatewayServer.start();
 +
 +    String host = connector.getHost();
 +    if (host == null) {
 +      host = "localhost";
 +    }
 +    int port = connector.getLocalPort();
 +    serverUri = new URI(String.format("ws://%s:%d/", host, port));
 +
 +    /* Setup websocket handler */
 +    setupGatewayConfig(backendServerUri.toString());
 +
 +    final GatewayWebsocketHandler gatewayWebsocketHandler = new 
GatewayWebsocketHandler(
 +        gatewayConfig, services);
 +    handlers.addHandler(gatewayWebsocketHandler);
 +    gatewayWebsocketHandler.start();
 +  }
 +
 +  /**
 +   * Initialize the configs and components required for this test.
 +   * 
 +   * @param backend
 +   * @throws IOException
 +   */
 +  private static void setupGatewayConfig(final String backend)
 +      throws IOException {
 +    services = new DefaultGatewayServices();
 +
 +    topoDir = createDir();
 +    URL serviceUrl = ClassLoader.getSystemResource("websocket-services");
 +
 +    final File descriptor = new File(topoDir, "websocket.xml");
 +    final FileOutputStream stream = new FileOutputStream(descriptor);
 +    createKnoxTopology(backend).toStream(stream);
 +    stream.close();
 +
 +    final TestTopologyListener topoListener = new TestTopologyListener();
 +
 +    final Map<String, String> options = new HashMap<>();
 +    options.put("persist-master", "false");
 +    options.put("master", "password");
 +
 +    gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class);
 +    EasyMock.expect(gatewayConfig.getGatewayTopologyDir())
 +        .andReturn(topoDir.toString()).anyTimes();
 +
++    EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir())
++            .andReturn(topoDir.getAbsolutePath() + 
"/shared-providers").anyTimes();
++
++    EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir())
++            .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes();
++
 +    EasyMock.expect(gatewayConfig.getGatewayServicesDir())
 +        .andReturn(serviceUrl.getFile()).anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048")
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
 +        .andReturn(topoDir.toString()).anyTimes();
 +
 +    /* Websocket configs */
 +    EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageSize())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageSize())
 +        
.andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageBufferSize())
 +        .andReturn(
 +            GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageBufferSize())
 +        .andReturn(
 +            
GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketInputBufferSize())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_INPUT_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketAsyncWriteTimeout())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout())
 +        
.andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes();
 +
++    EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames())
++            .andReturn(Collections.emptyList())
++            .anyTimes();
++
 +    EasyMock.replay(gatewayConfig);
 +
 +    try {
 +      services.init(gatewayConfig, options);
 +    } catch (ServiceLifecycleException e) {
 +      e.printStackTrace();
 +    }
 +
 +    DeploymentFactory.setGatewayServices(services);
 +    final TopologyService monitor = services
 +        .getService(GatewayServices.TOPOLOGY_SERVICE);
 +    monitor.addTopologyChangeListener(topoListener);
 +    monitor.reloadTopologies();
 +
 +  }
 +
 +  private static File createDir() throws IOException {
 +    return TestUtils
 +        .createTempDir(WebsocketEchoTest.class.getSimpleName() + "-");
 +  }
 +
 +  private static XMLTag createKnoxTopology(final String backend) {
 +    XMLTag xml = 
XMLDoc.newDocument(true).addRoot("topology").addTag("service")
 +        .addTag("role").addText("WEBSOCKET").addTag("url").addText(backend)
 +        .gotoParent().gotoRoot();
 +    // System.out.println( "GATEWAY=" + xml.toString() );
 +    return xml;
 +  }
 +
 +  private static class TestTopologyListener implements TopologyListener {
 +
 +    public ArrayList<List<TopologyEvent>> events = new 
ArrayList<List<TopologyEvent>>();
 +
 +    @Override
 +    public void handleTopologyEvent(List<TopologyEvent> events) {
 +      this.events.add(events);
 +
 +      synchronized (this) {
 +        for (TopologyEvent event : events) {
 +          if (!event.getType().equals(TopologyEvent.Type.DELETED)) {
 +
 +            /* for this test we only care about this part */
 +            DeploymentFactory.createDeployment(gatewayConfig,
 +                event.getTopology());
 +
 +          }
 +        }
 +
 +      }
 +
 +    }
 +
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
----------------------------------------------------------------------
diff --cc 
gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
index 42bc9c3,0000000..5e5006c
mode 100644,000000..100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketMultipleConnectionTest.java
@@@ -1,389 -1,0 +1,400 @@@
 +/**
 + * 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.websockets;
 +
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.lang.management.ManagementFactory;
 +import java.lang.management.MemoryMXBean;
 +import java.net.URI;
 +import java.net.URL;
 +import java.util.ArrayList;
++import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.concurrent.CountDownLatch;
 +import java.util.concurrent.TimeUnit;
 +
 +import javax.websocket.ContainerProvider;
 +import javax.websocket.Endpoint;
 +import javax.websocket.EndpointConfig;
 +import javax.websocket.MessageHandler;
 +import javax.websocket.Session;
 +import javax.websocket.WebSocketContainer;
 +
 +import org.apache.commons.io.FileUtils;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentFactory;
 +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.TopologyEvent;
 +import org.apache.knox.gateway.topology.TopologyListener;
 +import org.apache.knox.test.TestUtils;
 +import org.easymock.EasyMock;
 +import org.eclipse.jetty.server.Server;
 +import org.eclipse.jetty.server.ServerConnector;
 +import org.eclipse.jetty.server.handler.ContextHandler;
 +import org.eclipse.jetty.server.handler.HandlerCollection;
 +import org.eclipse.jetty.util.thread.QueuedThreadPool;
 +import org.junit.AfterClass;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +
 +import com.mycila.xmltool.XMLDoc;
 +import com.mycila.xmltool.XMLTag;
 +
 +/**
 + * Test how Knox holds up under multiple concurrent connections.
 + *
 + */
 +public class WebsocketMultipleConnectionTest {
 +  /**
 +   * Simulate backend websocket
 +   */
 +  private static Server backendServer;
 +  /**
 +   * URI for backend websocket server
 +   */
 +  private static URI backendServerUri;
 +
 +  /**
 +   * Mock Gateway server
 +   */
 +  private static Server gatewayServer;
 +
 +  /**
 +   * Mock gateway config
 +   */
 +  private static GatewayConfig gatewayConfig;
 +
 +  private static GatewayServices services;
 +
 +  /**
 +   * URI for gateway server
 +   */
 +  private static URI serverUri;
 +
 +  private static File topoDir;
 +
 +  /**
 +   * Maximum number of open connections to test.
 +   */
 +  private static int MAX_CONNECTIONS = 100;
 +
 +  public WebsocketMultipleConnectionTest() {
 +    super();
 +  }
 +
 +  @BeforeClass
 +  public static void startServers() throws Exception {
 +
 +    startWebsocketServer();
 +    startGatewayServer();
 +
 +  }
 +
 +  @AfterClass
 +  public static void stopServers() {
 +    try {
 +      gatewayServer.stop();
 +      backendServer.stop();
 +    } catch (final Exception e) {
 +      e.printStackTrace(System.err);
 +    }
 +
 +    /* Cleanup the created files */
 +    FileUtils.deleteQuietly(topoDir);
 +
 +  }
 +
 +  /**
 +   * Test websocket proxying through gateway.
 +   * 
 +   * @throws Exception
 +   */
 +  @Test
 +  public void testMultipleConnections() throws Exception {
 +    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
 +
 +    final CountDownLatch latch = new CountDownLatch(MAX_CONNECTIONS);
 +
 +    Session[] sessions = new Session[MAX_CONNECTIONS];
 +
 +    MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
 +
 +    System.gc();
 +    final long heapt1 = memoryMXBean.getHeapMemoryUsage().getUsed();
 +    final long nonHeapt1 = memoryMXBean.getNonHeapMemoryUsage().getUsed();
 +
 +    for (int i = 0; i < MAX_CONNECTIONS; i++) {
 +
 +      sessions[i] = container.connectToServer(new WebsocketClient() {
 +
 +        @Override
 +        public void onMessage(String message) {
 +          latch.countDown();
 +
 +        }
 +
 +      }, new URI(serverUri.toString() + "gateway/websocket/ws"));
 +
 +    }
 +
 +    for (int i = 0; i < MAX_CONNECTIONS; i++) {
 +      /* make sure the session is active and valid before trying to connect */
 +      if(sessions[i].isOpen() && sessions[i].getBasicRemote() != null) {
 +        sessions[i].getBasicRemote().sendText("OK");
 +      }
 +    }
 +
 +    latch.await(5 * MAX_CONNECTIONS, TimeUnit.MILLISECONDS);
 +
 +    System.gc();
 +
 +    final long heapUsed = memoryMXBean.getHeapMemoryUsage().getUsed() - 
heapt1;
 +    final long nonHeapUsed = memoryMXBean.getNonHeapMemoryUsage().getUsed()
 +        - nonHeapt1;
 +
 +    System.out.println("heapUsed = " + heapUsed);
 +    System.out.println("nonHeapUsed = " + nonHeapUsed);
 +
 +    /* 90 KB per connection */
 +    /*
 +    long expected = 90 * 1024 * MAX_CONNECTIONS;
 +    assertThat("heap used", heapUsed, lessThan(expected));
 +    */
 +  }
 +
 +  /**
 +   * Start Mock Websocket server that acts as backend.
 +   * 
 +   * @throws Exception
 +   */
 +  private static void startWebsocketServer() throws Exception {
 +
 +    backendServer = new Server(new QueuedThreadPool(254));
 +    ServerConnector connector = new ServerConnector(backendServer);
 +    backendServer.addConnector(connector);
 +
 +    final WebsocketEchoHandler handler = new WebsocketEchoHandler();
 +
 +    ContextHandler context = new ContextHandler();
 +    context.setContextPath("/");
 +    context.setHandler(handler);
 +    backendServer.setHandler(context);
 +
 +    // Start Server
 +    backendServer.start();
 +
 +    String host = connector.getHost();
 +    if (host == null) {
 +      host = "localhost";
 +    }
 +    int port = connector.getLocalPort();
 +    backendServerUri = new URI(String.format("ws://%s:%d/ws", host, port));
 +
 +  }
 +
 +  /**
 +   * Start Gateway Server.
 +   * 
 +   * @throws Exception
 +   */
 +  private static void startGatewayServer() throws Exception {
 +    /* use default Max threads */
 +    gatewayServer = new Server(new QueuedThreadPool(254));
 +    final ServerConnector connector = new ServerConnector(gatewayServer);
 +    gatewayServer.addConnector(connector);
 +
 +    /* workaround so we can add our handler later at runtime */
 +    HandlerCollection handlers = new HandlerCollection(true);
 +
 +    /* add some initial handlers */
 +    ContextHandler context = new ContextHandler();
 +    context.setContextPath("/");
 +    handlers.addHandler(context);
 +
 +    gatewayServer.setHandler(handlers);
 +
 +    // Start Server
 +    gatewayServer.start();
 +
 +    String host = connector.getHost();
 +    if (host == null) {
 +      host = "localhost";
 +    }
 +    int port = connector.getLocalPort();
 +    serverUri = new URI(String.format("ws://%s:%d/", host, port));
 +
 +    /* Setup websocket handler */
 +    setupGatewayConfig(backendServerUri.toString());
 +
 +    final GatewayWebsocketHandler gatewayWebsocketHandler = new 
GatewayWebsocketHandler(
 +        gatewayConfig, services);
 +    handlers.addHandler(gatewayWebsocketHandler);
 +    gatewayWebsocketHandler.start();
 +  }
 +
 +  /**
 +   * Initialize the configs and components required for this test.
 +   * 
 +   * @param backend
 +   * @throws IOException
 +   */
 +  private static void setupGatewayConfig(final String backend)
 +      throws IOException {
 +    services = new DefaultGatewayServices();
 +
 +    topoDir = createDir();
 +    URL serviceUrl = ClassLoader.getSystemResource("websocket-services");
 +
 +    final File descriptor = new File(topoDir, "websocket.xml");
 +    final FileOutputStream stream = new FileOutputStream(descriptor);
 +    createKnoxTopology(backend).toStream(stream);
 +    stream.close();
 +
 +    final TestTopologyListener topoListener = new TestTopologyListener();
 +
 +    final Map<String, String> options = new HashMap<>();
 +    options.put("persist-master", "false");
 +    options.put("master", "password");
 +
 +    gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class);
 +    EasyMock.expect(gatewayConfig.getGatewayTopologyDir())
 +        .andReturn(topoDir.toString()).anyTimes();
 +
++    EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir())
++            .andReturn(topoDir.getAbsolutePath() + 
"/shared-providers").anyTimes();
++
++    EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir())
++            .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes();
++
 +    EasyMock.expect(gatewayConfig.getGatewayServicesDir())
 +        .andReturn(serviceUrl.getFile()).anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048")
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getGatewaySecurityDir())
 +        .andReturn(topoDir.toString()).anyTimes();
 +
 +    /* Websocket configs */
 +    EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageSize())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageSize())
 +        
.andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageBufferSize())
 +        .andReturn(
 +            GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageBufferSize())
 +        .andReturn(
 +            
GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketInputBufferSize())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_INPUT_BUFFER_SIZE)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketAsyncWriteTimeout())
 +        .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT)
 +        .anyTimes();
 +
 +    EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout())
 +        
.andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes();
 +
++    EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames())
++            .andReturn(Collections.emptyList())
++            .anyTimes();
++
 +    EasyMock.replay(gatewayConfig);
 +
 +    try {
 +      services.init(gatewayConfig, options);
 +    } catch (ServiceLifecycleException e) {
 +      e.printStackTrace();
 +    }
 +
 +    DeploymentFactory.setGatewayServices(services);
 +    final TopologyService monitor = services
 +        .getService(GatewayServices.TOPOLOGY_SERVICE);
 +    monitor.addTopologyChangeListener(topoListener);
 +    monitor.reloadTopologies();
 +
 +  }
 +
 +  private static File createDir() throws IOException {
 +    return TestUtils
 +        .createTempDir(WebsocketEchoTest.class.getSimpleName() + "-");
 +  }
 +
 +  private static XMLTag createKnoxTopology(final String backend) {
 +    XMLTag xml = 
XMLDoc.newDocument(true).addRoot("topology").addTag("service")
 +        .addTag("role").addText("WEBSOCKET").addTag("url").addText(backend)
 +        .gotoParent().gotoRoot();
 +    // System.out.println( "GATEWAY=" + xml.toString() );
 +    return xml;
 +  }
 +
 +  private static class TestTopologyListener implements TopologyListener {
 +
 +    public ArrayList<List<TopologyEvent>> events = new 
ArrayList<List<TopologyEvent>>();
 +
 +    @Override
 +    public void handleTopologyEvent(List<TopologyEvent> events) {
 +      this.events.add(events);
 +
 +      synchronized (this) {
 +        for (TopologyEvent event : events) {
 +          if (!event.getType().equals(TopologyEvent.Type.DELETED)) {
 +
 +            /* for this test we only care about this part */
 +            DeploymentFactory.createDeployment(gatewayConfig,
 +                event.getTopology());
 +
 +          }
 +        }
 +
 +      }
 +
 +    }
 +
 +  }
 +
 +  private static abstract class WebsocketClient extends Endpoint
 +      implements MessageHandler.Whole<String> {
 +    @Override
 +    public void onOpen(Session session, EndpointConfig config) {
 +      session.addMessageHandler(this);
 +    }
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/22a7304a/gateway-service-definitions/src/main/resources/services/ambariui/2.2.1/service.xml
----------------------------------------------------------------------
diff --cc 
gateway-service-definitions/src/main/resources/services/ambariui/2.2.1/service.xml
index c6135ae,0000000..e69de29
mode 100644,000000..100644
--- 
a/gateway-service-definitions/src/main/resources/services/ambariui/2.2.1/service.xml
+++ 
b/gateway-service-definitions/src/main/resources/services/ambariui/2.2.1/service.xml

Reply via email to