SLIDER-596 add processing for USER_NAME token to slider client
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 0e87906..d9100e4 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
@@ -960,6 +960,7 @@
   private static String replaceTokens(String s, String userName,
       String clusterName) throws IOException {
     return s.replaceAll(Pattern.quote("${USER}"), userName)
+        .replaceAll(Pattern.quote("${USER_NAME}"), userName)
         .replaceAll(Pattern.quote("${CLUSTER_NAME}"), clusterName);
   }
 
diff --git a/slider-core/src/test/groovy/org/apache/slider/client/TestClientBasicArgs.groovy b/slider-core/src/test/groovy/org/apache/slider/client/TestClientBasicArgs.groovy
index d1e86a1..23c1ffa 100644
--- a/slider-core/src/test/groovy/org/apache/slider/client/TestClientBasicArgs.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/client/TestClientBasicArgs.groovy
@@ -55,8 +55,6 @@
                                         [])
   }
 
-  // removed due to retry policy dicating 15 minutes of retries for the
-  // generated UnknownHostExceptionj
   @Test
   public void testListUnknownRM() throws Throwable {
     try {
diff --git a/slider-core/src/test/groovy/org/apache/slider/client/TestReplaceTokens.groovy b/slider-core/src/test/groovy/org/apache/slider/client/TestReplaceTokens.groovy
new file mode 100644
index 0000000..c4c755d
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/client/TestReplaceTokens.groovy
@@ -0,0 +1,62 @@
+/*
+ * 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.client
+
+import org.apache.hadoop.yarn.conf.YarnConfiguration
+import org.apache.slider.common.params.Arguments
+import org.apache.slider.common.params.ClientArgs
+import org.apache.slider.common.tools.SliderUtils
+import org.apache.slider.core.conf.ConfTree
+import org.apache.slider.core.main.ServiceLauncher
+import org.apache.slider.core.main.ServiceLauncherBaseTest
+import org.apache.slider.core.persist.ConfTreeSerDeser
+import org.apache.slider.core.persist.JsonSerDeser
+import org.junit.Assert
+import org.junit.Test
+
+/**
+ * Test bad argument handling
+ */
+//@CompileStatic
+class TestReplaceTokens extends Assert {
+
+  static final String PACKAGE = "/org/apache/slider/core/conf/examples/"
+  static final String app_configuration = "app_configuration_tokenized.json"
+  static final String app_configuration_processed =
+    "app_configuration_processed.json"
+
+  /**
+   * help should print out help string and then succeed
+   * @throws Throwable
+   */
+  @Test
+  public void testHelp() throws Throwable {
+    JsonSerDeser<ConfTree> confTreeJsonSerDeser =
+      new JsonSerDeser<ConfTree>(ConfTree)
+    def confTree = confTreeJsonSerDeser.fromResource(PACKAGE + app_configuration)
+    SliderClient.replaceTokens(confTree, "testUser", "testCluster")
+    assert confTree.global.get("site.fs.defaultFS") == "hdfs://testCluster:8020"
+    assert confTree.global.get("site.fs.default.name") == "hdfs://testCluster:8020"
+    assert confTree.global.get("site.hbase.user_name") == "testUser"
+    assert confTree.global.get("site.hbase.another.user") == "testUser"
+
+
+  }
+  
+}
diff --git a/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration_tokenized.json b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration_tokenized.json
new file mode 100644
index 0000000..b902469
--- /dev/null
+++ b/slider-core/src/test/resources/org/apache/slider/core/conf/examples/app_configuration_tokenized.json
@@ -0,0 +1,27 @@
+{
+  "schema": "http://example.org/specification/v2.0.0",
+
+  "global": {
+
+    "zookeeper.port": "2181",
+    "zookeeper.path": "/yarnapps_small_cluster",
+    "zookeeper.hosts": "zoo1,zoo2,zoo3",
+    "env.MALLOC_ARENA_MAX": "4",
+    "site.hbase.master.startup.retainassign": "true",
+    "site.fs.defaultFS": "hdfs://${CLUSTER_NAME}:8020",
+    "site.fs.default.name": "hdfs://${CLUSTER_NAME}:8020",
+    "site.hbase.master.info.port": "0",
+    "site.hbase.regionserver.info.port": "0",
+    "site.hbase.user_name": "${USER}",
+    "site.hbase.another.user": "${USER_NAME}"
+  },
+  "components": {
+
+    "worker": {
+      "jvm.heapsize": "512M"
+    },
+    "master": {
+      "jvm.heapsize": "512M"
+    }
+  }
+}
\ No newline at end of file