aboutsummaryrefslogtreecommitdiffstats
path: root/ddms/libs/ddmlib/src/com
diff options
context:
space:
mode:
authorBrett Chabot <brettchabot@android.com>2010-03-02 10:53:37 -0800
committerBrett Chabot <brettchabot@android.com>2010-03-04 18:04:28 -0800
commitb98892c6797a275e2bfbcb969c89d760591e4b90 (patch)
tree7d3ff09a5517d352dd8e6b77ad23bbbdec66c48c /ddms/libs/ddmlib/src/com
parent91ed8175993fb6eca29e5281bf3f7f5b7a3b3ded (diff)
downloadsdk-b98892c6797a275e2bfbcb969c89d760591e4b90.zip
sdk-b98892c6797a275e2bfbcb969c89d760591e4b90.tar.gz
sdk-b98892c6797a275e2bfbcb969c89d760591e4b90.tar.bz2
Add ability to detect incomplete test runs to InstrumentationResultParser.
And clean-up whitespace. Change-Id: Icb6bd5c8bf403fda0de436d4b9e732e7ea976267
Diffstat (limited to 'ddms/libs/ddmlib/src/com')
-rwxr-xr-xddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java178
-rw-r--r--ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java32
2 files changed, 121 insertions, 89 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
index 1a0b21f..30c72a5 100755
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
@@ -21,25 +21,25 @@ import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
/**
- * Parses the 'raw output mode' results of an instrumentation test run from shell and informs a
+ * Parses the 'raw output mode' results of an instrumentation test run from shell and informs a
* ITestRunListener of the results.
- *
+ *
* <p>Expects the following output:
- *
+ *
* <p>If fatal error occurred when attempted to run the tests:
* <pre>
* INSTRUMENTATION_STATUS: Error=error Message
- * INSTRUMENTATION_FAILED:
+ * INSTRUMENTATION_FAILED:
* </pre>
* <p>or
* <pre>
* INSTRUMENTATION_RESULT: shortMsg=error Message
* </pre>
- *
+ *
* <p>Otherwise, expect a series of test results, each one containing a set of status key/value
- * pairs, delimited by a start(1)/pass(0)/fail(-2)/error(-1) status code result. At end of test
- * run, expects that the elapsed test time in seconds will be displayed
- *
+ * pairs, delimited by a start(1)/pass(0)/fail(-2)/error(-1) status code result. At end of test
+ * run, expects that the elapsed test time in seconds will be displayed
+ *
* <p>For example:
* <pre>
* INSTRUMENTATION_STATUS_CODE: 1
@@ -48,15 +48,15 @@ import com.android.ddmlib.MultiLineReceiver;
* INSTRUMENTATION_STATUS: numtests=2
* INSTRUMENTATION_STATUS: stack=com.foo.FooTest#testFoo:312
* com.foo.X
- * INSTRUMENTATION_STATUS_CODE: -2
- * ...
- *
+ * INSTRUMENTATION_STATUS_CODE: -2
+ * ...
+ *
* Time: X
* </pre>
* <p>Note that the "value" portion of the key-value pair may wrap over several text lines
*/
public class InstrumentationResultParser extends MultiLineReceiver {
-
+
/** Relevant test status keys. */
private static class StatusKeys {
private static final String TEST = "test";
@@ -66,7 +66,7 @@ public class InstrumentationResultParser extends MultiLineReceiver {
private static final String ERROR = "Error";
private static final String SHORTMSG = "shortMsg";
}
-
+
/** Test result status codes. */
private static class StatusCodes {
private static final int FAILURE = -2;
@@ -84,10 +84,10 @@ public class InstrumentationResultParser extends MultiLineReceiver {
private static final String RESULT = "INSTRUMENTATION_RESULT: ";
private static final String TIME_REPORT = "Time: ";
}
-
+
private final ITestRunListener mTestListener;
- /**
+ /**
* Test result data
*/
private static class TestResult {
@@ -96,12 +96,12 @@ public class InstrumentationResultParser extends MultiLineReceiver {
private String mTestClass = null;
private String mStackTrace = null;
private Integer mNumTests = null;
-
+
/** Returns true if all expected values have been parsed */
boolean isComplete() {
return mCode != null && mTestName != null && mTestClass != null;
}
-
+
/** Provides a more user readable string for TestResult, if possible */
@Override
public String toString() {
@@ -109,49 +109,58 @@ public class InstrumentationResultParser extends MultiLineReceiver {
if (mTestClass != null ) {
output.append(mTestClass);
output.append('#');
- }
+ }
if (mTestName != null) {
output.append(mTestName);
}
if (output.length() > 0) {
return output.toString();
- }
+ }
return "unknown result";
}
}
-
+
/** Stores the status values for the test result currently being parsed */
private TestResult mCurrentTestResult = null;
-
+
/** Stores the current "key" portion of the status key-value being parsed. */
private String mCurrentKey = null;
-
+
/** Stores the current "value" portion of the status key-value being parsed. */
private StringBuilder mCurrentValue = null;
-
+
/** True if start of test has already been reported to listener. */
private boolean mTestStartReported = false;
-
+
+ /** True if test run failure has already been reported to listener. */
+ private boolean mTestRunFailReported = false;
+
/** The elapsed time of the test run, in milliseconds. */
private long mTestTime = 0;
-
+
/** True if current test run has been canceled by user. */
private boolean mIsCancelled = false;
-
+
+ /** The number of tests currently run */
+ private int mNumTestsRun = 0;
+
+ /** The number of tests expected to run */
+ private int mNumTestsExpected = 0;
+
private static final String LOG_TAG = "InstrumentationResultParser";
-
+
/**
* Creates the InstrumentationResultParser.
- *
+ *
* @param listener informed of test results as the tests are executing
*/
public InstrumentationResultParser(ITestRunListener listener) {
mTestListener = listener;
}
-
+
/**
* Processes the instrumentation test output from shell.
- *
+ *
* @see MultiLineReceiver#processNewLines
*/
@Override
@@ -162,23 +171,23 @@ public class InstrumentationResultParser extends MultiLineReceiver {
Log.v(LOG_TAG, line);
}
}
-
+
/**
* Parse an individual output line. Expects a line that is one of:
* <ul>
- * <li>
- * The start of a new status line (starts with Prefixes.STATUS or Prefixes.STATUS_CODE),
- * and thus there is a new key=value pair to parse, and the previous key-value pair is
- * finished.
+ * <li>
+ * The start of a new status line (starts with Prefixes.STATUS or Prefixes.STATUS_CODE),
+ * and thus there is a new key=value pair to parse, and the previous key-value pair is
+ * finished.
* </li>
* <li>
* A continuation of the previous status (the "value" portion of the key has wrapped
* to the next line).
- * </li>
+ * </li>
* <li> A line reporting a fatal error in the test run (Prefixes.STATUS_FAILED) </li>
- * <li> A line reporting the total elapsed time of the test run. (Prefixes.TIME_REPORT) </li>
+ * <li> A line reporting the total elapsed time of the test run. (Prefixes.TIME_REPORT) </li>
* </ul>
- *
+ *
* @param line Text output line
*/
private void parse(String line) {
@@ -193,25 +202,25 @@ public class InstrumentationResultParser extends MultiLineReceiver {
} else if (line.startsWith(Prefixes.RESULT)) {
// Previous status key-value has been collected. Store it.
submitCurrentKeyValue();
- parseKey(line, Prefixes.RESULT.length());
- } else if (line.startsWith(Prefixes.STATUS_FAILED) ||
+ 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();
- // just ignore the remaining data on this line
+ // just ignore the remaining data on this line
} else if (line.startsWith(Prefixes.TIME_REPORT)) {
parseTime(line, Prefixes.TIME_REPORT.length());
} else {
if (mCurrentValue != null) {
- // this is a value that has wrapped to next line.
+ // this is a value that has wrapped to next line.
mCurrentValue.append("\r\n");
mCurrentValue.append(line);
} else {
- Log.w(LOG_TAG, "unrecognized line " + line);
+ Log.i(LOG_TAG, "unrecognized line " + line);
}
}
}
-
+
/**
* Stores the currently parsed key-value pair into mCurrentTestInfo.
*/
@@ -230,10 +239,10 @@ public class InstrumentationResultParser extends MultiLineReceiver {
} catch (NumberFormatException e) {
Log.e(LOG_TAG, "Unexpected integer number of tests, received " + statusValue);
}
- } else if (mCurrentKey.equals(StatusKeys.ERROR) ||
+ } else if (mCurrentKey.equals(StatusKeys.ERROR) ||
mCurrentKey.equals(StatusKeys.SHORTMSG)) {
// test run must have failed
- handleTestRunFailed(statusValue);
+ handleTestRunFailed(statusValue);
} else if (mCurrentKey.equals(StatusKeys.STACK)) {
testInfo.mStackTrace = statusValue;
}
@@ -242,23 +251,23 @@ public class InstrumentationResultParser extends MultiLineReceiver {
mCurrentValue = null;
}
}
-
+
private TestResult getCurrentTestInfo() {
if (mCurrentTestResult == null) {
mCurrentTestResult = new TestResult();
}
return mCurrentTestResult;
}
-
+
private void clearCurrentTestInfo() {
mCurrentTestResult = null;
}
-
+
/**
* Parses the key from the current line.
* Expects format of "key=value".
- *
- * @param line full line of text to parse
+ *
+ * @param line full line of text to parse
* @param keyStartPos the starting position of the key in the given line
*/
private void parseKey(String line, int keyStartPos) {
@@ -268,55 +277,55 @@ public class InstrumentationResultParser extends MultiLineReceiver {
parseValue(line, endKeyPos + 1);
}
}
-
+
/**
* Parses the start of a key=value pair.
- *
- * @param line - full line of text to parse
+ *
+ * @param line - full line of text to parse
* @param valueStartPos - the starting position of the value in the given line
*/
private void parseValue(String line, int valueStartPos) {
mCurrentValue = new StringBuilder();
mCurrentValue.append(line.substring(valueStartPos));
}
-
+
/**
- * Parses out a status code result.
+ * Parses out a status code result.
*/
private void parseStatusCode(String line) {
String value = line.substring(Prefixes.STATUS_CODE.length()).trim();
TestResult testInfo = getCurrentTestInfo();
try {
- testInfo.mCode = Integer.parseInt(value);
+ testInfo.mCode = Integer.parseInt(value);
} catch (NumberFormatException e) {
Log.e(LOG_TAG, "Expected integer status code, received: " + value);
}
-
+
// this means we're done with current test result bundle
reportResult(testInfo);
clearCurrentTestInfo();
}
-
+
/**
* Returns true if test run canceled.
- *
+ *
* @see IShellOutputReceiver#isCancelled()
*/
public boolean isCancelled() {
return mIsCancelled;
}
-
+
/**
* Requests cancellation of test run.
*/
public void cancel() {
mIsCancelled = true;
}
-
+
/**
* Reports a test result to the test run listener. Must be called when a individual test
- * result has been fully parsed.
- *
+ * result has been fully parsed.
+ *
* @param statusMap key-value status pairs of test result
*/
private void reportResult(TestResult testInfo) {
@@ -332,52 +341,57 @@ public class InstrumentationResultParser extends MultiLineReceiver {
mTestListener.testStarted(testId);
break;
case StatusCodes.FAILURE:
- mTestListener.testFailed(ITestRunListener.TestFailure.FAILURE, testId,
+ mTestListener.testFailed(ITestRunListener.TestFailure.FAILURE, testId,
getTrace(testInfo));
mTestListener.testEnded(testId);
+ mNumTestsRun++;
break;
case StatusCodes.ERROR:
- mTestListener.testFailed(ITestRunListener.TestFailure.ERROR, testId,
+ mTestListener.testFailed(ITestRunListener.TestFailure.ERROR, testId,
getTrace(testInfo));
mTestListener.testEnded(testId);
+ mNumTestsRun++;
break;
case StatusCodes.OK:
mTestListener.testEnded(testId);
+ mNumTestsRun++;
break;
default:
Log.e(LOG_TAG, "Unknown status code received: " + testInfo.mCode);
mTestListener.testEnded(testId);
+ mNumTestsRun++;
break;
}
}
-
+
/**
- * Reports the start of a test run, and the total test count, if it has not been previously
+ * Reports the start of a test run, and the total test count, if it has not been previously
* reported.
- *
+ *
* @param testInfo current test status values
*/
private void reportTestRunStarted(TestResult testInfo) {
// if start test run not reported yet
if (!mTestStartReported && testInfo.mNumTests != null) {
mTestListener.testRunStarted(testInfo.mNumTests);
+ mNumTestsExpected = testInfo.mNumTests;
mTestStartReported = true;
}
}
-
+
/**
* Returns the stack trace of the current failed test, from the provided testInfo.
*/
private String getTrace(TestResult testInfo) {
if (testInfo.mStackTrace != null) {
- return testInfo.mStackTrace;
+ return testInfo.mStackTrace;
} else {
Log.e(LOG_TAG, "Could not find stack trace for failed test ");
return new Throwable("Unknown failure").toString();
}
}
-
+
/**
* Parses out and store the elapsed time.
*/
@@ -385,25 +399,35 @@ public class InstrumentationResultParser extends MultiLineReceiver {
String timeString = line.substring(startPos);
try {
float timeSeconds = Float.parseFloat(timeString);
- mTestTime = (long) (timeSeconds * 1000);
+ mTestTime = (long) (timeSeconds * 1000);
} catch (NumberFormatException e) {
Log.e(LOG_TAG, "Unexpected time format " + timeString);
}
}
-
+
/**
* Process a instrumentation run failure
*/
private void handleTestRunFailed(String errorMsg) {
+ Log.i(LOG_TAG, String.format("test run failed %s", errorMsg));
mTestListener.testRunFailed(errorMsg == null ? "Unknown error" : errorMsg);
+ mTestRunFailReported = true;
}
-
+
/**
- * Called by parent when adb session is complete.
+ * Called by parent when adb session is complete.
*/
@Override
public void done() {
super.done();
- mTestListener.testRunEnded(mTestTime);
+ if (!mTestRunFailReported && mNumTestsExpected > mNumTestsRun) {
+ final String message =
+ String.format("Test run incomplete. Expected %d tests, received %d",
+ mNumTestsExpected, mNumTestsRun);
+ Log.w(LOG_TAG, message);
+ mTestListener.testRunFailed(message);
+ } else {
+ mTestListener.testRunEnded(mTestTime);
+ }
}
}
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java
index 4d3b108..f0cf4c8 100644
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/TestIdentifier.java
@@ -17,44 +17,44 @@
package com.android.ddmlib.testrunner;
/**
- * Identifies a parsed instrumentation test
+ * Identifies a parsed instrumentation test.
*/
public class TestIdentifier {
private final String mClassName;
private final String mTestName;
-
+
/**
- * Creates a test identifier
- *
+ * Creates a test identifier.
+ *
* @param className fully qualified class name of the test. Cannot be null.
* @param testName name of the test. Cannot be null.
*/
public TestIdentifier(String className, String testName) {
if (className == null || testName == null) {
- throw new IllegalArgumentException("className and testName must " +
+ throw new IllegalArgumentException("className and testName must " +
"be non-null");
}
mClassName = className;
mTestName = testName;
}
-
+
/**
- * Returns the fully qualified class name of the test
+ * Returns the fully qualified class name of the test.
*/
public String getClassName() {
return mClassName;
}
/**
- * Returns the name of the test
+ * Returns the name of the test.
*/
public String getTestName() {
return mTestName;
}
-
+
/**
- * Tests equality by comparing class and method name
+ * Tests equality by comparing class and method name.
*/
@Override
public boolean equals(Object other) {
@@ -62,10 +62,10 @@ public class TestIdentifier {
return false;
}
TestIdentifier otherTest = (TestIdentifier)other;
- return getClassName().equals(otherTest.getClassName()) &&
+ return getClassName().equals(otherTest.getClassName()) &&
getTestName().equals(otherTest.getTestName());
}
-
+
/**
* Generates hashCode based on class and method name.
*/
@@ -73,4 +73,12 @@ public class TestIdentifier {
public int hashCode() {
return getClassName().hashCode() * 31 + getTestName().hashCode();
}
+
+ /**
+ * Generates user friendly string.
+ */
+ @Override
+ public String toString() {
+ return String.format("%s#%s", getClassName(), getTestName());
+ }
}