Handle DeviceNotAvailableException in JarHostTest.

Bug 5497983

Change-Id: I998ddcd23368225275bac6b98a55aad09a1058cf
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 37a61d1..5f38ed8 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -522,7 +522,7 @@
         if (!mutualExclusiveArgs) {
             throw new IllegalArgumentException(String.format(
                     "Ambiguous or missing arguments. " +
-                    "One and only of --%s --%s(s), --%s or %s to run can be specified",
+                    "One and only of --%s --%s(s), --%s or --%s to run can be specified",
                     PLAN_OPTION, PACKAGE_OPTION, CLASS_OPTION, CONTINUE_OPTION));
         }
         if (mMethodName != null && mClassName == null) {
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
index eed5223..110bc98 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
@@ -22,30 +22,30 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.result.JUnitToInvocationResultForwarder;
+import com.android.tradefed.testtype.DeviceTestResult.RuntimeDeviceNotAvailableException;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IDeviceTest;
 import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.JUnitRunUtil;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.IRunUtil.IRunnableResult;
 import com.android.tradefed.util.RunUtil;
 
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.Collection;
-import java.util.Collections;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestResult;
 
 /**
  * A {@link IRemoteTest} that can run a set of JUnit tests from a CTS jar.
  */
-public class JarHostTest implements IDeviceTest, IRemoteTest, IBuildReceiver {
+public class JarHostTest implements IDeviceTest, IRemoteTest, IBuildReceiver, Test {
 
     private static final String LOG_TAG = "JarHostTest";
 
@@ -166,21 +166,20 @@
         checkFields();
         Log.i(LOG_TAG, String.format("Running %s test package from jar, contains %d tests.",
                 mRunName, mTests.size()));
-        // create a junit listener to forward the JUnit test results to the
-        // {@link ITestInvocationListener}s
-        JUnitToInvocationResultForwarder resultForwarder =
-                new JUnitToInvocationResultForwarder(listener);
-        TestResult junitResult = new TestResult();
-        junitResult.addListener(resultForwarder);
-        long startTime = System.currentTimeMillis();
-        listener.testRunStarted(mRunName, mTests.size());
+        JUnitRunUtil.runTest(listener, this, mRunName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void run(TestResult junitResult) {
         for (TestIdentifier testId : mTests) {
             Test junitTest = loadTest(testId.getClassName(), testId.getTestName());
             if (junitTest != null) {
                 runTest(testId, junitTest, junitResult);
             }
         }
-        listener.testRunEnded(System.currentTimeMillis() - startTime, Collections.EMPTY_MAP);
     }
 
     /**
@@ -196,23 +195,53 @@
             deviceTest.setDevice(getDevice().getIDevice());
             deviceTest.setTestAppPath(mCtsBuild.getTestCasesDir().getAbsolutePath());
         }
-        CommandStatus status = RunUtil.getDefault().runTimed(mTimeoutMs, new IRunnableResult() {
+        TestRunnable testRunnable = new TestRunnable(junitTest, junitResult);
 
-            @Override
-            public boolean run() throws Exception {
-                junitTest.run(junitResult);
-                return true;
-            }
-
-            @Override
-            public void cancel() {
-                // ignore
-            }
-        }, true);
+        CommandStatus status = RunUtil.getDefault().runTimed(mTimeoutMs, testRunnable, true);
         if (status.equals(CommandStatus.TIMED_OUT)) {
             junitResult.addError(junitTest, new TestTimeoutException());
             junitResult.endTest(junitTest);
         }
+        if (testRunnable.getException() != null) {
+            throw testRunnable.getException();
+        }
+    }
+
+    private static class TestRunnable implements IRunnableResult {
+
+        private final Test mJunitTest;
+        private RuntimeDeviceNotAvailableException mException = null;
+        private TestResult mJunitResult;
+
+        TestRunnable(Test junitTest, TestResult junitResult) {
+            mJunitTest = junitTest;
+            mJunitResult = junitResult;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean run() throws Exception {
+            try {
+                mJunitTest.run(mJunitResult);
+            } catch (RuntimeDeviceNotAvailableException e) {
+                mException = e;
+            }
+            return true;
+        }
+
+        public RuntimeDeviceNotAvailableException getException() {
+            return mException;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void cancel() {
+        }
+
     }
 
     /**
@@ -300,4 +329,12 @@
                     mCtsBuild.getRootDir().getAbsolutePath()));
         }
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int countTestCases() {
+        return mTests.size();
+    }
 }