SLIDER-604 AppsThroughAgentIT to spin waiting for live instance count
diff --git a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
index 1b32471..8bf1959 100644
--- a/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/test/SliderTestUtils.groovy
@@ -478,8 +478,7 @@
   public static void assertContainersLive(ClusterDescription clusterDescription,
       String component, int expected) {
     log.info("Asserting component $component expected count $expected}",)
-    def instances = clusterDescription?.instances?.get(component)
-    int actual = instances != null ? instances.size() : 0
+    int actual = extractLiveContainerCount(clusterDescription, component)
     if (expected != actual) {
       log.warn(
           "$component actual=$actual, expected $expected in \n$clusterDescription")
@@ -488,6 +487,20 @@
   }
 
   /**
+   * Robust extraction of live container count
+   * @param clusterDescription status
+   * @param component component to resolve
+   * @return the number of containers live.
+   */
+  public static int extractLiveContainerCount(
+      ClusterDescription clusterDescription,
+      String component) {
+    def instances = clusterDescription?.instances?.get(component)
+    int actual = instances != null ? instances.size() : 0
+    return actual
+  }
+
+  /**
    * Execute a closure, assert it fails with a given exit code and text
    * @param exitCode exit code
    * @param text text (can be "")
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 f14e9f1..640deaf 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
@@ -1084,15 +1084,60 @@
       ClusterDescription cd = execStatus(application);
       log.info("Parsed status \n$cd")
       fail(message)
-    };
-
+    }
   }
 
-  public ClusterDescription expectContainersLive(String clustername,
+  public ClusterDescription assertContainersLive(String clustername,
       String component,
       int count) {
     ClusterDescription cd = execStatus(clustername)
     assertContainersLive(cd, component, count)
     return cd;
   }
+
+  /**
+   * Outcome checker for the live container count
+   * @param args argument map, must contain "application", "component" and "live"
+   * @return
+   */
+  Outcome hasLiveContainerCountReached(Map<String, String> args) {
+    assert args['application']
+    assert args['component']
+    assert args['live']
+    String application = args['application']
+    String component = args['component']
+    int expectedCount = args['live'].toInteger();
+    ClusterDescription cd = execStatus(application)
+    def actual = extractLiveContainerCount(cd, component)
+    log.debug(
+        "live $component count = $actual; expected=$expectedCount")
+    return Outcome.fromBool(actual >= expectedCount)
+  }
+
+  /**
+   * Wait for the live container count to be reached
+   * @param application application name
+   * @param component component name
+   * @param expected expected count
+   * @param container_launch_timeout launch timeout
+   */
+  void expectLiveContainerCountReached(
+      String application,
+      String component,
+      int expected,
+      int container_launch_timeout) {
+
+    repeatUntilSuccess(
+        this.&hasLiveContainerCountReached,
+        container_launch_timeout,
+        PROBE_SLEEP_TIME,
+        [live      : Integer.toString(expected),
+         component  : component,
+         application: application],
+        true,
+        "countainer count not reached") {
+      describe "container count not reached"
+      assertContainersLive(application, component, expected)
+    }
+  }
 }
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMFailuresIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMFailuresIT.groovy
index 7cc01b8..a78ae87 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMFailuresIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMFailuresIT.groovy
@@ -76,7 +76,7 @@
     // Wait for 20 secs for AM and agent to both reach STARTED state
     sleep(1000 * 20)
 
-    def cd = expectContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
+    def cd = assertContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
     def loggerInstances = cd.instances[COMMAND_LOGGER]
     assert loggerInstances.size() == 1
 
@@ -104,7 +104,7 @@
     ensureYarnApplicationIsUp(appId)
 
     // There should be exactly 1 live logger container
-    def cd2 = expectContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
+    def cd2 = assertContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
 
     // No new containers should be requested for the agents
     def loggerStats2 = cd2.statistics[COMMAND_LOGGER]
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy
index efd6194..a6930b2 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AgentFailuresIT.groovy
@@ -20,7 +20,6 @@
 
 import groovy.transform.CompileStatic
 import groovy.util.logging.Slf4j
-import org.apache.hadoop.yarn.api.records.YarnApplicationState
 import org.apache.slider.common.SliderExitCodes
 import org.apache.slider.common.params.Arguments
 import org.apache.slider.common.params.SliderActions
@@ -67,7 +66,7 @@
         CONTAINER_LAUNCH_TIMEOUT)
     sleep(1000 * 20)
     assertAppRunning(appId)
-    def cd = expectContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
+    def cd = assertContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
     assert cd.statistics[COMMAND_LOGGER]["containers.requested"] >= 2
     assertAppRunning(appId)
   }
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
index 5be7211..1d65ce7 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentDemo.groovy
@@ -26,7 +26,6 @@
 import org.apache.slider.funtest.framework.AgentCommandTestBase
 import org.apache.slider.funtest.framework.FuntestProperties
 import org.apache.slider.funtest.framework.SliderShell
-import org.junit.After
 import org.junit.Before
 import org.junit.Test
 
@@ -77,7 +76,7 @@
         [ACTION_STATUS,
             APPLICATION_NAME])
 
-    expectContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 2)
+    assertContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 2)
 
     String amWebUrl = getInfoAmWebUrl(APPLICATION_NAME)
     log.info("Dumping data from AM Web URL");
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
index 75807c3..5cd6dc5 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentIT.groovy
@@ -76,8 +76,8 @@
     sleep(1000 * 10)
 
     status(0, APPLICATION_NAME)
-
-    expectContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 2)
+    expectLiveContainerCountReached(APPLICATION_NAME, COMMAND_LOGGER, 2,
+        CONTAINER_LAUNCH_TIMEOUT)
 
     String amWebUrl = getInfoAmWebUrl(APPLICATION_NAME)
     log.info("Dumping data from AM Web URL");
diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
index f6a1b1e..51bb440 100644
--- a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
+++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AppsThroughAgentQueueAndLabelsIT.groovy
@@ -94,7 +94,7 @@
 
     expectContainerRequestedCountReached(APPLICATION_NAME, COMMAND_LOGGER, 1,
         CONTAINER_LAUNCH_TIMEOUT)
-    expectContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
+    assertContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1)
 
     //flex
     slider(EXIT_SUCCESS,