blob: 08b1d768cdac2ce1284ceb339239b6aa12c15ca5 [file] [log] [blame]
/*
* Copyright (C) 2014 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.compatibility.common.util;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Utility class to add results to the report.
*/
public class ReportLog implements Serializable {
private static final String ENCODING = "UTF-8";
private static final String TYPE = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
// XML constants
private static final String METRIC_TAG = "Metric";
private static final String MESSAGE_ATTR = "message";
private static final String SCORETYPE_ATTR = "score_type";
private static final String SCOREUNIT_ATTR = "score_unit";
private static final String SOURCE_ATTR = "source";
private static final String SUMMARY_TAG = "Summary";
private static final String VALUE_TAG = "Value";
private static final String DEFAULT_NAME = "default";
protected Metric mSummary;
protected String mReportLogName;
protected String mStreamName;
public static class Metric implements Serializable {
private static final int MAX_SOURCE_LENGTH = 200;
private static final int MAX_MESSAGE_LENGTH = 200;
private static final int MAX_NUM_VALUES = 1000;
String mSource;
String mMessage;
double[] mValues;
ResultType mType;
ResultUnit mUnit;
Metric(String source, String message, double value, ResultType type, ResultUnit unit) {
this(source, message, new double[] { value }, type, unit);
}
/**
* Creates a metric array to be included in the report. Each object has a message
* describing its values and enums to interpret them. In addition, each result also includes
* class, method and line number information about the test which added this result which is
* collected by looking at the stack trace.
*
* @param message A string describing the values
* @param values An array of the values
* @param type Represents how to interpret the values (eg. A lower score is better)
* @param unit Represents the unit in which the values are (eg. Milliseconds)
*/
Metric(String source, String message, double[] values, ResultType type, ResultUnit unit) {
int sourceLength = source.length();
if (sourceLength > MAX_SOURCE_LENGTH) {
// Substring to the end
mSource = source.substring(sourceLength - MAX_SOURCE_LENGTH);
} else {
mSource = source;
}
int messageLength = message.length();
if (messageLength > MAX_MESSAGE_LENGTH) {
// Substring from the start
mMessage = message.substring(0, MAX_MESSAGE_LENGTH);
} else {
mMessage = message;
}
int valuesLength = values.length;
if (valuesLength > MAX_NUM_VALUES) {
// Subarray from the start
mValues = Arrays.copyOf(values, MAX_NUM_VALUES);
} else {
mValues = values;
}
mType = type;
mUnit = unit;
}
public String getSource() {
return mSource;
}
public String getMessage() {
return mMessage;
}
public double[] getValues() {
return mValues;
}
public ResultType getType() {
return mType;
}
public ResultUnit getUnit() {
return mUnit;
}
void serialize(XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(null, METRIC_TAG);
serializer.attribute(null, SOURCE_ATTR, getSource());
serializer.attribute(null, MESSAGE_ATTR, getMessage());
serializer.attribute(null, SCORETYPE_ATTR, getType().toReportString());
serializer.attribute(null, SCOREUNIT_ATTR, getUnit().toReportString());
for (double d : getValues()) {
serializer.startTag(null, VALUE_TAG);
serializer.text(Double.toString(d));
serializer.endTag(null, VALUE_TAG);
}
serializer.endTag(null, METRIC_TAG);
}
static Metric parse(XmlPullParser parser)
throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, null, METRIC_TAG);
String source = parser.getAttributeValue(null, SOURCE_ATTR);
String message = parser.getAttributeValue(null, MESSAGE_ATTR);
ResultType type = ResultType.parseReportString(
parser.getAttributeValue(null, SCORETYPE_ATTR));
ResultUnit unit = ResultUnit.parseReportString(
parser.getAttributeValue(null, SCOREUNIT_ATTR));
List<String> valuesList = new ArrayList<>();
while (parser.nextTag() == XmlPullParser.START_TAG) {
parser.require(XmlPullParser.START_TAG, null, VALUE_TAG);
valuesList.add(parser.nextText());
parser.require(XmlPullParser.END_TAG, null, VALUE_TAG);
}
int length = valuesList.size();
double[] values = new double[length];
for (int i = 0; i < length; i++) {
values[i] = Double.parseDouble(valuesList.get(i));
}
parser.require(XmlPullParser.END_TAG, null, METRIC_TAG);
return new Metric(source, message, values, type, unit);
}
}
public ReportLog() {
mReportLogName = DEFAULT_NAME;
}
public ReportLog(String reportLogName, String streamName) {
mReportLogName = reportLogName;
mStreamName = streamName;
}
/**
* Adds a double array of metrics to the report.
*/
public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a double array of metrics to the report.
*/
public void addValues(String source, String message, double[] values, ResultType type,
ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a double metric to the report.
*/
public void addValue(String message, double value, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a double metric to the report.
*/
public void addValue(String source, String message, double value, ResultType type,
ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds an int metric to the report.
*/
public void addValue(String message, int value, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a long metric to the report.
*/
public void addValue(String message, long value, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a float metric to the report.
*/
public void addValue(String message, float value, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a boolean metric to the report.
*/
public void addValue(String message, boolean value, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a String metric to the report.
*/
public void addValue(String message, String value, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds an int array of metrics to the report.
*/
public void addValues(String message, int[] values, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a long array of metrics to the report.
*/
public void addValues(String message, long[] values, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a float array of metrics to the report.
*/
public void addValues(String message, float[] values, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a boolean array of metrics to the report.
*/
public void addValues(String message, boolean[] values, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* Adds a String List of metrics to the report.
*/
public void addValues(String message, List<String> values, ResultType type, ResultUnit unit) {
// Do nothing. Subclasses may implement using InfoStore to write metrics to files.
}
/**
* @param elem
*/
/* package */ void setSummary(Metric elem) {
mSummary = elem;
}
/**
* Sets the double metric summary of the report.
*
* NOTE: messages over {@value Metric#MAX_MESSAGE_LENGTH} chars will be trimmed.
*/
public void setSummary(String message, double value, ResultType type, ResultUnit unit) {
setSummary(new Metric(Stacktrace.getTestCallerClassMethodNameLineNumber(), message, value,
type, unit));
}
public Metric getSummary() {
return mSummary;
}
/**
* Serializes a given {@link ReportLog} to a String.
* @throws XmlPullParserException
* @throws IOException
* @throws IllegalStateException
* @throws IllegalArgumentException
*/
public static String serialize(ReportLog reportlog) throws XmlPullParserException,
IllegalArgumentException, IllegalStateException, IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
serializer.setOutput(byteArrayOutputStream, ENCODING);
serializer.startDocument(ENCODING, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serialize(serializer, reportlog);
serializer.endDocument();
return byteArrayOutputStream.toString(ENCODING);
}
/**
* Serializes a given {@link ReportLog} to XML.
* @param serializer
* @param reportLog
* @throws IOException
*/
public static void serialize(XmlSerializer serializer, ReportLog reportLog)
throws IOException {
if (reportLog == null) {
throw new IllegalArgumentException("Metrics reports was null");
}
Metric summary = reportLog.getSummary();
// Summary is optional. Details are not included in result report.
if (summary != null) {
serializer.startTag(null, SUMMARY_TAG);
summary.serialize(serializer);
serializer.endTag(null, SUMMARY_TAG);
}
}
/**
* Parses a {@link ReportLog} from the given string.
* @throws XmlPullParserException
* @throws IOException
*/
public static ReportLog parse(String result) throws XmlPullParserException, IOException {
if (result == null){
throw new IllegalArgumentException("Metrics string was null");
}
if (result.trim().isEmpty()) {
// Empty report.
return new ReportLog();
}
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new ByteArrayInputStream(result.getBytes(ENCODING)), ENCODING);
try {
parser.nextTag();
} catch (XmlPullParserException e) {
// Empty Report.
return new ReportLog();
}
return parse(parser);
}
/**
* Parses a {@link ReportLog} from the given XML parser.
* @param parser
* @throws IOException
* @throws XmlPullParserException
*/
public static ReportLog parse(XmlPullParser parser) throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, null, SUMMARY_TAG);
parser.nextTag();
ReportLog report = new ReportLog();
report.setSummary(Metric.parse(parser));
parser.nextTag();
parser.require(XmlPullParser.END_TAG, null, SUMMARY_TAG);
return report;
}
}