You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2018/01/11 17:39:15 UTC

[48/53] [abbrv] knox git commit: Merge branch 'master' into KNOX-998-Package_Restructuring

http://git-wip-us.apache.org/repos/asf/knox/blob/e5fd0622/gateway-server/src/test/java/org/apache/knox/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java
----------------------------------------------------------------------
diff --cc gateway-server/src/test/java/org/apache/knox/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java
index 75cd5d0,0000000..2e753f1
mode 100644,000000..100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java
@@@ -1,355 -1,0 +1,368 @@@
 +/**
 + * 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
 + * <p>
 + * http://www.apache.org/licenses/LICENSE-2.0
 + * <p>
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 + * License for the specific language governing permissions and limitations under
 + * the License.
 + */
 +package org.apache.knox.gateway.topology.monitor;
 +
 +import org.apache.commons.io.FileUtils;
 +import org.apache.curator.framework.CuratorFramework;
 +import org.apache.curator.framework.CuratorFrameworkFactory;
 +import org.apache.curator.retry.ExponentialBackoffRetry;
 +import org.apache.curator.test.InstanceSpec;
 +import org.apache.curator.test.TestingCluster;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientService;
 +import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientServiceProvider;
 +import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 +import org.apache.knox.gateway.services.security.AliasService;
 +import org.apache.knox.test.TestUtils;
 +import org.apache.zookeeper.CreateMode;
 +import org.apache.zookeeper.ZooDefs;
 +import org.apache.zookeeper.data.ACL;
 +import org.easymock.EasyMock;
 +import org.junit.AfterClass;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +
 +import java.io.File;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +
 +import static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertFalse;
 +import static org.junit.Assert.assertNotNull;
 +import static org.junit.Assert.assertTrue;
 +import static org.junit.Assert.fail;
 +
 +/**
 + * Test the ZooKeeperConfigMonitor WITHOUT SASL configured or znode ACLs applied.
 + * The implementation of the monitor is the same regardless, since the ACLs are defined by the ZooKeeper znode
 + * creator, and the SASL config is purely JAAS (and external to the implementation).
 + */
 +public class ZooKeeperConfigurationMonitorTest {
 +
 +    private static final String PATH_KNOX = "/knox";
 +    private static final String PATH_KNOX_CONFIG = PATH_KNOX + "/config";
 +    private static final String PATH_KNOX_PROVIDERS = PATH_KNOX_CONFIG + "/shared-providers";
 +    private static final String PATH_KNOX_DESCRIPTORS = PATH_KNOX_CONFIG + "/descriptors";
 +
 +    private static File testTmp;
 +    private static File providersDir;
 +    private static File descriptorsDir;
 +
 +    private static TestingCluster zkCluster;
 +
 +    private static CuratorFramework client;
 +
 +    private GatewayConfig gc;
 +
 +
 +    @BeforeClass
 +    public static void setupSuite() throws Exception {
 +        testTmp = TestUtils.createTempDir(ZooKeeperConfigurationMonitorTest.class.getName());
 +        File confDir   = TestUtils.createTempDir(testTmp + "/conf");
 +        providersDir   = TestUtils.createTempDir(confDir + "/shared-providers");
 +        descriptorsDir = TestUtils.createTempDir(confDir + "/descriptors");
 +
 +        configureAndStartZKCluster();
 +    }
 +
 +    private static void configureAndStartZKCluster() throws Exception {
 +        // Configure security for the ZK cluster instances
 +        Map<String, Object> customInstanceSpecProps = new HashMap<>();
 +        customInstanceSpecProps.put("authProvider.1", "org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
 +        customInstanceSpecProps.put("requireClientAuthScheme", "sasl");
 +
 +        // Define the test cluster
 +        List<InstanceSpec> instanceSpecs = new ArrayList<>();
 +        for (int i = 0 ; i < 3 ; i++) {
 +            InstanceSpec is = new InstanceSpec(null, -1, -1, -1, false, (i+1), -1, -1, customInstanceSpecProps);
 +            instanceSpecs.add(is);
 +        }
 +        zkCluster = new TestingCluster(instanceSpecs);
 +
 +        // Start the cluster
 +        zkCluster.start();
 +
 +        // Create the client for the test cluster
 +        client = CuratorFrameworkFactory.builder()
 +                                        .connectString(zkCluster.getConnectString())
 +                                        .retryPolicy(new ExponentialBackoffRetry(100, 3))
 +                                        .build();
 +        assertNotNull(client);
 +        client.start();
 +
 +        // Create the knox config paths with an ACL for the sasl user configured for the client
 +        List<ACL> acls = new ArrayList<>();
 +        acls.add(new ACL(ZooDefs.Perms.ALL, ZooDefs.Ids.ANYONE_ID_UNSAFE));
 +
 +        client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(acls).forPath(PATH_KNOX_DESCRIPTORS);
 +        assertNotNull("Failed to create node:" + PATH_KNOX_DESCRIPTORS,
-                 client.checkExists().forPath(PATH_KNOX_DESCRIPTORS));
++                      client.checkExists().forPath(PATH_KNOX_DESCRIPTORS));
 +        client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(acls).forPath(PATH_KNOX_PROVIDERS);
 +        assertNotNull("Failed to create node:" + PATH_KNOX_PROVIDERS,
-                 client.checkExists().forPath(PATH_KNOX_PROVIDERS));
++                      client.checkExists().forPath(PATH_KNOX_PROVIDERS));
 +    }
 +
 +    @AfterClass
 +    public static void tearDownSuite() throws Exception {
 +        // Clean up the ZK nodes, and close the client
 +        if (client != null) {
 +            client.delete().deletingChildrenIfNeeded().forPath(PATH_KNOX);
 +            client.close();
 +        }
 +
 +        // Shutdown the ZK cluster
 +        zkCluster.close();
 +
 +        // Delete the working dir
 +        testTmp.delete();
 +    }
 +
 +    @Test
 +    public void testZooKeeperConfigMonitor() throws Exception {
 +        String configMonitorName = "remoteConfigMonitorClient";
 +
 +        // Setup the base GatewayConfig mock
 +        gc = EasyMock.createNiceMock(GatewayConfig.class);
 +        EasyMock.expect(gc.getGatewayProvidersConfigDir()).andReturn(providersDir.getAbsolutePath()).anyTimes();
 +        EasyMock.expect(gc.getGatewayDescriptorsDir()).andReturn(descriptorsDir.getAbsolutePath()).anyTimes();
 +        EasyMock.expect(gc.getRemoteRegistryConfigurationNames())
 +                .andReturn(Collections.singletonList(configMonitorName))
 +                .anyTimes();
 +        final String registryConfig =
 +                                GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE + "=" + ZooKeeperClientService.TYPE + ";" +
 +                                GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS + "=" + zkCluster.getConnectString();
 +        EasyMock.expect(gc.getRemoteRegistryConfiguration(configMonitorName))
 +                .andReturn(registryConfig)
 +                .anyTimes();
 +        EasyMock.expect(gc.getRemoteConfigurationMonitorClientName()).andReturn(configMonitorName).anyTimes();
 +        EasyMock.replay(gc);
 +
 +        AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
 +        EasyMock.replay(aliasService);
 +
 +        RemoteConfigurationRegistryClientService clientService = (new ZooKeeperClientServiceProvider()).newInstance();
 +        clientService.setAliasService(aliasService);
 +        clientService.init(gc, Collections.emptyMap());
 +        clientService.start();
 +
 +        DefaultRemoteConfigurationMonitor cm = new DefaultRemoteConfigurationMonitor(gc, clientService);
 +
++        // Create a provider configuration in the test ZK, prior to starting the monitor, to make sure that the monitor
++        // will download existing entries upon starting.
++        final String preExistingProviderConfig = getProviderPath("pre-existing-providers.xml");
++        client.create().withMode(CreateMode.PERSISTENT).forPath(preExistingProviderConfig,
++                                                                TEST_PROVIDERS_CONFIG_1.getBytes());
++        File preExistingProviderConfigLocalFile = new File(providersDir, "pre-existing-providers.xml");
++        assertFalse("This file should not exist locally prior to monitor starting.",
++                    preExistingProviderConfigLocalFile.exists());
++
 +        try {
 +            cm.start();
 +        } catch (Exception e) {
 +            fail("Failed to start monitor: " + e.getMessage());
 +        }
 +
++        assertTrue("This file should exist locally immediately after monitor starting.",
++                    preExistingProviderConfigLocalFile.exists());
++
++
 +        try {
 +            final String pc_one_znode = getProviderPath("providers-config1.xml");
 +            final File pc_one         = new File(providersDir, "providers-config1.xml");
 +            final String pc_two_znode = getProviderPath("providers-config2.xml");
 +            final File pc_two         = new File(providersDir, "providers-config2.xml");
 +
 +            client.create().withMode(CreateMode.PERSISTENT).forPath(pc_one_znode, TEST_PROVIDERS_CONFIG_1.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(pc_one.exists());
 +            assertEquals(TEST_PROVIDERS_CONFIG_1, FileUtils.readFileToString(pc_one));
 +
 +            client.create().withMode(CreateMode.PERSISTENT).forPath(getProviderPath("providers-config2.xml"), TEST_PROVIDERS_CONFIG_2.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(pc_two.exists());
 +            assertEquals(TEST_PROVIDERS_CONFIG_2, FileUtils.readFileToString(pc_two));
 +
 +            client.setData().forPath(pc_two_znode, TEST_PROVIDERS_CONFIG_1.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(pc_two.exists());
 +            assertEquals(TEST_PROVIDERS_CONFIG_1, FileUtils.readFileToString(pc_two));
 +
 +            client.delete().forPath(pc_two_znode);
 +            Thread.sleep(100);
 +            assertFalse(pc_two.exists());
 +
 +            client.delete().forPath(pc_one_znode);
 +            Thread.sleep(100);
 +            assertFalse(pc_one.exists());
 +
 +            final String desc_one_znode   = getDescriptorPath("test1.json");
 +            final String desc_two_znode   = getDescriptorPath("test2.json");
 +            final String desc_three_znode = getDescriptorPath("test3.json");
 +            final File desc_one           = new File(descriptorsDir, "test1.json");
 +            final File desc_two           = new File(descriptorsDir, "test2.json");
 +            final File desc_three         = new File(descriptorsDir, "test3.json");
 +
 +            client.create().withMode(CreateMode.PERSISTENT).forPath(desc_one_znode, TEST_DESCRIPTOR_1.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(desc_one.exists());
 +            assertEquals(TEST_DESCRIPTOR_1, FileUtils.readFileToString(desc_one));
 +
 +            client.create().withMode(CreateMode.PERSISTENT).forPath(desc_two_znode, TEST_DESCRIPTOR_1.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(desc_two.exists());
 +            assertEquals(TEST_DESCRIPTOR_1, FileUtils.readFileToString(desc_two));
 +
 +            client.setData().forPath(desc_two_znode, TEST_DESCRIPTOR_2.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(desc_two.exists());
 +            assertEquals(TEST_DESCRIPTOR_2, FileUtils.readFileToString(desc_two));
 +
 +            client.create().withMode(CreateMode.PERSISTENT).forPath(desc_three_znode, TEST_DESCRIPTOR_1.getBytes());
 +            Thread.sleep(100);
 +            assertTrue(desc_three.exists());
 +            assertEquals(TEST_DESCRIPTOR_1, FileUtils.readFileToString(desc_three));
 +
 +            client.delete().forPath(desc_two_znode);
 +            Thread.sleep(100);
 +            assertFalse("Expected test2.json to have been deleted.", desc_two.exists());
 +
 +            client.delete().forPath(desc_three_znode);
 +            Thread.sleep(100);
 +            assertFalse(desc_three.exists());
 +
 +            client.delete().forPath(desc_one_znode);
 +            Thread.sleep(100);
 +            assertFalse(desc_one.exists());
 +        } finally {
 +            cm.stop();
 +        }
 +    }
 +
 +    private static String getDescriptorPath(String descriptorName) {
 +        return PATH_KNOX_DESCRIPTORS + "/" + descriptorName;
 +    }
 +
 +    private static String getProviderPath(String providerConfigName) {
 +        return PATH_KNOX_PROVIDERS + "/" + providerConfigName;
 +    }
 +
 +
 +    private static final String TEST_PROVIDERS_CONFIG_1 =
 +            "<gateway>\n" +
 +            "    <provider>\n" +
 +            "        <role>identity-assertion</role>\n" +
 +            "        <name>Default</name>\n" +
 +            "        <enabled>true</enabled>\n" +
 +            "    </provider>\n" +
 +            "    <provider>\n" +
 +            "        <role>hostmap</role>\n" +
 +            "        <name>static</name>\n" +
 +            "        <enabled>true</enabled>\n" +
 +            "        <param><name>localhost</name><value>sandbox,sandbox.hortonworks.com</value></param>\n" +
 +            "    </provider>\n" +
 +            "</gateway>\n";
 +
 +    private static final String TEST_PROVIDERS_CONFIG_2 =
 +            "<gateway>\n" +
 +            "    <provider>\n" +
 +            "        <role>authentication</role>\n" +
 +            "        <name>ShiroProvider</name>\n" +
 +            "        <enabled>true</enabled>\n" +
 +            "        <param>\n" +
 +            "            <name>sessionTimeout</name>\n" +
 +            "            <value>30</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>main.ldapRealm</name>\n" +
 +            "            <value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>main.ldapContextFactory</name>\n" +
 +            "            <value>org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>main.ldapRealm.contextFactory</name>\n" +
 +            "            <value>$ldapContextFactory</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>main.ldapRealm.userDnTemplate</name>\n" +
 +            "            <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>main.ldapRealm.contextFactory.url</name>\n" +
 +            "            <value>ldap://localhost:33389</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" +
 +            "            <value>simple</value>\n" +
 +            "        </param>\n" +
 +            "        <param>\n" +
 +            "            <name>urls./**</name>\n" +
 +            "            <value>authcBasic</value>\n" +
 +            "        </param>\n" +
 +            "    </provider>\n" +
 +            "</gateway>\n";
 +
 +    private static final String TEST_DESCRIPTOR_1 =
 +            "{\n" +
 +            "  \"discovery-type\":\"AMBARI\",\n" +
 +            "  \"discovery-address\":\"http://sandbox.hortonworks.com:8080\",\n" +
 +            "  \"discovery-user\":\"maria_dev\",\n" +
 +            "  \"discovery-pwd-alias\":\"sandbox.ambari.discovery.password\",\n" +
 +            "  \"provider-config-ref\":\"sandbox-providers.xml\",\n" +
 +            "  \"cluster\":\"Sandbox\",\n" +
 +            "  \"services\":[\n" +
 +            "    {\"name\":\"NODEUI\"},\n" +
 +            "    {\"name\":\"YARNUI\"},\n" +
 +            "    {\"name\":\"HDFSUI\"},\n" +
 +            "    {\"name\":\"OOZIEUI\"},\n" +
 +            "    {\"name\":\"HBASEUI\"},\n" +
 +            "    {\"name\":\"NAMENODE\"},\n" +
 +            "    {\"name\":\"JOBTRACKER\"},\n" +
 +            "    {\"name\":\"WEBHDFS\"},\n" +
 +            "    {\"name\":\"WEBHCAT\"},\n" +
 +            "    {\"name\":\"OOZIE\"},\n" +
 +            "    {\"name\":\"WEBHBASE\"},\n" +
 +            "    {\"name\":\"RESOURCEMANAGER\"},\n" +
 +            "    {\"name\":\"AMBARI\", \"urls\":[\"http://c6401.ambari.apache.org:8080\"]},\n" +
 +            "    {\"name\":\"AMBARIUI\", \"urls\":[\"http://c6401.ambari.apache.org:8080\"]}\n" +
 +            "  ]\n" +
 +            "}\n";
 +
 +    private static final String TEST_DESCRIPTOR_2 =
 +            "{\n" +
 +            "  \"discovery-type\":\"AMBARI\",\n" +
 +            "  \"discovery-address\":\"http://sandbox.hortonworks.com:8080\",\n" +
 +            "  \"discovery-user\":\"maria_dev\",\n" +
 +            "  \"discovery-pwd-alias\":\"sandbox.ambari.discovery.password\",\n" +
 +            "  \"provider-config-ref\":\"sandbox-providers.xml\",\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\":\"RESOURCEMANAGER\"}\n" +
 +            "  ]\n" +
 +            "}\n";
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/e5fd0622/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 b768937,0000000..116b8dd
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,1032 -1,0 +1,1048 @@@
 +/**
 + * 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.hadoop.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 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);
++
++      outContent.reset();
++      final String[] listArgs = {"list-provider-configs", "--registry-client", "test_client"};
++      cli.run(listArgs);
++      String outStr =  outContent.toString().trim();
++      assertTrue(outStr.startsWith("Provider Configurations"));
++      assertTrue(outStr.endsWith(")\n"+providerConfigName));
++
 +      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);
++
++      outContent.reset();
++      final String[] listArgs = {"list-descriptors", "--registry-client", "test_client"};
++      cli.run(listArgs);
++      String outStr =  outContent.toString().trim();
++      assertTrue(outStr.startsWith("Descriptors"));
++      assertTrue(outStr.endsWith(")\n"+descriptorName));
++
 +      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/e5fd0622/pom.xml
----------------------------------------------------------------------