blob: df1d4f1a787da8027564f30e4f270cfc258914b8 [file] [log] [blame]
/*
* Copyright (C) 2011 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.cts.tradefed.result;
import com.android.tradefed.result.TestResult;
import org.kxml2.io.KXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
* Data structure that represents a "Test" result XML element.
*/
class Test extends AbstractXmlPullParser {
static final String TAG = "Test";
private static final String NAME_ATTR = "name";
private static final String MESSAGE_ATTR = "message";
private static final String ENDTIME_ATTR = "endtime";
private static final String STARTTIME_ATTR = "starttime";
private static final String RESULT_ATTR = "result";
private static final String SCENE_TAG = "FailedScene";
private static final String STACK_TAG = "StackTrace";
private String mName;
private CtsTestStatus mResult;
private String mStartTime;
private String mEndTime;
private String mMessage;
private String mStackTrace;
/**
* Create an empty {@link Test}
*/
public Test() {
}
/**
* Create a {@link Test} from a {@link TestResult}.
*
* @param name
*/
public Test(String name) {
mName = name;
mResult = CtsTestStatus.NOT_EXECUTED;
mStartTime = TimeUtil.getTimestamp();
updateEndTime();
}
/**
* Set the name of this {@link Test}
*/
public void setName(String name) {
mName = name;
}
/**
* Get the name of this {@link Test}
*/
public String getName() {
return mName;
}
public CtsTestStatus getResult() {
return mResult;
}
public String getMessage() {
return mMessage;
}
public void setMessage(String message) {
mMessage = message;
}
public String getStartTime() {
return mStartTime;
}
public String getEndTime() {
return mEndTime;
}
public String getStackTrace() {
return mStackTrace;
}
public void setStackTrace(String stackTrace) {
mStackTrace = sanitizeStackTrace(stackTrace);
mMessage = getFailureMessageFromStackTrace(mStackTrace);
}
public void updateEndTime() {
mEndTime = TimeUtil.getTimestamp();
}
public void setResultStatus(CtsTestStatus status) {
mResult = status;
}
/**
* Serialize this object and all its contents to XML.
*
* @param serializer
* @throws IOException
*/
public void serialize(KXmlSerializer serializer)
throws IOException {
serializer.startTag(CtsXmlResultReporter.ns, TAG);
serializer.attribute(CtsXmlResultReporter.ns, NAME_ATTR, getName());
serializer.attribute(CtsXmlResultReporter.ns, RESULT_ATTR, mResult.getValue());
serializer.attribute(CtsXmlResultReporter.ns, STARTTIME_ATTR, mStartTime);
serializer.attribute(CtsXmlResultReporter.ns, ENDTIME_ATTR, mEndTime);
if (mMessage != null) {
if (mResult == CtsTestStatus.PASS) { // PTS will add performance result
serializer.startTag(CtsXmlResultReporter.ns, SCENE_TAG);
serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, mMessage);
serializer.endTag(CtsXmlResultReporter.ns, SCENE_TAG);
} else {
serializer.startTag(CtsXmlResultReporter.ns, SCENE_TAG);
serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, mMessage);
if (mStackTrace != null) {
serializer.startTag(CtsXmlResultReporter.ns, STACK_TAG);
serializer.text(mStackTrace);
serializer.endTag(CtsXmlResultReporter.ns, STACK_TAG);
}
serializer.endTag(CtsXmlResultReporter.ns, SCENE_TAG);
}
}
serializer.endTag(CtsXmlResultReporter.ns, TAG);
}
/**
* Strip out any invalid XML characters that might cause the report to be unviewable.
* http://www.w3.org/TR/REC-xml/#dt-character
*/
private static String sanitizeStackTrace(String trace) {
if (trace != null) {
return trace.replaceAll("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");
} else {
return null;
}
}
/**
* Gets the failure message to show from the stack trace.
* <p/>
* Exposed for unit testing
*
* @param stack the full stack trace
* @return the failure message
*/
static String getFailureMessageFromStackTrace(String stack) {
// return the first two lines of stack as failure message
int endPoint = stack.indexOf('\n');
if (endPoint != -1) {
int nextLine = stack.indexOf('\n', endPoint + 1);
if (nextLine != -1) {
return stack.substring(0, nextLine);
}
}
return stack;
}
/**
* Populates this class with test result data parsed from XML.
*
* @param parser the {@link XmlPullParser}. Expected to be pointing at start
* of a Test tag
*/
@Override
void parse(XmlPullParser parser) throws XmlPullParserException, IOException {
if (!parser.getName().equals(TAG)) {
throw new XmlPullParserException(String.format(
"invalid XML: Expected %s tag but received %s", TAG, parser.getName()));
}
setName(getAttribute(parser, NAME_ATTR));
mResult = CtsTestStatus.getStatus(getAttribute(parser, RESULT_ATTR));
mStartTime = getAttribute(parser, STARTTIME_ATTR);
mEndTime = getAttribute(parser, ENDTIME_ATTR);
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG && parser.getName().equals(SCENE_TAG)) {
mMessage = getAttribute(parser, MESSAGE_ATTR);
} else if (eventType == XmlPullParser.START_TAG && parser.getName().equals(STACK_TAG)) {
mStackTrace = parser.nextText();
} else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) {
return;
}
eventType = parser.next();
}
}
}