Add TestRunEnd metrics to getLastCommandResult operation.
Change-Id: I6e1bb8654f8fe677b33b8c4d56021de2a29e512b
diff --git a/Android.mk b/Android.mk
index 57fbf1e..e667cdb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,7 +26,7 @@
LOCAL_MODULE := tradefed
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := junit kxml2-2.3.0 guavalib jline-1.0
+LOCAL_STATIC_JAVA_LIBRARIES := junit kxml2-2.3.0 jline-1.0
# emmalib is only a runtime dependency if generating code coverage reporters,
# not a compile time dependency
LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt emmalib tools-common-prebuilt tf-remote-client
diff --git a/remote/.classpath b/remote/.classpath
index 72f62ef..fc4759a 100644
--- a/remote/.classpath
+++ b/remote/.classpath
@@ -3,6 +3,7 @@
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry exported="true" kind="var" path="TRADEFED_ROOT/prebuilts/misc/common/json/json-prebuilt.jar"/>
+ <classpathentry exported="true" kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar" sourcepath="/TRADEFED_ROOT/external/guava/guava/src"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/remote/Android.mk b/remote/Android.mk
index a0fbc14..0793f33 100644
--- a/remote/Android.mk
+++ b/remote/Android.mk
@@ -26,7 +26,7 @@
LOCAL_MODULE_TAGS := optional
# only depend on ddmlib for the Log class
LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt
-LOCAL_STATIC_JAVA_LIBRARIES := json-prebuilt
+LOCAL_STATIC_JAVA_LIBRARIES := json-prebuilt guavalib
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/remote/src/com/android/tradefed/command/remote/CommandResult.java b/remote/src/com/android/tradefed/command/remote/CommandResult.java
index 4cfd87c..78939f2 100644
--- a/remote/src/com/android/tradefed/command/remote/CommandResult.java
+++ b/remote/src/com/android/tradefed/command/remote/CommandResult.java
@@ -17,6 +17,8 @@
import com.android.tradefed.device.FreeDeviceState;
+import java.util.Map;
+
/**
* Encapsulates 'last command execution' data sent over the wire
*/
@@ -33,15 +35,18 @@
private final Status mStatus;
private final String mError;
private final FreeDeviceState mState;
+ private final Map<String, String> mRunMetrics;
- CommandResult(Status status, String errorDetails, FreeDeviceState state) {
+ CommandResult(Status status, String errorDetails, FreeDeviceState state,
+ Map<String, String> runMetrics) {
mStatus = status;
mError = errorDetails;
mState = state;
+ mRunMetrics = runMetrics;
}
public CommandResult(Status status) {
- this(status, null, null);
+ this(status, null, null, null);
}
Status getStatus() {
@@ -55,4 +60,12 @@
FreeDeviceState getFreeDeviceState() {
return mState;
}
+
+ /*
+ * Although commands can have multiple runs, we only return one set of metrics and replace any
+ * currently stored metrics with the same key.
+ */
+ Map<String, String> getRunMetrics() {
+ return mRunMetrics;
+ }
}
diff --git a/remote/src/com/android/tradefed/command/remote/GetLastCommandResultOp.java b/remote/src/com/android/tradefed/command/remote/GetLastCommandResultOp.java
index 09b2ab1..3fcc010 100644
--- a/remote/src/com/android/tradefed/command/remote/GetLastCommandResultOp.java
+++ b/remote/src/com/android/tradefed/command/remote/GetLastCommandResultOp.java
@@ -15,12 +15,17 @@
*/
package com.android.tradefed.command.remote;
+import com.google.common.collect.ImmutableMap;
+
import com.android.tradefed.command.remote.CommandResult.Status;
import com.android.tradefed.device.FreeDeviceState;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Map;
+
/**
* Remote operation for getting the result of the last command executed
*/
@@ -31,6 +36,9 @@
private static final String FREE_DEVICE_STATE = "free_device_state";
private static final String STATUS = "status";
private static final String INVOCATION_ERROR = "invocation_error";
+ private static final String RUN_METRICS = "run_metrics";
+ private static final String RUN_METRICS_KEY = "key";
+ private static final String RUN_METRICS_VALUE = "value";
private final String mSerial;
@@ -88,7 +96,21 @@
throw new JSONException(String.format("unrecognized state '%s'", freeDeviceString));
}
}
- return new CommandResult(status, errorDetails, state);
+
+ Map<String, String> runMetricsMap = null;
+ JSONArray jsonRunMetricsArray = json.optJSONArray(RUN_METRICS);
+ if (jsonRunMetricsArray != null && jsonRunMetricsArray.length() > 0) {
+ ImmutableMap.Builder<String, String> mapBuilder =
+ new ImmutableMap.Builder<String, String>();
+ for (int i = 0; i < jsonRunMetricsArray.length(); i++) {
+ JSONObject runMetricJson = jsonRunMetricsArray.getJSONObject(i);
+ final String key = runMetricJson.getString(RUN_METRICS_KEY);
+ final String value = runMetricJson.getString(RUN_METRICS_VALUE);
+ mapBuilder.put(key, value);
+ }
+ runMetricsMap = mapBuilder.build();
+ }
+ return new CommandResult(status, errorDetails, state, runMetricsMap);
}
/**
@@ -103,6 +125,17 @@
if (commandResult.getFreeDeviceState() != null) {
json.put(FREE_DEVICE_STATE, commandResult.getFreeDeviceState().name());
}
+ Map<String, String> runMetrics = commandResult.getRunMetrics();
+ if (runMetrics != null && runMetrics.size() > 0) {
+ JSONArray jsonRunMetricsArray = new JSONArray();
+ for (Map.Entry<String, String> entry : runMetrics.entrySet()) {
+ JSONObject keyValuePairJson = new JSONObject();
+ keyValuePairJson.put(RUN_METRICS_KEY, entry.getKey());
+ keyValuePairJson.put(RUN_METRICS_VALUE, entry.getValue());
+ jsonRunMetricsArray.put(keyValuePairJson);
+ }
+ json.put(RUN_METRICS, jsonRunMetricsArray);
+ }
}
public String getDeviceSerial() {
diff --git a/remote/src/com/android/tradefed/command/remote/ICommandResultHandler.java b/remote/src/com/android/tradefed/command/remote/ICommandResultHandler.java
index 6762a57..68053a3 100644
--- a/remote/src/com/android/tradefed/command/remote/ICommandResultHandler.java
+++ b/remote/src/com/android/tradefed/command/remote/ICommandResultHandler.java
@@ -17,12 +17,17 @@
import com.android.tradefed.device.FreeDeviceState;
+import java.util.Map;
+
/**
- * Callback for handling the result of a {@link GetLastCommandResultOp}
+ * Callback for handling the result of a {@link GetLastCommandResultOp}. Although commands can have
+ * multiple runs, we only return one set of metrics and replace any currently stored metrics with
+ * the same key.
*/
public interface ICommandResultHandler {
- public void success();
- public void failure(String errorDetails, FreeDeviceState deviceState);
+ public void success(Map<String, String> runMetrics);
+ public void failure(String errorDetails, FreeDeviceState deviceState,
+ Map<String, String> runMetrics);
public void stillRunning();
public void notAllocated();
public void noActiveCommand();
diff --git a/remote/src/com/android/tradefed/command/remote/RemoteClient.java b/remote/src/com/android/tradefed/command/remote/RemoteClient.java
index 86a23b8..2d06cf9 100644
--- a/remote/src/com/android/tradefed/command/remote/RemoteClient.java
+++ b/remote/src/com/android/tradefed/command/remote/RemoteClient.java
@@ -200,10 +200,11 @@
handler.stillRunning();
break;
case INVOCATION_ERROR:
- handler.failure(r.getInvocationErrorDetails(), r.getFreeDeviceState());
+ handler.failure(r.getInvocationErrorDetails(), r.getFreeDeviceState(),
+ r.getRunMetrics());
break;
case INVOCATION_SUCCESS:
- handler.success();
+ handler.success(r.getRunMetrics());
break;
case NO_ACTIVE_COMMAND:
handler.noActiveCommand();
diff --git a/remote/src/com/android/tradefed/command/remote/RemoteOperation.java b/remote/src/com/android/tradefed/command/remote/RemoteOperation.java
index 11e4906..e0fabfe 100644
--- a/remote/src/com/android/tradefed/command/remote/RemoteOperation.java
+++ b/remote/src/com/android/tradefed/command/remote/RemoteOperation.java
@@ -28,7 +28,7 @@
/** represents json key for error message */
static final String ERROR = "error";
- static final int CURRENT_PROTOCOL_VERSION = 4;
+ static final int CURRENT_PROTOCOL_VERSION = 5;
/**
* Represents all types of remote operations that can be performed
diff --git a/src/com/android/tradefed/command/remote/ExecCommandTracker.java b/src/com/android/tradefed/command/remote/ExecCommandTracker.java
index 7139854..20c524a 100644
--- a/src/com/android/tradefed/command/remote/ExecCommandTracker.java
+++ b/src/com/android/tradefed/command/remote/ExecCommandTracker.java
@@ -20,8 +20,12 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.StubTestInvocationListener;
+import com.google.common.collect.ImmutableMap;
+
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
class ExecCommandTracker extends StubTestInvocationListener implements
IScheduledInvocationListener {
@@ -29,6 +33,7 @@
private CommandResult.Status mStatus = CommandResult.Status.EXECUTING;
private String mErrorDetails = null;
private FreeDeviceState mState = null;
+ Map<String, String> mRunMetrics = new HashMap<String, String>();
@Override
public void invocationFailed(Throwable cause) {
@@ -49,11 +54,18 @@
}
}
+ @Override
+ public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {
+ mRunMetrics.putAll(runMetrics);
+ }
+
/**
* Returns the current state as a {@link CommandResult}.
* @return
*/
CommandResult getCommandResult() {
- return new CommandResult(mStatus, mErrorDetails, mState);
+ return new CommandResult(mStatus, mErrorDetails, mState,
+ new ImmutableMap.Builder<String, String>()
+ .putAll(mRunMetrics).build());
}
}
diff --git a/tests/src/com/android/tradefed/command/remote/RemoteManagerTest.java b/tests/src/com/android/tradefed/command/remote/RemoteManagerTest.java
index 15a1d6f..62db318 100644
--- a/tests/src/com/android/tradefed/command/remote/RemoteManagerTest.java
+++ b/tests/src/com/android/tradefed/command/remote/RemoteManagerTest.java
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Unit tests for {@link RemoteManager}.
@@ -404,9 +405,11 @@
/**
* Test {@link GetLastCommandResultOp} result when commmand fails due to a not available device.
*/
+ @SuppressWarnings("unchecked")
public void testGetLastCommandResult_notAvail() throws Exception {
ICommandResultHandler mockHandler = EasyMock.createStrictMock(ICommandResultHandler.class);
- mockHandler.failure((String)EasyMock.anyObject(), EasyMock.eq(FreeDeviceState.UNAVAILABLE));
+ mockHandler.failure((String)EasyMock.anyObject(), EasyMock.eq(FreeDeviceState.UNAVAILABLE),
+ (Map<String, String>)EasyMock.anyObject());
ITestDevice device = EasyMock.createMock(ITestDevice.class);
EasyMock.expect(device.getSerialNumber()).andStubReturn("serial");
EasyMock.expect(mMockDeviceManager.forceAllocateDevice("serial")).andReturn(device);