am b1a9891a: Result XML Reporter
* commit 'b1a9891a0b2109a7fba9c900f68ee90f62aa843e':
Result XML Reporter
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 855c209..686c90a 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -84,6 +84,9 @@
@Option(name = "quiet-output", description = "Mute display of test results.")
private boolean mQuietOutput = false;
+ @Option(name = "result-server", description = "Server to publish test results.")
+ private String mResultServer;
+
protected IBuildInfo mBuildInfo;
private String mStartTime;
private String mDeviceSerial;
@@ -254,9 +257,18 @@
CLog.w("Unable to create XML report");
return;
}
- createXmlResult(mReportDir, mStartTime, elapsedTime);
+
+ File reportFile = getResultFile(mReportDir);
+ createXmlResult(reportFile, mStartTime, elapsedTime);
copyFormattingFiles(mReportDir);
zipResults(mReportDir);
+
+ try {
+ ResultReporter reporter = new ResultReporter(mResultServer, reportFile);
+ reporter.reportResult();
+ } catch (IOException e) {
+ CLog.e(e);
+ }
}
private void logResult(String format, Object... args) {
@@ -281,12 +293,11 @@
/**
* Creates a report file and populates it with the report data from the completed tests.
*/
- private void createXmlResult(File reportDir, String startTimestamp, long elapsedTime) {
+ private void createXmlResult(File reportFile, String startTimestamp, long elapsedTime) {
String endTime = getTimestamp();
-
OutputStream stream = null;
try {
- stream = createOutputResultStream(reportDir);
+ stream = createOutputResultStream(reportFile);
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(stream, "UTF-8");
serializer.startDocument("UTF-8", false);
@@ -331,11 +342,14 @@
//serializer.endTag(ns, RESULT_TAG);
}
+ private File getResultFile(File reportDir) {
+ return new File(reportDir, TEST_RESULT_FILE_NAME);
+ }
+
/**
* Creates the output stream to use for test results. Exposed for mocking.
*/
- OutputStream createOutputResultStream(File reportDir) throws IOException {
- File reportFile = new File(reportDir, TEST_RESULT_FILE_NAME);
+ OutputStream createOutputResultStream(File reportFile) throws IOException {
logResult("Created xml report file at file://%s", reportFile.getAbsolutePath());
return new FileOutputStream(reportFile);
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
index 8ee9c0f..9d903dd 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/IssueReporter.java
@@ -28,11 +28,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@@ -46,7 +41,6 @@
*/
public class IssueReporter implements ITestInvocationListener {
- private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
private static final int BUGREPORT_SIZE = 500 * 1024;
private static final String PRODUCT_NAME_KEY = "buildName";
@@ -87,22 +81,42 @@
*/
private void setBugReport(InputStreamSource dataStream) throws IOException {
if (mCurrentIssue != null) {
- InputStream input = dataStream.createInputStream();
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(BUGREPORT_SIZE);
- GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
- for (byte[] buffer = new byte[1024]; input.read(buffer) >= 0; ) {
- gzipOutput.write(buffer);
- }
- gzipOutput.close();
-
// Only one bug report can be stored at a time and they are gzipped to
// about 0.5 MB so there shoudn't be any memory leak bringing down CTS.
- mCurrentIssue.mBugReport = byteOutput.toByteArray();
+ InputStream input = null;
+ try {
+ input = dataStream.createInputStream();
+ mCurrentIssue.mBugReport = getBytes(input, BUGREPORT_SIZE);
+ } finally {
+ if (input != null) {
+ input.close();
+ }
+ }
} else {
CLog.e("setBugReport is getting called on an empty issue...");
}
}
+ /**
+ * @param input that will be gzipped and returne as a byte array
+ * @param size of the output expected
+ * @return the byte array with the input's data
+ * @throws IOException
+ */
+ static byte[] getBytes(InputStream input, int size) throws IOException {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(size);
+ GZIPOutputStream gzipOutput = new GZIPOutputStream(byteOutput);
+ for (byte[] buffer = new byte[1024]; ; ) {
+ int numRead = input.read(buffer);
+ if (numRead < 0) {
+ break;
+ }
+ gzipOutput.write(buffer, 0, numRead);
+ }
+ gzipOutput.close();
+ return byteOutput.toByteArray();
+ }
+
@Override
public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
if (mCurrentIssue != null) {
@@ -158,32 +172,14 @@
return null;
}
- HttpURLConnection connection = null;
-
- try {
- URL url = new URL(mServerUrl);
- connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setDoOutput(true);
- connection.setRequestProperty("Content-Type",
- "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
-
- byte[] body = getContentBody();
- connection.setRequestProperty("Content-Length", Integer.toString(body.length));
-
- OutputStream output = connection.getOutputStream();
- output.write(body);
- output.close();
-
- // Open the stream to get a response. Otherwise request will be cancelled.
- InputStream input = connection.getInputStream();
- input.close();
-
- } finally {
- if (connection != null) {
- connection.disconnect();
- }
- }
+ new MultipartForm(mServerUrl)
+ .addFormValue("productName", mProductName)
+ .addFormValue("buildType", mBuildType)
+ .addFormValue("buildId", mBuildId)
+ .addFormValue("testName", mTestName)
+ .addFormValue("stackTrace", mStackTrace)
+ .addFormFile("bugReport", "bugreport.txt.gz", mBugReport)
+ .submit();
return null;
}
@@ -191,43 +187,6 @@
private boolean isEmpty(String value) {
return value == null || value.trim().isEmpty();
}
-
- private byte[] getContentBody() throws IOException {
- ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
- PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
- writer.println();
- writeFormField(writer, "productName", mProductName);
- writeFormField(writer, "buildType", mBuildType);
- writeFormField(writer, "buildId", mBuildId);
- writeFormField(writer, "testName", mTestName);
- writeFormField(writer, "stackTrace", mStackTrace);
- if (mBugReport != null) {
- writeFormFileHeader(writer, "bugReport", "bugReport.txt.gz");
- writer.flush(); // Must flush here before writing to the byte stream!
- byteOutput.write(mBugReport);
- writer.println();
- }
- writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
- writer.flush();
- writer.close();
- return byteOutput.toByteArray();
- }
-
- private void writeFormField(PrintWriter writer, String name, String value) {
- writer.append("--").println(FORM_DATA_BOUNDARY);
- writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
- writer.println();
- writer.println(value);
- }
-
- private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
- writer.append("--").println(FORM_DATA_BOUNDARY);
- writer.append("Content-Disposition: form-data; name=\"").append(name);
- writer.append("\"; filename=\"").append(fileName).println("\"");
- writer.println("Content-Type: application/x-gzip");
- writer.println("Content-Transfer-Encoding: binary");
- writer.println();
- }
}
@Override
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java
new file mode 100644
index 0000000..f3ef0bb
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/MultipartForm.java
@@ -0,0 +1,144 @@
+/*
+ * 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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/** MultipartForm builds a multipart form and submits it. */
+class MultipartForm {
+
+ private static final String FORM_DATA_BOUNDARY = "C75I55u3R3p0r73r";
+
+ private final String mServerUrl;
+
+ private final Map<String, String> mFormValues = new HashMap<String, String>();
+
+ private String mName;
+ private String mFileName;
+ private byte[] mData;
+
+ public MultipartForm(String serverUrl) {
+ mServerUrl = serverUrl;
+ }
+
+ public MultipartForm addFormValue(String name, String value) {
+ mFormValues.put(name, value);
+ return this;
+ }
+
+ public MultipartForm addFormFile(String name, String fileName, byte[] data) {
+ mName = name;
+ mFileName = fileName;
+ mData = data;
+ return this;
+ }
+
+ public void submit() throws IOException {
+ String redirectUrl = submitForm(mServerUrl);
+ if (redirectUrl != null) {
+ submitForm(redirectUrl);
+ }
+ }
+
+ /**
+ * @param serverUrl to post the data to
+ * @return a url if the server redirected to another url
+ * @throws IOException
+ */
+ private String submitForm(String serverUrl) throws IOException {
+ HttpURLConnection connection = null;
+ try {
+ URL url = new URL(serverUrl);
+ connection = (HttpURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(false);
+ connection.setRequestMethod("POST");
+ connection.setDoOutput(true);
+ connection.setRequestProperty("Content-Type",
+ "multipart/form-data; boundary=" + FORM_DATA_BOUNDARY);
+
+ byte[] body = getContentBody();
+ connection.setRequestProperty("Content-Length", Integer.toString(body.length));
+
+ OutputStream output = connection.getOutputStream();
+ try {
+ output.write(body);
+ } finally {
+ output.close();
+ }
+
+ // Open the stream to get a response. Otherwise request will be cancelled.
+ InputStream input = connection.getInputStream();
+ input.close();
+
+ if (connection.getResponseCode() == 302) {
+ return connection.getHeaderField("Location");
+ }
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getContentBody() throws IOException {
+ ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(byteOutput));
+ writer.println();
+
+ for (Map.Entry<String, String> formValue : mFormValues.entrySet()) {
+ writeFormField(writer, formValue.getKey(), formValue.getValue());
+ }
+
+ if (mData != null) {
+ writeFormFileHeader(writer, mName, mFileName);
+ writer.flush(); // Must flush here before writing to the byte stream!
+ byteOutput.write(mData);
+ writer.println();
+ }
+ writer.append("--").append(FORM_DATA_BOUNDARY).println("--");
+ writer.flush();
+ writer.close();
+ return byteOutput.toByteArray();
+ }
+
+ private void writeFormField(PrintWriter writer, String name, String value) {
+ writer.append("--").println(FORM_DATA_BOUNDARY);
+ writer.append("Content-Disposition: form-data; name=\"").append(name).println("\"");
+ writer.println();
+ writer.println(value);
+ }
+
+ private void writeFormFileHeader(PrintWriter writer, String name, String fileName) {
+ writer.append("--").println(FORM_DATA_BOUNDARY);
+ writer.append("Content-Disposition: form-data; name=\"").append(name);
+ writer.append("\"; filename=\"").append(fileName).println("\"");
+ writer.println("Content-Type: application/x-gzip");
+ writer.println("Content-Transfer-Encoding: binary");
+ writer.println();
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java
new file mode 100644
index 0000000..05192c9
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/ResultReporter.java
@@ -0,0 +1,60 @@
+/*
+ * 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 java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Class that sends a HTTP POST multipart/form-data request containing
+ * the test result XML.
+ */
+class ResultReporter {
+
+ private static final int RESULT_XML_BYTES = 500 * 1024;
+
+ private final String mServerUrl;
+
+ private final File mReportFile;
+
+ ResultReporter(String serverUrl, File reportFile) {
+ mServerUrl = serverUrl;
+ mReportFile = reportFile;
+ }
+
+ public void reportResult() throws IOException {
+ if (isEmpty(mServerUrl)) {
+ return;
+ }
+
+ InputStream input = new FileInputStream(mReportFile);
+ try {
+ byte[] data = IssueReporter.getBytes(input, RESULT_XML_BYTES);
+ new MultipartForm(mServerUrl)
+ .addFormFile("resultXml", "testResult.xml.gz", data)
+ .submit();
+ } finally {
+ input.close();
+ }
+ }
+
+ private boolean isEmpty(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+}