blob: 50a11e0a63b8497ee3b24b33eb33d286ac141881 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.cluster;
import com.android.tradefed.log.LogUtil.CLog;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/** A class to encapsulate cluster command events to be uploaded. */
public class ClusterCommandEvent implements IClusterEvent {
public static final String DATA_KEY_ERROR = "error";
public static final String DATA_KEY_SUMMARY = "summary";
public static final String DATA_KEY_SETUP_TIME_MILLIS = "setup_time_millis";
public static final String DATA_KEY_FETCH_BUILD_TIME_MILLIS = "fetch_build_time_millis";
public static final String DATA_KEY_TOTAL_TEST_COUNT = "total_test_count";
public static final String DATA_KEY_FAILED_TEST_COUNT = "failed_test_count";
public static final String DATA_KEY_PASSED_TEST_COUNT = "passed_test_count";
public static final String DATA_KEY_FAILED_TEST_RUN_COUNT = "failed_test_run_count";
public static final String DATA_KEY_LOST_DEVICE_DETECTED = "device_lost_detected";
public static final String DATA_KEY_SUBPROCESS_COMMAND_ERROR = "subprocess_command_error";
public static final String DATA_KEY_ERROR_ID_NAME = "error_name";
public static final String DATA_KEY_ERROR_ID_CODE = "error_code";
public static final String DATA_KEY_ERROR_STATUS = "error_status";
// Maximum size of an individual data string value.
public static final int MAX_DATA_STRING_SIZE = 4095;
public enum Type {
AllocationFailed,
ConfigurationError,
FetchFailed,
ExecuteFailed,
InvocationInitiated,
InvocationStarted,
InvocationFailed,
InvocationEnded,
InvocationCompleted,
TestRunInProgress,
TestEnded
}
private long mTimestamp;
private Type mType;
private String mCommandTaskId;
private String mAttemptId;
private String mHostName;
private InvocationStatus mInvocationStatus;
private Map<String, Object> mData = new HashMap<>();
private Set<String> mDeviceSerials;
private ClusterCommandEvent() {}
public String getHostName() {
return mHostName;
}
public long getTimestamp() {
return mTimestamp;
}
public Type getType() {
return mType;
}
public String getCommandTaskId() {
return mCommandTaskId;
}
public String getAttemptId() {
return mAttemptId;
}
public InvocationStatus getInvocationStatus() {
return mInvocationStatus;
}
public Map<String, Object> getData() {
return mData;
}
public Set<String> getDeviceSerials() {
return mDeviceSerials;
}
public static class Builder {
private long mTimestamp = System.currentTimeMillis();
private Type mType;
private String mCommandTaskId;
private String mAttemptId;
private String mHostName;
private InvocationStatus mInvocationStatus;
private Map<String, Object> mData = new HashMap<>();
private Set<String> mDeviceSerials = new HashSet<>();
public Builder() {}
public Builder setTimestamp(final long timestamp) {
mTimestamp = timestamp;
return this;
}
public Builder setType(final Type type) {
mType = type;
return this;
}
public Builder setCommandTaskId(final String commandTaskId) {
mCommandTaskId = commandTaskId;
return this;
}
public Builder setAttemptId(final String attemptId) {
mAttemptId = attemptId;
return this;
}
public Builder setHostName(final String hostName) {
mHostName = hostName;
return this;
}
public Builder setInvocationStatus(final InvocationStatus invocationStatus) {
mInvocationStatus = invocationStatus;
return this;
}
public Builder setData(final String name, final Object value) {
if (value instanceof String && ((String) value).length() > MAX_DATA_STRING_SIZE) {
CLog.w(
String.format(
"Data for '%s' exceeds %d characters, and has been truncated.",
name, MAX_DATA_STRING_SIZE));
mData.put(name, ((String) value).substring(0, MAX_DATA_STRING_SIZE));
} else {
mData.put(name, value);
}
return this;
}
public Builder setDeviceSerials(final Set<String> deviceSerials) {
mDeviceSerials = deviceSerials;
return this;
}
public Builder addDeviceSerial(final String deviceSerial) {
mDeviceSerials.add(deviceSerial);
return this;
}
public ClusterCommandEvent build() {
final ClusterCommandEvent obj = new ClusterCommandEvent();
obj.mTimestamp = mTimestamp;
obj.mType = mType;
obj.mCommandTaskId = mCommandTaskId;
obj.mAttemptId = mAttemptId;
obj.mHostName = mHostName;
obj.mInvocationStatus = mInvocationStatus;
obj.mData = new HashMap<>(mData);
obj.mDeviceSerials = mDeviceSerials;
return obj;
}
}
/**
* Creates a base {@link Builder}.
*
* @return a {@link Builder}.
*/
public static Builder createEventBuilder() {
return createEventBuilder(null);
}
/**
* Creates a base {@link Builder} for the given {@link ClusterCommand}.
*
* @return a {@link Builder}.
*/
public static Builder createEventBuilder(final ClusterCommand command) {
final ClusterCommandEvent.Builder builder = new ClusterCommandEvent.Builder();
if (command != null) {
builder.setCommandTaskId(command.getTaskId());
builder.setAttemptId(command.getAttemptId());
}
return builder;
}
/** {@inheritDoc} */
@Override
public JSONObject toJSON() throws JSONException {
final JSONObject json = new JSONObject();
json.put("type", this.getType().toString());
// event time should be in POSIX timestamp.
json.put("time", this.getTimestamp() / 1000);
json.put("task_id", this.getCommandTaskId());
json.put("attempt_id", this.getAttemptId());
json.put("hostname", this.getHostName());
// TODO(b/79583735): deprecated.
if (!this.getDeviceSerials().isEmpty()) {
json.put("device_serial", this.getDeviceSerials().iterator().next());
}
json.put("device_serials", new JSONArray(this.getDeviceSerials()));
if (mInvocationStatus != null) {
json.put("invocation_status", mInvocationStatus.toJSON());
}
json.put("data", new JSONObject(this.getData()));
return json;
}
@Override
public String toString() {
String str = null;
try {
str = toJSON().toString();
} catch (final JSONException e) {
// ignore
}
return str;
}
}