SLIDER-19. Add functional test for Agent

git-svn-id: https://svn.apache.org/repos/asf/incubator/slider/trunk@1592654 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
index 83156df..3858206 100644
--- a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
+++ b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java
@@ -496,7 +496,7 @@
     } catch (SliderException e) {
       //problem, reject it
       log.info("Error {} validating application instance definition ", e.toString());
-      log.debug("Error {} validating application instance definition ", e);
+      log.debug("Error validating application instance definition ", e);
       log.info(instanceDefinition.toString());
       throw e;
     }
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
index ebc5f8f..9020d79 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
@@ -94,6 +94,7 @@
       LoggerFactory.getLogger(AgentProviderService.class);
   private static final ProviderUtils providerUtils = new ProviderUtils(log);
   private static final String LABEL_MAKER = "___";
+  private static final String CONTAINER_ID = "container_id";
   private AgentClientProvider clientProvider;
   private Map<String, ComponentInstanceState> componentStatuses = new HashMap<String, ComponentInstanceState>();
   private Map<String, List<String>> roleHostMapping = new HashMap<String, List<String>>();
@@ -155,6 +156,7 @@
     String logDir = ApplicationConstants.Environment.LOG_DIRS.$();
     launcher.setEnv("AGENT_LOG_ROOT", logDir);
     log.info("AGENT_LOG_ROOT set to {}", logDir);
+    launcher.setEnv("HADOOP_USER_NAME", System.getenv(HADOOP_USER_NAME));
 
     //local resources
 
@@ -338,10 +340,11 @@
 
     String label = heartBeat.getHostname();
     String roleName = getRoleName(label);
+    String containerId = getContainerId(label);
     StateAccessForProviders accessor = getStateAccessor();
     String scriptPath;
-      scriptPath = accessor.getInstanceDefinitionSnapshot().
-          getAppConfOperations().getComponentOpt(roleName, AgentKeys.COMPONENT_SCRIPT, null);
+    scriptPath = accessor.getInstanceDefinitionSnapshot().
+        getAppConfOperations().getComponentOpt(roleName, AgentKeys.COMPONENT_SCRIPT, null);
     if (scriptPath == null) {
       log.error("role.script is unavailable for " + roleName + ". Commands will not be sent.");
       return response;
@@ -376,10 +379,10 @@
         componentStatus.commandIssued(command);
         if (command == Command.INSTALL) {
           log.info("Installing component ...");
-          addInstallCommand(roleName, response, scriptPath);
+          addInstallCommand(roleName, containerId, response, scriptPath);
         } else if (command == Command.START) {
           log.info("Starting component ...");
-          addStartCommand(roleName, response, scriptPath);
+          addStartCommand(roleName, containerId, response, scriptPath);
         }
       } catch (SliderException e) {
         componentStatus.applyCommandResult(CommandResult.FAILED, command);
@@ -394,7 +397,11 @@
     return label.substring(label.indexOf(LABEL_MAKER) + LABEL_MAKER.length());
   }
 
-  protected void addInstallCommand(String roleName, HeartBeatResponse response, String scriptPath)
+  private String getContainerId(String label) {
+    return label.substring(0, label.indexOf(LABEL_MAKER));
+  }
+
+  protected void addInstallCommand(String roleName, String containerId, HeartBeatResponse response, String scriptPath)
       throws SliderException {
     assert getStateAccessor().isApplicationLive();
     ConfTreeOperations appConf = getStateAccessor().getAppConfSnapshot();
@@ -414,6 +421,7 @@
     hostLevelParams.put(PACKAGE_LIST, "[{\"type\":\"tarball\",\"name\":\"" +
                                       appConf.getGlobalOptions().getMandatoryOption(
                                           PACKAGE_LIST) + "\"}]");
+    hostLevelParams.put(CONTAINER_ID, containerId);
     cmd.setHostLevelParams(hostLevelParams);
 
     setInstallCommandConfigurations(cmd);
@@ -447,7 +455,7 @@
     cmd.setConfigurations(configurations);
   }
 
-  protected void addStatusCommand(String roleName, HeartBeatResponse response, String scriptPath)
+  protected void addStatusCommand(String roleName, String containerId, HeartBeatResponse response, String scriptPath)
       throws SliderException {
     assert getStateAccessor().isApplicationLive();
     ConfTreeOperations appConf = getStateAccessor().getAppConfSnapshot();
@@ -464,6 +472,7 @@
 
     Map<String, String> hostLevelParams = new TreeMap<String, String>();
     hostLevelParams.put(JAVA_HOME, appConf.getGlobalOptions().getMandatoryOption(JAVA_HOME));
+    hostLevelParams.put(CONTAINER_ID, containerId);
     cmd.setHostLevelParams(hostLevelParams);
 
     cmd.setCommandParams(setCommandParameters(scriptPath, false));
@@ -475,7 +484,7 @@
     response.addStatusCommand(cmd);
   }
 
-  protected void addGetConfigCommand(String roleName, HeartBeatResponse response)
+  protected void addGetConfigCommand(String roleName, String containerId, HeartBeatResponse response)
       throws SliderException {
     assert getStateAccessor().isApplicationLive();
     ConfTreeOperations internalsConf = getStateAccessor().getInternalsSnapshot();
@@ -488,11 +497,17 @@
     cmd.setServiceName(clusterName);
     cmd.setClusterName(clusterName);
     cmd.setRoleCommand(StatusCommand.GET_CONFIG_COMMAND);
+    Map<String, String> hostLevelParams = new TreeMap<String, String>();
+    hostLevelParams.put(CONTAINER_ID, containerId);
+    cmd.setHostLevelParams(hostLevelParams);
+
+    hostLevelParams.put(CONTAINER_ID, containerId);
 
     response.addStatusCommand(cmd);
   }
 
-  protected void addStartCommand(String roleName, HeartBeatResponse response, String scriptPath) throws
+  protected void addStartCommand(String roleName, String containerId, HeartBeatResponse response, String scriptPath)
+      throws
       SliderException {
     assert getStateAccessor().isApplicationLive();
     ConfTreeOperations appConf = getStateAccessor().getAppConfSnapshot();
@@ -510,6 +525,7 @@
     cmd.setRole(roleName);
     Map<String, String> hostLevelParams = new TreeMap<String, String>();
     hostLevelParams.put(JAVA_HOME, appConf.getGlobalOptions().getMandatoryOption(JAVA_HOME));
+    hostLevelParams.put(CONTAINER_ID, containerId);
     cmd.setHostLevelParams(hostLevelParams);
 
     cmd.setCommandParams(setCommandParameters(scriptPath, true));
diff --git a/slider-core/src/test/app_packages/test_command_log/appConfig.json b/slider-core/src/test/app_packages/test_command_log/appConfig.json
new file mode 100644
index 0000000..02ee4d4
--- /dev/null
+++ b/slider-core/src/test/app_packages/test_command_log/appConfig.json
@@ -0,0 +1,28 @@
+{
+    "schema": "http://example.org/specification/v2.0.0",
+    "metadata": {
+    },
+    "global": {
+        "agent.conf": "/slider/agent/conf/agent.ini",
+        "application.def": "/slider/cmd_log_app_pkg.tar",
+        "config_types": "cl-site",
+        "java_home": "/usr/jdk64/jdk1.7.0_45",
+        "package_list": "files/command_log_10.tar",
+        "site.global.app_user": "yarn",
+        "site.global.application_id": "CommandLogger",
+        "site.global.app_log_dir": "${AGENT_LOG_ROOT}/app/log",
+        "site.global.app_pid_dir": "${AGENT_WORK_ROOT}/app/run",
+        "site.global.app_root": "${AGENT_WORK_ROOT}/app/install/hbase-0.96.1-hadoop2",
+        "site.global.app_install_dir": "${AGENT_WORK_ROOT}/app/install",
+        "site.cl-site.logfile.location": "${AGENT_LOG_ROOT}/app/log/operations.log",
+        "site.cl-site.datetime.format": "%A, %d. %B %Y %I:%M%p"
+    },
+    "components": {
+        "COMMAND_LOGGER": {
+            "role.script": "scripts/cl.py"
+        },
+        "slider-appmaster": {
+            "jvm.heapsize": "256M"
+        }
+    }
+}
diff --git a/slider-core/src/test/app_packages/test_command_log/cmd_log_app_pkg.tar b/slider-core/src/test/app_packages/test_command_log/cmd_log_app_pkg.tar
new file mode 100644
index 0000000..9dd165e
--- /dev/null
+++ b/slider-core/src/test/app_packages/test_command_log/cmd_log_app_pkg.tar
Binary files differ
diff --git a/slider-core/src/test/app_packages/test_command_log/package/scripts/cl.py b/slider-core/src/test/app_packages/test_command_log/package/scripts/cl.py
index 4b7b91b..6b18faa 100644
--- a/slider-core/src/test/app_packages/test_command_log/package/scripts/cl.py
+++ b/slider-core/src/test/app_packages/test_command_log/package/scripts/cl.py
@@ -25,7 +25,7 @@
 from resource_management.core.base import Fail
 
 
-class HbaseMaster(Script):
+class CommandLogger(Script):
   def install(self, env):
     self.install_packages(env)
 
@@ -51,10 +51,7 @@
     self.rename_file(env)
 
   def status(self, env):
-    import params
-
-    env.set_params(params)
-    self.check_and_log(env, "Status check.")
+    Logger.info("Returning status as live.")
 
   def check_and_log(self, env, message):
     import params
@@ -89,4 +86,4 @@
     )
 
 if __name__ == "__main__":
-  HbaseMaster().execute()
+  CommandLogger().execute()
diff --git a/slider-core/src/test/app_packages/test_command_log/package/scripts/params.py b/slider-core/src/test/app_packages/test_command_log/package/scripts/params.py
index af200c1..3d388ae 100644
--- a/slider-core/src/test/app_packages/test_command_log/package/scripts/params.py
+++ b/slider-core/src/test/app_packages/test_command_log/package/scripts/params.py
@@ -23,7 +23,7 @@
 # server configurations
 config = Script.get_config()
 
-container_id = config['configurations']['global']['container_id']
+container_id = config['hostLevelParams']['container_id']
 application_id = config['configurations']['global']['application_id']
 app_user = config['configurations']['global']['app_user']
 
diff --git a/slider-core/src/test/app_packages/test_command_log/resources.json b/slider-core/src/test/app_packages/test_command_log/resources.json
new file mode 100644
index 0000000..cc422df
--- /dev/null
+++ b/slider-core/src/test/app_packages/test_command_log/resources.json
@@ -0,0 +1,15 @@
+{
+    "schema": "http://example.org/specification/v2.0.0",
+    "metadata": {
+    },
+    "global": {
+    },
+    "components": {
+        "COMMAND_LOGGER": {
+            "role.priority": "1",
+            "component.instances": "1"
+        },
+        "slider-appmaster": {
+        }
+    }
+}
diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/AgentProviderServiceTest.java b/slider-core/src/test/java/org/apache/slider/providers/agent/AgentProviderServiceTest.java
index bbc7115..d6cdb9c 100644
--- a/slider-core/src/test/java/org/apache/slider/providers/agent/AgentProviderServiceTest.java
+++ b/slider-core/src/test/java/org/apache/slider/providers/agent/AgentProviderServiceTest.java
@@ -106,6 +106,7 @@
     try {
       doNothing().when(mockAps).addInstallCommand(
           eq("HBASE_MASTER"),
+          eq("mockcontainer_1"),
           any(HeartBeatResponse.class),
           eq("scripts/hbase_master.py"));
     } catch (SliderException e) {
diff --git a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy
index 615cbde..d6b077e 100644
--- a/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy
+++ b/slider-funtest/src/main/groovy/org/apache/slider/funtest/framework/CommandTestBase.groovy
@@ -40,8 +40,8 @@
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import static org.apache.slider.common.SliderExitCodes.*
-import static FuntestProperties.*
-import static Arguments.*
+import static org.apache.slider.funtest.framework.FuntestProperties.*
+import static org.apache.slider.common.params.Arguments.*
 import static org.apache.slider.common.params.SliderActions.*
 import static org.apache.slider.common.SliderXMLConfKeysForTesting.*
 
@@ -71,6 +71,7 @@
 
   public static final boolean FUNTESTS_ENABLED
   public static final boolean AGENTTESTS_ENABLED
+  public static final String AGENT_PKG
 
 
   static {
@@ -93,7 +94,9 @@
         SLIDER_CONFIG.getBoolean(KEY_TEST_ACCUMULO_ENABLED, false)
 
     AGENTTESTS_ENABLED =
-        SLIDER_CONFIG.getBoolean(KEY_TEST_AGENT_ENABLED, true)
+      SLIDER_CONFIG.getBoolean(KEY_TEST_AGENT_ENABLED, true)
+    AGENT_PKG =
+      SLIDER_CONFIG.getRaw(KEY_TEST_AGENT_TAR)
  }
 
   @Rule
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/TestAppsThroughAgent.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/TestAppsThroughAgent.groovy
new file mode 100644
index 0000000..34c3a57
--- /dev/null
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/TestAppsThroughAgent.groovy
@@ -0,0 +1,187 @@
+/*
+ * 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.slider.funtest.lifecycle
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.slider.common.params.Arguments
+import org.apache.slider.common.params.SliderActions
+import org.apache.slider.funtest.framework.CommandTestBase
+import org.apache.slider.funtest.framework.SliderShell
+import org.junit.Test
+
+import static org.apache.slider.common.SliderExitCodes.EXIT_UNKNOWN_INSTANCE
+
+@CompileStatic
+@Slf4j
+public class TestAppsThroughAgent extends CommandTestBase {
+
+  private static String COMMAND_LOGGER = "COMMAND_LOGGER"
+  private static String APPLICATION_NAME = "agenttst"
+  private static String APP_RESOURCE = "../slider-core/src/test/app_packages/test_command_log/resources.json"
+  private static String APP_TEMPLATE = "../slider-core/src/test/app_packages/test_command_log/appConfig.json"
+
+  @Test
+  public void testUsage() throws Throwable {
+    SliderShell shell = slider(0, [SliderActions.ACTION_USAGE])
+    assertSuccess(shell)
+  }
+
+  @Test
+  public void testCreateFlexHBase() throws Throwable {
+    if (!AGENTTESTS_ENABLED) {
+      log.info "TESTS are not run."
+      return
+    }
+
+    cleanup()
+    try {
+      SliderShell shell = slider(0, [
+          SliderActions.ACTION_CREATE,
+          TestAppsThroughAgent.APPLICATION_NAME,
+          Arguments.ARG_IMAGE,
+          AGENT_PKG,
+          Arguments.ARG_TEMPLATE,
+          TestAppsThroughAgent.APP_TEMPLATE,
+          Arguments.ARG_RESOURCES,
+          TestAppsThroughAgent.APP_RESOURCE])
+
+      logShell(shell)
+
+      assertSuccess(shell)
+
+      int attemptCount = 0
+      while (attemptCount < 10) {
+        shell = slider(0, [
+            SliderActions.ACTION_LIST,
+            TestAppsThroughAgent.APPLICATION_NAME])
+
+        if (isAppRunning("RUNNING", shell)) {
+          break
+        }
+
+        attemptCount++
+        assert attemptCount != 10, 'Application did not start, aborting test.'
+
+        sleep(1000 * 5)
+      }
+
+      //flex
+      slider(0, [
+          SliderActions.ACTION_FLEX,
+          TestAppsThroughAgent.APPLICATION_NAME,
+          Arguments.ARG_COMPONENT,
+          COMMAND_LOGGER,
+          "2"])
+
+      // sleep till the new instance starts
+      sleep(1000 * 10)
+
+      shell = slider(0, [
+          SliderActions.ACTION_STATUS,
+          TestAppsThroughAgent.APPLICATION_NAME])
+
+      assertComponentCount(COMMAND_LOGGER, 2, shell)
+
+      shell = slider(0, [
+          SliderActions.ACTION_LIST,
+          TestAppsThroughAgent.APPLICATION_NAME])
+
+      assert isAppRunning("RUNNING", shell), 'App is not running.'
+
+      assertSuccess(shell)
+    } finally {
+      cleanup()
+    }
+  }
+
+  public void logShell(SliderShell shell) {
+    for (String str in shell.out) {
+      log.info str
+    }
+  }
+
+
+  public void assertComponentCount(String component, int count, SliderShell shell) {
+    log.info("Asserting component count.")
+    String entry = findLineEntry(shell, ["instances", component] as String[])
+    log.info(entry)
+    assert entry != null
+    int instanceCount = 0
+    int index = entry.indexOf("container_")
+    while (index != -1) {
+      instanceCount++;
+      index = entry.indexOf("container_", index + 1)
+    }
+
+    assert instanceCount == count, 'Instance count for component did not match expected. Parsed: ' + entry
+  }
+
+  public String findLineEntry(SliderShell shell, String[] locators) {
+    int index = 0;
+    for (String str in shell.out) {
+      if (str.contains("\"" + locators[index] + "\"")) {
+        if (locators.size() == index + 1) {
+          return str;
+        } else {
+          index++;
+        }
+      }
+    }
+
+    return null;
+  }
+
+  public boolean isAppRunning(String text, SliderShell shell) {
+    boolean exists = false
+    for (String str in shell.out) {
+      if (str.contains(text)) {
+        exists = true
+      }
+    }
+
+    return exists
+  }
+
+  public void cleanup() throws Throwable {
+    log.info "Cleaning app instance, if exists, by name " + TestAppsThroughAgent.APPLICATION_NAME
+    SliderShell shell = slider([
+        SliderActions.ACTION_FREEZE,
+        TestAppsThroughAgent.APPLICATION_NAME])
+
+    if (shell.ret != 0 && shell.ret != EXIT_UNKNOWN_INSTANCE) {
+      logShell(shell)
+      assert fail("Old cluster either should not exist or should get frozen.")
+    }
+
+    // sleep till the instance is frozen
+    sleep(1000 * 5)
+
+    shell = slider([
+        SliderActions.ACTION_DESTROY,
+        TestAppsThroughAgent.APPLICATION_NAME])
+
+    if (shell.ret != 0 && shell.ret != EXIT_UNKNOWN_INSTANCE) {
+      logShell(shell)
+      assert fail("Old cluster either should not exist or should get destroyed.")
+    }
+  }
+
+
+}
diff --git a/slider-providers/hbase/slider-hbase-provider/src/test/groovy/org/apache/slider/providers/hbase/minicluster/HBaseMiniClusterTestBase.groovy b/slider-providers/hbase/slider-hbase-provider/src/test/groovy/org/apache/slider/providers/hbase/minicluster/HBaseMiniClusterTestBase.groovy
index 9cedbc2..4fcdc65 100644
--- a/slider-providers/hbase/slider-hbase-provider/src/test/groovy/org/apache/slider/providers/hbase/minicluster/HBaseMiniClusterTestBase.groovy
+++ b/slider-providers/hbase/slider-hbase-provider/src/test/groovy/org/apache/slider/providers/hbase/minicluster/HBaseMiniClusterTestBase.groovy
@@ -35,7 +35,7 @@
 import static org.apache.slider.common.params.Arguments.*
 import static org.apache.slider.test.SliderTestUtils.*
 import static org.apache.slider.common.SliderXMLConfKeysForTesting.*
-import static HBaseKeys.*
+import static org.apache.slider.providers.hbase.HBaseKeys.*
 /**
  * test base for all hbase clusters
  */
diff --git a/src/test/clusters/remote/README.md b/src/test/clusters/remote/README.md
new file mode 100644
index 0000000..3ca34bd
--- /dev/null
+++ b/src/test/clusters/remote/README.md
@@ -0,0 +1,60 @@
+<!---
+  Licensed 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. See accompanying LICENSE file.
+-->
+  
+ # README
+ 
+This config is required for tests defined in **org.apache.slider.funtest.lifecycle**.
+
+**Test setup**
+
+Edit config file src/test/clusters/remote/slider/slider-client.xml and ensure that the host names are accurate for the test cluster.
+
+**User setup**
+
+Ensure that the user, running the test, is present on the cluster against which you are running the tests. The user must be a member of the hadoop group.
+
+E.g. adduser **testuser** -d /home/**testuser** -g hadoop -m
+
+**HDFS Setup**
+
+Set up various test folders and load the agent and app packages.
+
+Set up hdfs folders for slider and test user
+
+*  su hdfs
+*  hdfs dfs -mkdir /slider
+*  hdfs dfs -chown testuser:hdfs /slider
+*  hdfs dfs -mkdir /user/testuser
+*  hdfs dfs -chown testuser:hdfs /user/testuser
+
+Set up agent package and config
+
+*  su **testuser**
+*  hdfs dfs -mkdir /slider/agent
+*  hdfs dfs -mkdir /slider/agent/conf
+*  hdfs dfs -copyFromLocal <share>/slider-agent-0.23.0-SNAPSHOT.tar.gz /slider/agent
+*  hdfs dfs -copyFromLocal <share>agent.ini /slider/agent/conf
+
+Add app packages 
+
+*  hdfs dfs -copyFromLocal slider-core/src/test/app_packages/test_command_log/cmd_log_app_pkg.tar
+
+**Enable/Execute the tests**
+
+To enable the test ensure that *slider.test.agent.enabled* is set to *true*. The tests can be executed through the following mvn command executed at slider/slider-funtest.
+
+```
+mvn test -Dslider.conf.dir=../src/test/clusters/remote/slider -Dtest=TestAppsThroughAgent -DfailIfNoTests=false
+```
+ 
\ No newline at end of file
diff --git a/src/test/clusters/remote/slider/log4j.properties b/src/test/clusters/remote/slider/log4j.properties
new file mode 100644
index 0000000..300f682
--- /dev/null
+++ b/src/test/clusters/remote/slider/log4j.properties
@@ -0,0 +1,84 @@
+#
+# Licensed 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. See accompanying LICENSE file.
+#
+
+#
+# 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.
+#
+
+#   Licensed 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.
+# log4j configuration used during build and unit tests
+
+log4j.rootLogger=INFO,stdout
+log4j.threshhold=ALL
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+
+# log layout skips stack-trace creation operations by avoiding line numbers and method
+#log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} - %m%n
+
+# debug edition is much more expensive
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c{2} (%F:%M(%L)) - %m%n
+
+
+log4j.appender.subprocess=org.apache.log4j.ConsoleAppender
+log4j.appender.subprocess.layout=org.apache.log4j.PatternLayout
+log4j.appender.subprocess.layout.ConversionPattern=[%c{1}]: %m%n
+#log4j.logger.org.apache.hoya.yarn.appmaster.HoyaAppMaster.master=INFO,subprocess
+
+log4j.logger.org.apache.hoya=DEBUG
+
+# uncomment to debug service lifecycle issues
+#log4j.logger.org.apache.hadoop.yarn.service.launcher=DEBUG
+#log4j.logger.org.apache.hadoop.yarn.service=DEBUG
+
+# uncomment for YARN operations
+#log4j.logger.org.apache.hadoop.yarn.client=DEBUG
+
+# uncomment this to debug security problems
+#log4j.logger.org.apache.hadoop.security=DEBUG
+
+#crank back on some noise
+log4j.logger.org.apache.hadoop.util.NativeCodeLoader=ERROR
+log4j.logger.org.apache.hadoop.hdfs=WARN
+
+
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor=WARN
+log4j.logger.org.apache.hadoop.yarn.server.nodemanager.NodeStatusUpdaterImpl=WARN
+log4j.logger.org.apache.zookeeper=WARN
+
+
diff --git a/src/test/clusters/remote/slider/slider-client.xml b/src/test/clusters/remote/slider/slider-client.xml
new file mode 100644
index 0000000..e912239
--- /dev/null
+++ b/src/test/clusters/remote/slider/slider-client.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+  ~ Licensed 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. See accompanying LICENSE file.
+  -->
+<!--
+  Properties set here are picked up in the client.
+  They are not passed to the AM
+-->
+<configuration>
+
+  <property>
+    <name>yarn.application.classpath</name>
+    <value>
+      /etc/hadoop/conf,/usr/lib/hadoop/*,/usr/lib/hadoop/lib/*,/usr/lib/hadoop-hdfs/*,/usr/lib/hadoop-hdfs/lib/*,/usr/lib/hadoop-yarn/*,/usr/lib/hadoop-yarn/lib/*,/usr/lib/hadoop-mapreduce/*,/usr/lib/hadoop-mapreduce/lib/*
+    </value>
+  </property>
+
+  <property>
+    <name>slider.zookeeper.quorum</name>
+    <value>c6403.ambari.apache.org:2181</value>
+  </property>
+
+  <property>
+    <name>yarn.resourcemanager.address</name>
+    <value>c6403.ambari.apache.org:8050</value>
+  </property>
+
+  <property>
+    <name>yarn.resourcemanager.scheduler.address</name>
+    <value>c6403.ambari.apache.org:8030</value>
+  </property>
+
+  <property>
+    <name>fs.defaultFS</name>
+    <value>hdfs://c6403.ambari.apache.org:8020</value>
+  </property>
+
+  <property>
+    <name>slider.security.enabled</name>
+    <value>false</value>
+  </property>
+
+  <property>
+    <name>slider.test.agent.enabled</name>
+    <value>false</value>
+  </property>
+  
+  <property>
+    <name>slider.test.agent.tar</name>
+    <value>hdfs://c6403.ambari.apache.org:8020/slider/agent/slider-agent-0.23.0-SNAPSHOT.tar.gz</value>
+  </property>
+
+</configuration>