Merge "Updated Summarizer to use SQLite DB."
This commit is contained in:
committed by
Android (Google) Code Review
commit
67a58a0f7c
@@ -18,8 +18,16 @@ package com.android.dumprendertree2;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A class that represent a result of the test. It is responsible for returning the result's
|
||||
* raw data and generating its own diff in HTML format.
|
||||
@@ -49,7 +57,7 @@ public abstract class AbstractResult implements Comparable<AbstractResult> {
|
||||
/**
|
||||
* A code representing the result of comparing actual and expected results.
|
||||
*/
|
||||
public enum ResultCode {
|
||||
public enum ResultCode implements Serializable {
|
||||
RESULTS_MATCH("Results match"),
|
||||
RESULTS_DIFFER("Results differ"),
|
||||
NO_EXPECTED_RESULT("No expected result"),
|
||||
@@ -81,6 +89,58 @@ public abstract class AbstractResult implements Comparable<AbstractResult> {
|
||||
return mAdditionalTextOutputString;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream baos = null;
|
||||
ObjectOutputStream oos = null;
|
||||
try {
|
||||
try {
|
||||
baos = new ByteArrayOutputStream();
|
||||
oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(this);
|
||||
} finally {
|
||||
if (baos != null) {
|
||||
baos.close();
|
||||
}
|
||||
if (oos != null) {
|
||||
oos.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "Unable to serialize result: " + getRelativePath(), e);
|
||||
}
|
||||
|
||||
return baos == null ? null : baos.toByteArray();
|
||||
}
|
||||
|
||||
public static AbstractResult create(byte[] bytes) {
|
||||
ByteArrayInputStream bais = null;
|
||||
ObjectInputStream ois = null;
|
||||
AbstractResult result = null;
|
||||
try {
|
||||
try {
|
||||
bais = new ByteArrayInputStream(bytes);
|
||||
ois = new ObjectInputStream(bais);
|
||||
result = (AbstractResult)ois.readObject();
|
||||
} finally {
|
||||
if (bais != null) {
|
||||
bais.close();
|
||||
}
|
||||
if (ois != null) {
|
||||
ois.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "Unable to deserialize result!", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Unable to deserialize result!", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void clearResults() {
|
||||
mAdditionalTextOutputString = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the result object obtain the results of the test from the webview
|
||||
* and store them in the format that suits itself bests. This method is asynchronous.
|
||||
|
||||
@@ -147,7 +147,7 @@ public class ManagerService extends Service {
|
||||
super.onCreate();
|
||||
|
||||
mFileFilter = new FileFilter();
|
||||
mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH);
|
||||
mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH, getApplicationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.android.dumprendertree2;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.os.Build;
|
||||
import android.os.Message;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -32,7 +34,6 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -189,6 +190,7 @@ public class Summarizer {
|
||||
private static final String TXT_SUMMARY_RELATIVE_PATH = "summary.txt";
|
||||
|
||||
private static final int RESULTS_PER_DUMP = 500;
|
||||
private static final int RESULTS_PER_DB_ACCESS = 50;
|
||||
|
||||
private int mCrashedTestsCount = 0;
|
||||
private List<AbstractResult> mUnexpectedFailures = new ArrayList<AbstractResult>();
|
||||
@@ -196,16 +198,31 @@ public class Summarizer {
|
||||
private List<AbstractResult> mExpectedPasses = new ArrayList<AbstractResult>();
|
||||
private List<AbstractResult> mUnexpectedPasses = new ArrayList<AbstractResult>();
|
||||
|
||||
private Cursor mUnexpectedFailuresCursor;
|
||||
private Cursor mExpectedFailuresCursor;
|
||||
private Cursor mUnexpectedPassesCursor;
|
||||
private Cursor mExpectedPassesCursor;
|
||||
|
||||
private FileFilter mFileFilter;
|
||||
private String mResultsRootDirPath;
|
||||
private String mTestsRelativePath;
|
||||
private Date mDate;
|
||||
|
||||
private int mResultsSinceLastHtmlDump = 0;
|
||||
private int mResultsSinceLastDbAccess = 0;
|
||||
|
||||
public Summarizer(FileFilter fileFilter, String resultsRootDirPath) {
|
||||
private SummarizerDBHelper mDbHelper;
|
||||
|
||||
public Summarizer(FileFilter fileFilter, String resultsRootDirPath, Context context) {
|
||||
mFileFilter = fileFilter;
|
||||
mResultsRootDirPath = resultsRootDirPath;
|
||||
|
||||
/**
|
||||
* We don't run the database I/O in a separate thread to avoid consumer/producer problem
|
||||
* and to simplify code.
|
||||
*/
|
||||
mDbHelper = new SummarizerDBHelper(context);
|
||||
mDbHelper.open();
|
||||
}
|
||||
|
||||
public static URI getDetailsUri() {
|
||||
@@ -221,6 +238,7 @@ public class Summarizer {
|
||||
}
|
||||
|
||||
if (result.didPass()) {
|
||||
result.clearResults();
|
||||
if (mFileFilter.isFail(relativePath)) {
|
||||
mUnexpectedPasses.add(result);
|
||||
} else {
|
||||
@@ -233,6 +251,32 @@ public class Summarizer {
|
||||
mUnexpectedFailures.add(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (++mResultsSinceLastDbAccess == RESULTS_PER_DB_ACCESS) {
|
||||
persistLists();
|
||||
clearLists();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearLists() {
|
||||
mUnexpectedFailures.clear();
|
||||
mExpectedFailures.clear();
|
||||
mUnexpectedPasses.clear();
|
||||
mExpectedPasses.clear();
|
||||
}
|
||||
|
||||
private void persistLists() {
|
||||
persistListToTable(mUnexpectedFailures, SummarizerDBHelper.UNEXPECTED_FAILURES_TABLE);
|
||||
persistListToTable(mExpectedFailures, SummarizerDBHelper.EXPECTED_FAILURES_TABLE);
|
||||
persistListToTable(mUnexpectedPasses, SummarizerDBHelper.UNEXPECTED_PASSES_TABLE);
|
||||
persistListToTable(mExpectedPasses, SummarizerDBHelper.EXPECTED_PASSES_TABLE);
|
||||
mResultsSinceLastDbAccess = 0;
|
||||
}
|
||||
|
||||
private void persistListToTable(List<AbstractResult> results, String table) {
|
||||
for (AbstractResult abstractResult : results) {
|
||||
mDbHelper.insertAbstractResult(abstractResult, table);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTestsRelativePath(String testsRelativePath) {
|
||||
@@ -240,17 +284,35 @@ public class Summarizer {
|
||||
}
|
||||
|
||||
public void summarize(Message onFinishMessage) {
|
||||
persistLists();
|
||||
clearLists();
|
||||
|
||||
mUnexpectedFailuresCursor =
|
||||
mDbHelper.getAbstractResults(SummarizerDBHelper.UNEXPECTED_FAILURES_TABLE);
|
||||
mUnexpectedPassesCursor =
|
||||
mDbHelper.getAbstractResults(SummarizerDBHelper.UNEXPECTED_PASSES_TABLE);
|
||||
mExpectedFailuresCursor =
|
||||
mDbHelper.getAbstractResults(SummarizerDBHelper.EXPECTED_FAILURES_TABLE);
|
||||
mExpectedPassesCursor =
|
||||
mDbHelper.getAbstractResults(SummarizerDBHelper.EXPECTED_PASSES_TABLE);
|
||||
|
||||
String webKitRevision = getWebKitRevision();
|
||||
createHtmlDetails(webKitRevision);
|
||||
createTxtSummary(webKitRevision);
|
||||
|
||||
clearLists();
|
||||
mUnexpectedFailuresCursor.close();
|
||||
mUnexpectedPassesCursor.close();
|
||||
mExpectedFailuresCursor.close();
|
||||
mExpectedPassesCursor.close();
|
||||
|
||||
onFinishMessage.sendToTarget();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mCrashedTestsCount = 0;
|
||||
mUnexpectedFailures.clear();
|
||||
mExpectedFailures.clear();
|
||||
mExpectedPasses.clear();
|
||||
clearLists();
|
||||
mDbHelper.reset();
|
||||
mDate = new Date();
|
||||
}
|
||||
|
||||
@@ -273,10 +335,10 @@ public class Summarizer {
|
||||
|
||||
txt.append("TOTAL: " + getTotalTestCount() + "\n");
|
||||
txt.append("CRASHED (among all tests): " + mCrashedTestsCount + "\n");
|
||||
txt.append("UNEXPECTED FAILURES: " + mUnexpectedFailures.size() + "\n");
|
||||
txt.append("UNEXPECTED PASSES: " + mUnexpectedPasses.size() + "\n");
|
||||
txt.append("EXPECTED FAILURES: " + mExpectedFailures.size() + "\n");
|
||||
txt.append("EXPECTED PASSES: " + mExpectedPasses.size() + "\n");
|
||||
txt.append("UNEXPECTED FAILURES: " + mUnexpectedFailuresCursor.getCount() + "\n");
|
||||
txt.append("UNEXPECTED PASSES: " + mUnexpectedPassesCursor.getCount() + "\n");
|
||||
txt.append("EXPECTED FAILURES: " + mExpectedFailuresCursor.getCount() + "\n");
|
||||
txt.append("EXPECTED PASSES: " + mExpectedPassesCursor.getCount() + "\n");
|
||||
|
||||
FsUtils.writeDataToStorage(new File(mResultsRootDirPath, TXT_SUMMARY_RELATIVE_PATH),
|
||||
txt.toString().getBytes(), false);
|
||||
@@ -293,20 +355,20 @@ public class Summarizer {
|
||||
createTopSummaryTable(webKitRevision, html);
|
||||
dumpHtmlToFile(html, false);
|
||||
|
||||
createResultsList(html, "Unexpected failures", mUnexpectedFailures);
|
||||
createResultsList(html, "Unexpected passes", mUnexpectedPasses);
|
||||
createResultsList(html, "Expected failures", mExpectedFailures);
|
||||
createResultsList(html, "Expected passes", mExpectedPasses);
|
||||
createResultsList(html, "Unexpected failures", mUnexpectedFailuresCursor);
|
||||
createResultsList(html, "Unexpected passes", mUnexpectedPassesCursor);
|
||||
createResultsList(html, "Expected failures", mExpectedFailuresCursor);
|
||||
createResultsList(html, "Expected passes", mExpectedPassesCursor);
|
||||
|
||||
html.append("</body></html>");
|
||||
dumpHtmlToFile(html, true);
|
||||
}
|
||||
|
||||
private int getTotalTestCount() {
|
||||
return mUnexpectedFailures.size() +
|
||||
mUnexpectedPasses.size() +
|
||||
mExpectedPasses.size() +
|
||||
mExpectedFailures.size();
|
||||
return mUnexpectedFailuresCursor.getCount() +
|
||||
mUnexpectedPassesCursor.getCount() +
|
||||
mExpectedPassesCursor.getCount() +
|
||||
mExpectedFailuresCursor.getCount();
|
||||
}
|
||||
|
||||
private String getWebKitVersionFromUserAgentString() {
|
||||
@@ -355,10 +417,10 @@ public class Summarizer {
|
||||
html.append("<table class=\"summary\">");
|
||||
createSummaryTableRow(html, "TOTAL", getTotalTestCount());
|
||||
createSummaryTableRow(html, "CRASHED (among all tests)", mCrashedTestsCount);
|
||||
createSummaryTableRow(html, "UNEXPECTED FAILURES", mUnexpectedFailures.size());
|
||||
createSummaryTableRow(html, "UNEXPECTED PASSES", mUnexpectedPasses.size());
|
||||
createSummaryTableRow(html, "EXPECTED FAILURES", mExpectedFailures.size());
|
||||
createSummaryTableRow(html, "EXPECTED PASSES", mExpectedPasses.size());
|
||||
createSummaryTableRow(html, "UNEXPECTED FAILURES", mUnexpectedFailuresCursor.getCount());
|
||||
createSummaryTableRow(html, "UNEXPECTED PASSES", mUnexpectedPassesCursor.getCount());
|
||||
createSummaryTableRow(html, "EXPECTED FAILURES", mExpectedFailuresCursor.getCount());
|
||||
createSummaryTableRow(html, "EXPECTED PASSES", mExpectedPassesCursor.getCount());
|
||||
html.append("</table>");
|
||||
}
|
||||
|
||||
@@ -370,14 +432,21 @@ public class Summarizer {
|
||||
}
|
||||
|
||||
private void createResultsList(
|
||||
StringBuilder html, String title, List<AbstractResult> resultsList) {
|
||||
StringBuilder html, String title, Cursor cursor) {
|
||||
String relativePath;
|
||||
String id = "";
|
||||
AbstractResult.ResultCode resultCode;
|
||||
|
||||
Collections.sort(resultsList);
|
||||
html.append("<h2>" + title + " [" + resultsList.size() + "]</h2>");
|
||||
for (AbstractResult result : resultsList) {
|
||||
html.append("<h2>" + title + " [" + cursor.getCount() + "]</h2>");
|
||||
|
||||
if (!cursor.moveToFirst()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractResult result;
|
||||
do {
|
||||
result = SummarizerDBHelper.getAbstractResult(cursor);
|
||||
|
||||
relativePath = result.getRelativePath();
|
||||
resultCode = result.getResultCode();
|
||||
|
||||
@@ -429,7 +498,9 @@ public class Summarizer {
|
||||
if (++mResultsSinceLastHtmlDump == RESULTS_PER_DUMP) {
|
||||
dumpHtmlToFile(html, true);
|
||||
}
|
||||
}
|
||||
|
||||
cursor.moveToNext();
|
||||
} while (!cursor.isAfterLast());
|
||||
}
|
||||
|
||||
private void appendTags(StringBuilder html, AbstractResult result) {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.dumprendertree2;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A basic class that wraps database accesses inside itself and provides functionality to
|
||||
* store and retrieve AbstractResults.
|
||||
*/
|
||||
public class SummarizerDBHelper {
|
||||
private static final String KEY_ID = "id";
|
||||
private static final String KEY_PATH = "path";
|
||||
private static final String KEY_BYTES = "bytes";
|
||||
|
||||
private static final String DATABASE_NAME = "SummarizerDB";
|
||||
private static final int DATABASE_VERSION = 1;
|
||||
|
||||
static final String EXPECTED_FAILURES_TABLE = "expectedFailures";
|
||||
static final String UNEXPECTED_FAILURES_TABLE = "unexpectedFailures";
|
||||
static final String EXPECTED_PASSES_TABLE = "expextedPasses";
|
||||
static final String UNEXPECTED_PASSES_TABLE = "unexpextedPasses";
|
||||
private static final Set<String> TABLES_NAMES = new HashSet<String>();
|
||||
{
|
||||
TABLES_NAMES.add(EXPECTED_FAILURES_TABLE);
|
||||
TABLES_NAMES.add(EXPECTED_PASSES_TABLE);
|
||||
TABLES_NAMES.add(UNEXPECTED_FAILURES_TABLE);
|
||||
TABLES_NAMES.add(UNEXPECTED_PASSES_TABLE);
|
||||
}
|
||||
|
||||
private static final void createTables(SQLiteDatabase db) {
|
||||
String cmd;
|
||||
for (String tableName : TABLES_NAMES) {
|
||||
cmd = "create table " + tableName + " ("
|
||||
+ KEY_ID + " integer primary key autoincrement, "
|
||||
+ KEY_PATH + " text not null, "
|
||||
+ KEY_BYTES + " blob not null);";
|
||||
db.execSQL(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
private static final void dropTables(SQLiteDatabase db) {
|
||||
for (String tableName : TABLES_NAMES) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + tableName);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||
DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
dropTables(db);
|
||||
createTables(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
/** NOOP for now, because we will never upgrade the db */
|
||||
}
|
||||
|
||||
public void reset(SQLiteDatabase db) {
|
||||
dropTables(db);
|
||||
createTables(db);
|
||||
}
|
||||
}
|
||||
|
||||
private DatabaseHelper mDbHelper;
|
||||
private SQLiteDatabase mDb;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public SummarizerDBHelper(Context ctx) {
|
||||
mContext = ctx;
|
||||
mDbHelper = new DatabaseHelper(mContext);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mDbHelper.reset(this.mDb);
|
||||
}
|
||||
|
||||
public void open() throws SQLException {
|
||||
mDb = mDbHelper.getWritableDatabase();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mDbHelper.close();
|
||||
}
|
||||
|
||||
public void insertAbstractResult(AbstractResult result, String table) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(KEY_PATH, result.getRelativePath());
|
||||
cv.put(KEY_BYTES, result.getBytes());
|
||||
mDb.insert(table, null, cv);
|
||||
}
|
||||
|
||||
public Cursor getAbstractResults(String table) throws SQLException {
|
||||
return mDb.query(false, table, new String[] {KEY_BYTES}, null, null, null, null,
|
||||
KEY_PATH + " ASC", null);
|
||||
}
|
||||
|
||||
public static AbstractResult getAbstractResult(Cursor cursor) {
|
||||
return AbstractResult.create(cursor.getBlob(cursor.getColumnIndex(KEY_BYTES)));
|
||||
}
|
||||
}
|
||||
@@ -41,11 +41,11 @@ public class TextResult extends AbstractResult {
|
||||
private String mRelativePath;
|
||||
private boolean mDidTimeOut;
|
||||
private ResultCode mResultCode;
|
||||
private Message mResultObtainedMsg;
|
||||
transient private Message mResultObtainedMsg;
|
||||
|
||||
private boolean mDumpChildFramesAsText;
|
||||
|
||||
private Handler mHandler = new Handler() {
|
||||
transient private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == MSG_DOCUMENT_AS_TEXT) {
|
||||
@@ -78,6 +78,13 @@ public class TextResult extends AbstractResult {
|
||||
mDidTimeOut = bundle.getBoolean("didTimeOut");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearResults() {
|
||||
super.clearResults();
|
||||
mExpectedResult = null;
|
||||
mActualResult = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultCode getResultCode() {
|
||||
if (mResultCode != null) {
|
||||
|
||||
Reference in New Issue
Block a user