Merge "Updated Summarizer to use SQLite DB."

This commit is contained in:
Maksymilian Osowski
2010-09-17 09:19:21 -07:00
committed by Android (Google) Code Review
5 changed files with 297 additions and 30 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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) {

View File

@@ -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)));
}
}

View File

@@ -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) {