Bug 1046709 - Part 5: Delete history db extensions related stuff r=nalexander,rnewman

- class
- tests

MozReview-Commit-ID: LwHo5Ej2FGS

--HG--
extra : transplant_source : %DFt%9B%C6gy%F3q%90%7Fc%FE%22%B5%BD%F85%FE%E4%1A
This commit is contained in:
Grigory Kruglov 2016-04-12 15:52:53 -07:00
Родитель 774870136d
Коммит a8a4a8f16c
8 изменённых файлов: 0 добавлений и 459 удалений

Просмотреть файл

@ -227,8 +227,6 @@ public class BrowserContract {
public static final String TABLE_NAME = "visits";
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "visits");
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/visits";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/visits";
}
// Combined bookmarks and history

Просмотреть файл

@ -13,7 +13,6 @@ import org.mozilla.gecko.background.fxa.oauth.FxAccountOAuthClient10;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager;
import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter;
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryDataExtender;
import org.mozilla.gecko.sync.repositories.android.ClientsDatabase;
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
@ -87,22 +86,6 @@ public class FxAccountDeletedService extends IntentService {
Logger.warn(LOG_TAG, "Got exception deleting the Firefox Sync clients database; ignoring.", e);
}
// Clear Firefox Sync history data table.
try {
Logger.info(LOG_TAG, "Deleting the Firefox Sync extended history database.");
AndroidBrowserHistoryDataExtender historyDataExtender = null;
try {
historyDataExtender = new AndroidBrowserHistoryDataExtender(context);
historyDataExtender.wipe();
} finally {
if (historyDataExtender != null) {
historyDataExtender.close();
}
}
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception deleting the Firefox Sync extended history database; ignoring.", e);
}
// Remove any displayed notifications.
new FxAccountNotificationManager(FxAccountSyncAdapter.NOTIFICATION_ID).clear(context);

Просмотреть файл

@ -1,187 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.repositories.android;
import java.util.ArrayList;
import org.json.simple.JSONArray;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.sync.repositories.NullCursorException;
import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
public class AndroidBrowserHistoryDataExtender extends CachedSQLiteOpenHelper {
public static final String LOG_TAG = "SyncHistoryVisits";
// Database Specifications.
protected static final String DB_NAME = "history_extension_database";
protected static final int SCHEMA_VERSION = 1;
// History Table.
public static final String TBL_HISTORY_EXT = "HistoryExtension";
public static final String COL_GUID = "guid";
public static final String GUID_IS = COL_GUID + " = ?";
public static final String COL_VISITS = "visits";
public static final String[] TBL_COLUMNS = { COL_GUID, COL_VISITS };
private final RepoUtils.QueryHelper queryHelper;
public AndroidBrowserHistoryDataExtender(Context context) {
super(context, DB_NAME, null, SCHEMA_VERSION);
this.queryHelper = new RepoUtils.QueryHelper(context, null, LOG_TAG);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTableSql = "CREATE TABLE " + TBL_HISTORY_EXT + " ("
+ COL_GUID + " TEXT PRIMARY KEY, "
+ COL_VISITS + " TEXT)";
db.execSQL(createTableSql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// For now we'll just drop and recreate the tables.
db.execSQL("DROP TABLE IF EXISTS " + TBL_HISTORY_EXT);
onCreate(db);
}
public void wipe() {
SQLiteDatabase db = this.getCachedWritableDatabase();
onUpgrade(db, SCHEMA_VERSION, SCHEMA_VERSION);
}
/**
* Store visit data.
*
* If a row with GUID `guid` does not exist, insert a new row.
* If a row with GUID `guid` does exist, replace the visits column.
*
* @param db The database to write to; must not be null.
* @param guid The GUID to store to; must not be null.
* @param visits New visits data.
*/
protected void store(SQLiteDatabase db, String guid, JSONArray visits) {
ContentValues cv = new ContentValues();
cv.put(COL_GUID, guid);
if (visits == null) {
cv.put(COL_VISITS, "[]");
} else {
cv.put(COL_VISITS, visits.toJSONString());
}
String[] args = new String[] { guid };
int rowsUpdated = db.update(TBL_HISTORY_EXT, cv, GUID_IS, args);
if (rowsUpdated >= 1) {
Logger.debug(LOG_TAG, "Replaced history extension record for row with GUID " + guid);
} else {
long rowId = db.insert(TBL_HISTORY_EXT, null, cv);
Logger.debug(LOG_TAG, "Inserted history extension record into row: " + rowId);
}
}
/**
* Store visit data.
*
* If a row with GUID `guid` does not exist, insert a new row.
* If a row with GUID `guid` does exist, replace the visits column.
*
* @param guid the GUID to store; must not be null.
* @param visits new visits data.
*/
public void store(String guid, JSONArray visits) {
SQLiteDatabase db = this.getCachedWritableDatabase();
store(db, guid, visits);
}
/**
* Store (update or insert) visit data in a single database transaction.
*/
public void bulkInsert(ArrayList<HistoryRecord> records) {
SQLiteDatabase db = this.getCachedWritableDatabase();
try {
db.beginTransaction();
for (HistoryRecord record : records) {
store(db, record.guid, record.visits);
}
db.setTransactionSuccessful();
} catch (SQLException e) {
Logger.error(LOG_TAG, "Caught exception in bulkInsert new history visits.", e);
} finally {
db.endTransaction();
}
}
/**
* Fetch a row.
*
* @param guid The GUID of the row to fetch.
* @return A Cursor.
* @throws NullCursorException
*/
public Cursor fetch(String guid) throws NullCursorException {
String[] args = new String[] { guid };
SQLiteDatabase db = this.getCachedReadableDatabase();
Cursor cur = queryHelper.safeQuery(db, ".fetch",
TBL_HISTORY_EXT, TBL_COLUMNS, GUID_IS, args);
return cur;
}
public JSONArray visitsForGUID(String guid) throws NullCursorException {
if (guid == null) {
Logger.warn(LOG_TAG, "Asked for visits for null GUID.");
return new JSONArray();
}
Logger.debug(LOG_TAG, "Fetching visits for GUID " + guid);
Cursor visits = fetch(guid);
try {
if (!visits.moveToFirst()) {
// Cursor is empty.
return new JSONArray();
} else {
return RepoUtils.getJSONArrayFromCursor(visits, COL_VISITS);
}
} finally {
visits.close();
}
}
/**
* Delete a row.
*
* @param guid the GUID of the row to delete.
* @return The number of rows deleted, either 0 (if a row with this GUID does not exist) or 1.
*/
public int delete(String guid) {
String[] args = new String[] { guid };
SQLiteDatabase db = this.getCachedWritableDatabase();
return db.delete(TBL_HISTORY_EXT, GUID_IS, args);
}
/**
* Fetch all rows.
*
* @return a <code>Cursor</code>.
* @throws NullCursorException
*/
public Cursor fetchAll() throws NullCursorException {
SQLiteDatabase db = this.getCachedReadableDatabase();
Cursor cur = queryHelper.safeQuery(db, ".fetchAll", TBL_HISTORY_EXT,
TBL_COLUMNS,
null, null);
return cur;
}
}

Просмотреть файл

@ -11,10 +11,8 @@ background_junit3_sources = [
'src/org/mozilla/gecko/background/common/TestWaitHelper.java',
'src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java',
'src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java',
'src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java',
'src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java',
'src/org/mozilla/gecko/background/db/TestBookmarks.java',
'src/org/mozilla/gecko/background/db/TestCachedSQLiteOpenHelper.java',
'src/org/mozilla/gecko/background/db/TestClientsDatabase.java',
'src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java',
'src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java',

Просмотреть файл

@ -6,10 +6,8 @@ subsuite = background
[src/org/mozilla/gecko/background/common/TestUtils.java]
[src/org/mozilla/gecko/background/common/TestWaitHelper.java]
[src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java]
[src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java]
[src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java]
[src/org/mozilla/gecko/background/db/TestBookmarks.java]
[src/org/mozilla/gecko/background/db/TestCachedSQLiteOpenHelper.java]
[src/org/mozilla/gecko/background/db/TestClientsDatabase.java]
[src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java]
[src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java]

Просмотреть файл

@ -1,145 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.gecko.background.db;
import android.database.Cursor;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
import org.mozilla.gecko.background.sync.helpers.HistoryHelpers;
import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.repositories.NullCursorException;
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryDataExtender;
import org.mozilla.gecko.sync.repositories.android.RepoUtils;
import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
import java.util.ArrayList;
public class TestAndroidBrowserHistoryDataExtender extends AndroidSyncTestCase {
protected AndroidBrowserHistoryDataExtender extender;
protected static final String LOG_TAG = "SyncHistoryVisitsTest";
public void setUp() {
extender = new AndroidBrowserHistoryDataExtender(getApplicationContext());
extender.wipe();
}
public void tearDown() {
extender.close();
}
public void testStoreFetch() throws Exception {
String guid = Utils.generateGuid();
extender.store(Utils.generateGuid(), null);
extender.store(guid, null);
extender.store(Utils.generateGuid(), null);
Cursor cur = null;
try {
cur = extender.fetch(guid);
assertEquals(1, cur.getCount());
assertTrue(cur.moveToFirst());
assertEquals(guid, cur.getString(0));
} finally {
if (cur != null) {
cur.close();
}
}
}
public void testVisitsForGUID() throws Exception {
String guid = Utils.generateGuid();
JSONArray visits = new ExtendedJSONObject("{ \"visits\": [ { \"key\" : \"value\" } ] }").getArray("visits");
extender.store(Utils.generateGuid(), null);
extender.store(guid, visits);
extender.store(Utils.generateGuid(), null);
JSONArray fetchedVisits = extender.visitsForGUID(guid);
assertEquals(1, fetchedVisits.size());
assertEquals("value", ((JSONObject)fetchedVisits.get(0)).get("key"));
}
public void testDeleteHandlesBadGUIDs() {
String evilGUID = "' or '1'='1";
extender.store(Utils.generateGuid(), null);
extender.store(Utils.generateGuid(), null);
extender.store(evilGUID, null);
extender.delete(evilGUID);
Cursor cur = null;
try {
cur = extender.fetchAll();
assertEquals(cur.getCount(), 2);
assertTrue(cur.moveToFirst());
while (!cur.isAfterLast()) {
String guid = RepoUtils.getStringFromCursor(cur, AndroidBrowserHistoryDataExtender.COL_GUID);
assertFalse(evilGUID.equals(guid));
cur.moveToNext();
}
} catch (NullCursorException e) {
e.printStackTrace();
fail("Should not have null cursor.");
} finally {
if (cur != null) {
cur.close();
}
}
}
public void testStoreFetchHandlesBadGUIDs() {
String evilGUID = "' or '1'='1";
extender.store(Utils.generateGuid(), null);
extender.store(Utils.generateGuid(), null);
extender.store(evilGUID, null);
Cursor cur = null;
try {
cur = extender.fetch(evilGUID);
assertEquals(1, cur.getCount());
assertTrue(cur.moveToFirst());
while (!cur.isAfterLast()) {
String guid = RepoUtils.getStringFromCursor(cur, AndroidBrowserHistoryDataExtender.COL_GUID);
assertEquals(evilGUID, guid);
cur.moveToNext();
}
} catch (NullCursorException e) {
e.printStackTrace();
fail("Should not have null cursor.");
} finally {
if (cur != null) {
cur.close();
}
}
}
public void testBulkInsert() throws NullCursorException {
ArrayList<HistoryRecord> records = new ArrayList<HistoryRecord>();
records.add(HistoryHelpers.createHistory1());
records.add(HistoryHelpers.createHistory2());
extender.bulkInsert(records);
for (HistoryRecord record : records) {
HistoryRecord toCompare = (HistoryRecord) record.copyWithIDs(record.guid, record.androidID);
toCompare.visits = extender.visitsForGUID(record.guid);
assertEquals(record.visits.size(), toCompare.visits.size());
assertTrue(record.equals(toCompare));
}
// Now insert existing records, changing one, and add another record.
records.get(0).title = "test";
records.add(HistoryHelpers.createHistory3());
extender.bulkInsert(records);
for (HistoryRecord record : records) {
HistoryRecord toCompare = (HistoryRecord) record.copyWithIDs(record.guid, record.androidID);
toCompare.visits = extender.visitsForGUID(record.guid);
assertEquals(record.visits.size(), toCompare.visits.size());
assertTrue(record.equals(toCompare));
}
}
}

Просмотреть файл

@ -7,11 +7,9 @@ import java.util.ArrayList;
import org.json.simple.JSONObject;
import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate;
import org.mozilla.gecko.background.sync.helpers.HistoryHelpers;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.repositories.InactiveSessionException;
import org.mozilla.gecko.sync.repositories.NullCursorException;
import org.mozilla.gecko.sync.repositories.Repository;
import org.mozilla.gecko.sync.repositories.RepositorySession;
@ -20,7 +18,6 @@ import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryReposito
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryRepositorySession;
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepository;
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor;
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositorySession;
import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
import org.mozilla.gecko.sync.repositories.android.RepoUtils;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
@ -61,14 +58,6 @@ public class TestAndroidBrowserHistoryRepository extends AndroidBrowserRepositor
return new AndroidBrowserHistoryDataAccessor(getApplicationContext());
}
@Override
protected void closeDataAccessor(AndroidBrowserRepositoryDataAccessor dataAccessor) {
if (!(dataAccessor instanceof AndroidBrowserHistoryDataAccessor)) {
throw new IllegalArgumentException("Only expecting a history data accessor.");
}
((AndroidBrowserHistoryDataAccessor) dataAccessor).closeExtender();
}
@Override
public void testFetchAll() {
Record[] expected = new Record[2];
@ -458,41 +447,4 @@ public class TestAndroidBrowserHistoryRepository extends AndroidBrowserRepositor
performWait(fetchAllRunnable(session, preparedExpectFetchDelegate(records.toArray(new Record[records.size()]))));
session.abort();
}
public void testDataExtenderIsClosedBeforeBegin() {
// Create a session but don't begin() it.
final AndroidBrowserRepositorySession session = (AndroidBrowserRepositorySession) createSession();
AndroidBrowserHistoryDataAccessor db = (AndroidBrowserHistoryDataAccessor) session.getDBHelper();
// Confirm dataExtender is closed before beginning session.
assertTrue(db.getHistoryDataExtender().isClosed());
}
public void testDataExtenderIsClosedAfterFinish() throws InactiveSessionException {
final AndroidBrowserHistoryRepositorySession session = (AndroidBrowserHistoryRepositorySession) createAndBeginSession();
AndroidBrowserHistoryDataAccessor db = (AndroidBrowserHistoryDataAccessor) session.getDBHelper();
// Perform an action that opens the dataExtender.
HistoryRecord h1 = HistoryHelpers.createHistory1();
db.insert(h1);
assertFalse(db.getHistoryDataExtender().isClosed());
// Check dataExtender is closed upon finish.
performWait(finishRunnable(session, new ExpectFinishDelegate()));
assertTrue(db.getHistoryDataExtender().isClosed());
}
public void testDataExtenderIsClosedAfterAbort() throws InactiveSessionException {
final AndroidBrowserHistoryRepositorySession session = (AndroidBrowserHistoryRepositorySession) createAndBeginSession();
AndroidBrowserHistoryDataAccessor db = (AndroidBrowserHistoryDataAccessor) session.getDBHelper();
// Perform an action that opens the dataExtender.
HistoryRecord h1 = HistoryHelpers.createHistory1();
db.insert(h1);
assertFalse(db.getHistoryDataExtender().isClosed());
// Check dataExtender is closed upon abort.
session.abort();
assertTrue(db.getHistoryDataExtender().isClosed());
}
}

Просмотреть файл

@ -1,56 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.gecko.background.db;
import org.mozilla.gecko.background.sync.helpers.HistoryHelpers;
import org.mozilla.gecko.sync.repositories.NullCursorException;
import org.mozilla.gecko.sync.repositories.android.AndroidBrowserHistoryDataExtender;
import org.mozilla.gecko.sync.repositories.android.ClientsDatabase;
import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
import org.mozilla.gecko.sync.repositories.domain.HistoryRecord;
import org.mozilla.gecko.sync.setup.Constants;
import android.database.Cursor;
import android.test.AndroidTestCase;
public class TestCachedSQLiteOpenHelper extends AndroidTestCase {
protected ClientsDatabase clientsDB;
protected AndroidBrowserHistoryDataExtender extender;
public void setUp() {
clientsDB = new ClientsDatabase(mContext);
extender = new AndroidBrowserHistoryDataExtender(mContext);
}
public void tearDown() {
clientsDB.close();
extender.close();
}
public void testUnclosedDatabasesDontInteract() throws NullCursorException {
// clientsDB gracefully does its thing and closes.
clientsDB.wipeClientsTable();
ClientRecord record = new ClientRecord();
String profileConst = Constants.DEFAULT_PROFILE;
clientsDB.store(profileConst, record);
clientsDB.close();
// extender does its thing but still hasn't closed.
HistoryRecord h = HistoryHelpers.createHistory1();
extender.store(h.guid, h.visits);
// Ensure items in the clientsDB are still accessible nonetheless.
Cursor cur = null;
try {
cur = clientsDB.fetchAllClients();
assertTrue(cur.moveToFirst());
assertEquals(1, cur.getCount());
} finally {
if (cur != null) {
cur.close();
}
}
}
}