OSDN Git Service

parse instrumentation result bundles
authorGuang Zhu <guangzhu@android.com>
Thu, 17 Jun 2010 18:44:05 +0000 (11:44 -0700)
committerGuang Zhu <guangzhu@android.com>
Sat, 17 Jul 2010 01:24:26 +0000 (18:24 -0700)
During tests, there are per-instrumentation based results emmitted
as key-value pairs. Examples include performance tests and normal
tests in code coverage mode. Currently most of these are discarded
by InstrumentationResultParser, this change adds parsing function,
stores the key-value pairs in a map, and finally send it to
ITestRunListeners at the end of test run.

Change-Id: If04c5f8b10eeaca494a155ed6c4a25bf0d9d892c

ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/ITestRunListener.java
ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/InstrumentationResultParserTest.java
ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java

index b61a698..5bcc836 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.ddmlib.testrunner;
 
+import java.util.Map;
+
 /**
  * Receives event notifications during instrumentation test runs. 
  * Patterned after {@link junit.runner.TestRunListener}.
@@ -43,8 +45,9 @@ public interface ITestRunListener {
      * Reports end of test run.
      * 
      * @param elapsedTime device reported elapsed time, in milliseconds
+     * @param runMetrics key-value pairs reported at the end of a test run
      */
-    public void testRunEnded(long elapsedTime);
+    public void testRunEnded(long elapsedTime, Map<String, String> runMetrics);
 
     /**
      * Reports test run stopped before completion.
index ff49c44..c3399f0 100755 (executable)
@@ -22,6 +22,8 @@ import com.android.ddmlib.MultiLineReceiver;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Parses the 'raw output mode' results of an instrumentation test run from shell and informs a
@@ -156,6 +158,15 @@ public class InstrumentationResultParser extends MultiLineReceiver {
     /** The number of tests expected to run  */
     private int mNumTestsExpected = 0;
 
+    /** True if the parser is parsing a line beginning with "INSTRUMENTATION_RESULT" */
+    private boolean mInInstrumentationResultKey = false;
+
+    /**
+     * Stores key-value pairs under INSTRUMENTATION_RESULT header, these are printed at the
+     * end of a test run, if applicable
+     */
+    private Map<String, String> mInstrumentationResultBundle = new HashMap<String, String>();
+
     private static final String LOG_TAG = "InstrumentationResultParser";
 
     /** Error message supplied when no parseable test results are received from test run. */
@@ -216,19 +227,23 @@ public class InstrumentationResultParser extends MultiLineReceiver {
         if (line.startsWith(Prefixes.STATUS_CODE)) {
             // Previous status key-value has been collected. Store it.
             submitCurrentKeyValue();
+            mInInstrumentationResultKey = false;
             parseStatusCode(line);
         } else if (line.startsWith(Prefixes.STATUS)) {
             // Previous status key-value has been collected. Store it.
             submitCurrentKeyValue();
+            mInInstrumentationResultKey = false;
             parseKey(line, Prefixes.STATUS.length());
         } else if (line.startsWith(Prefixes.RESULT)) {
             // Previous status key-value has been collected. Store it.
             submitCurrentKeyValue();
+            mInInstrumentationResultKey = true;
             parseKey(line, Prefixes.RESULT.length());
         } else if (line.startsWith(Prefixes.STATUS_FAILED) ||
                    line.startsWith(Prefixes.CODE)) {
             // Previous status key-value has been collected. Store it.
             submitCurrentKeyValue();
+            mInInstrumentationResultKey = false;
             // these codes signal the end of the instrumentation run
             mTestRunFinished = true;
             // just ignore the remaining data on this line
@@ -250,25 +265,34 @@ public class InstrumentationResultParser extends MultiLineReceiver {
      */
     private void submitCurrentKeyValue() {
         if (mCurrentKey != null && mCurrentValue != null) {
-            TestResult testInfo = getCurrentTestInfo();
-            String statusValue = mCurrentValue.toString();
-
-            if (mCurrentKey.equals(StatusKeys.CLASS)) {
-                testInfo.mTestClass = statusValue.trim();
-            } else if (mCurrentKey.equals(StatusKeys.TEST)) {
-                testInfo.mTestName = statusValue.trim();
-            } else if (mCurrentKey.equals(StatusKeys.NUMTESTS)) {
-                try {
-                    testInfo.mNumTests = Integer.parseInt(statusValue);
-                } catch (NumberFormatException e) {
-                    Log.e(LOG_TAG, "Unexpected integer number of tests, received " + statusValue);
+            if (mInInstrumentationResultKey) {
+                String statusValue = mCurrentValue.toString();
+                mInstrumentationResultBundle.put(mCurrentKey, statusValue);
+                if (mCurrentKey.equals(StatusKeys.SHORTMSG)) {
+                    // test run must have failed
+                    handleTestRunFailed(statusValue);
+                }
+            } else {
+                TestResult testInfo = getCurrentTestInfo();
+                String statusValue = mCurrentValue.toString();
+
+                if (mCurrentKey.equals(StatusKeys.CLASS)) {
+                    testInfo.mTestClass = statusValue.trim();
+                } else if (mCurrentKey.equals(StatusKeys.TEST)) {
+                    testInfo.mTestName = statusValue.trim();
+                } else if (mCurrentKey.equals(StatusKeys.NUMTESTS)) {
+                    try {
+                        testInfo.mNumTests = Integer.parseInt(statusValue);
+                    } catch (NumberFormatException e) {
+                        Log.e(LOG_TAG, "Unexpected integer number of tests, received "
+                                + statusValue);
+                    }
+                } else if (mCurrentKey.equals(StatusKeys.ERROR)) {
+                    // test run must have failed
+                    handleTestRunFailed(statusValue);
+                } else if (mCurrentKey.equals(StatusKeys.STACK)) {
+                    testInfo.mStackTrace = statusValue;
                 }
-            } else if (mCurrentKey.equals(StatusKeys.ERROR) ||
-                    mCurrentKey.equals(StatusKeys.SHORTMSG)) {
-                // test run must have failed
-                handleTestRunFailed(statusValue);
-            } else if (mCurrentKey.equals(StatusKeys.STACK)) {
-                testInfo.mStackTrace = statusValue;
             }
 
             mCurrentKey = null;
@@ -490,7 +514,7 @@ public class InstrumentationResultParser extends MultiLineReceiver {
                     // no tests
                     listener.testRunStarted(0);
                 }
-                listener.testRunEnded(mTestTime);
+                listener.testRunEnded(mTestTime, mInstrumentationResultBundle);
             }
         }
     }
index ed3a420..7a70518 100644 (file)
@@ -20,6 +20,8 @@ import com.android.ddmlib.testrunner.ITestRunListener.TestFailure;
 
 import junit.framework.TestCase;
 
+import java.util.Map;
+
 
 /**
  * Tests InstrumentationResultParser.
@@ -205,6 +207,24 @@ public class InstrumentationResultParserTest extends TestCase {
     }
 
     /**
+     * Test parsing of a test run that produces INSTRUMENTATION_RESULT output. This mimics launch
+     * performance test output.
+     */
+    public void testRunWithInstrumentationResults() {
+        StringBuilder output = new StringBuilder();
+        addResultKey(output, "other_pss", "2390");
+        addResultKey(output, "java_allocated", "2539");
+        addResultKey(output, "foo", "bar");
+        addLine(output, "INSTRUMENTATION_CODE: -1");
+
+        injectTestString(output.toString());
+
+        assertEquals("2390", mTestResult.mResultBundle.get("other_pss"));
+        assertEquals("2539", mTestResult.mResultBundle.get("java_allocated"));
+        assertEquals("bar", mTestResult.mResultBundle.get("foo"));
+    }
+
+    /**
      * Builds a common test result using TEST_NAME and TEST_CLASS.
      */
     private StringBuilder buildCommonResult() {
@@ -249,6 +269,18 @@ public class InstrumentationResultParserTest extends TestCase {
     }
 
     /**
+     * Helper method to add a result key value bundle.
+     */
+    private void addResultKey(StringBuilder outputBuilder, String key,
+          String value) {
+      outputBuilder.append("INSTRUMENTATION_RESULT: ");
+      outputBuilder.append(key);
+      outputBuilder.append('=');
+      outputBuilder.append(value);
+      addLineBreak(outputBuilder);
+    }
+
+    /**
      * Append a line to output.
      */
     private void addLine(StringBuilder outputBuilder, String lineContent) {
@@ -313,12 +345,14 @@ public class InstrumentationResultParserTest extends TestCase {
         boolean mStopped;
         /** stores the error message provided to testRunFailed */
         String mRunFailedMessage;
+        Map<String, String> mResultBundle;
 
         VerifyingTestResult() {
             mNumTestsRun = 0;
             mTestStatus = null;
             mStopped = false;
             mRunFailedMessage = null;
+            mResultBundle = null;
         }
 
         public void testEnded(TestIdentifier test) {
@@ -335,9 +369,9 @@ public class InstrumentationResultParserTest extends TestCase {
             assertEquals("Unexpected test ended", mTestName, test.getTestName());
         }
 
-        public void testRunEnded(long elapsedTime) {
+        public void testRunEnded(long elapsedTime, Map<String, String> resultBundle) {
             mTestTime = elapsedTime;
-
+            mResultBundle = resultBundle;
         }
 
         public void testRunStarted(int testCount) {
index 85b57aa..9d4e77b 100644 (file)
@@ -274,7 +274,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
             // ignore
         }
 
-        public void testRunEnded(long elapsedTime) {
+        public void testRunEnded(long elapsedTime, Map<String, String> resultBundle) {
             // ignore
         }