зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1046709 - Part 2: CRUD for Visits - query/insert/delete; tests. r=nalexander,rnewman
Note: need to set package name in robolectric.properties so that Robolectric reads correct resources MozReview-Commit-ID: 6wrh8kzJlXI --HG-- extra : transplant_source : %86T%8BUB%ABe%0A%DF8%F0%81%0C%ACi%D1Rx%E2%EC
This commit is contained in:
Родитель
1ab053d2cf
Коммит
1dab7ae855
|
@ -8,6 +8,7 @@ package org.mozilla.gecko.db;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mozilla.gecko.AboutPages;
|
||||
|
@ -18,6 +19,7 @@ import org.mozilla.gecko.db.BrowserContract.Combined;
|
|||
import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.Favicons;
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
import org.mozilla.gecko.db.BrowserContract.Visits;
|
||||
import org.mozilla.gecko.db.BrowserContract.Schema;
|
||||
import org.mozilla.gecko.db.BrowserContract.Tabs;
|
||||
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
|
||||
|
@ -63,6 +65,7 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
|
||||
static final String TABLE_BOOKMARKS = Bookmarks.TABLE_NAME;
|
||||
static final String TABLE_HISTORY = History.TABLE_NAME;
|
||||
static final String TABLE_VISITS = Visits.TABLE_NAME;
|
||||
static final String TABLE_FAVICONS = Favicons.TABLE_NAME;
|
||||
static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME;
|
||||
static final String TABLE_TABS = Tabs.TABLE_NAME;
|
||||
|
@ -110,11 +113,14 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
|
||||
static final int TOPSITES = 1000;
|
||||
|
||||
static final int VISITS = 1100;
|
||||
|
||||
static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.TYPE
|
||||
+ " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID
|
||||
+ " ASC";
|
||||
|
||||
static final String DEFAULT_HISTORY_SORT_ORDER = History.DATE_LAST_VISITED + " DESC";
|
||||
static final String DEFAULT_VISITS_SORT_ORDER = Visits.DATE_VISITED + " DESC";
|
||||
|
||||
static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
|
@ -125,6 +131,7 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
static final Map<String, String> FAVICONS_PROJECTION_MAP;
|
||||
static final Map<String, String> THUMBNAILS_PROJECTION_MAP;
|
||||
static final Map<String, String> URL_ANNOTATIONS_PROJECTION_MAP;
|
||||
static final Map<String, String> VISIT_PROJECTION_MAP;
|
||||
static final Table[] sTables;
|
||||
|
||||
static {
|
||||
|
@ -181,6 +188,17 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
map.put(History.IS_DELETED, History.IS_DELETED);
|
||||
HISTORY_PROJECTION_MAP = Collections.unmodifiableMap(map);
|
||||
|
||||
// Visits
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "visits", VISITS);
|
||||
|
||||
map = new HashMap<String, String>();
|
||||
map.put(Visits._ID, Visits._ID);
|
||||
map.put(Visits.HISTORY_GUID, Visits.HISTORY_GUID);
|
||||
map.put(Visits.VISIT_TYPE, Visits.VISIT_TYPE);
|
||||
map.put(Visits.DATE_VISITED, Visits.DATE_VISITED);
|
||||
map.put(Visits.IS_LOCAL, Visits.IS_LOCAL);
|
||||
VISIT_PROJECTION_MAP = Collections.unmodifiableMap(map);
|
||||
|
||||
// Favicons
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "favicons", FAVICONS);
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "favicons/#", FAVICON_ID);
|
||||
|
@ -423,11 +441,27 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
case HISTORY: {
|
||||
trace("Deleting history: " + uri);
|
||||
beginWrite(db);
|
||||
/**
|
||||
* Deletes from Sync are actual DELETE statements, which will cascade delete relevant visits.
|
||||
* Fennec's deletes mark records as deleted and wipe out all information (except for GUID).
|
||||
* Eventually, Fennec will purge history records that were marked as deleted for longer than some
|
||||
* period of time (e.g. 20 days).
|
||||
* See {@link SharedBrowserDatabaseProvider#cleanUpSomeDeletedRecords(Uri, String)}.
|
||||
*/
|
||||
if (!isCallerSync(uri)) {
|
||||
deleteVisitsForHistory(uri, selection, selectionArgs);
|
||||
}
|
||||
deleted = deleteHistory(uri, selection, selectionArgs);
|
||||
deleteUnusedImages(uri);
|
||||
break;
|
||||
}
|
||||
|
||||
case VISITS:
|
||||
trace("Deleting visits: " + uri);
|
||||
beginWrite(db);
|
||||
deleted = deleteVisits(uri, selection, selectionArgs);
|
||||
break;
|
||||
|
||||
case HISTORY_OLD: {
|
||||
String priority = uri.getQueryParameter(BrowserContract.PARAM_EXPIRE_PRIORITY);
|
||||
long keepAfter = System.currentTimeMillis() - DEFAULT_EXPIRY_PRESERVE_WINDOW;
|
||||
|
@ -512,6 +546,12 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
break;
|
||||
}
|
||||
|
||||
case VISITS: {
|
||||
trace("Insert on VISITS: " + uri);
|
||||
id = insertVisit(uri, values);
|
||||
break;
|
||||
}
|
||||
|
||||
case FAVICONS: {
|
||||
trace("Insert on FAVICONS: " + uri);
|
||||
id = insertFavicon(uri, values);
|
||||
|
@ -617,6 +657,9 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
} else {
|
||||
updated = updateHistory(uri, values, selection, selectionArgs);
|
||||
}
|
||||
if (shouldIncrementVisits(uri)) {
|
||||
insertVisitForHistory(uri, values, selection, selectionArgs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1039,6 +1082,16 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
break;
|
||||
}
|
||||
|
||||
case VISITS:
|
||||
debug("Query is on visits: " + uri);
|
||||
qb.setProjectionMap(VISIT_PROJECTION_MAP);
|
||||
qb.setTables(TABLE_VISITS);
|
||||
|
||||
if (TextUtils.isEmpty(sortOrder)) {
|
||||
sortOrder = DEFAULT_VISITS_SORT_ORDER;
|
||||
}
|
||||
break;
|
||||
|
||||
case FAVICON_ID:
|
||||
selection = DBUtils.concatenateWhere(selection, Favicons._ID + " = ?");
|
||||
selectionArgs = DBUtils.appendSelectionArgs(selectionArgs,
|
||||
|
@ -1364,32 +1417,85 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
|
||||
trace("Updating history meta data and incrementing visits");
|
||||
|
||||
// We might be altering the ContentValues, so let's use a copy.
|
||||
final ContentValues valuesForUpdate = new ContentValues(values);
|
||||
|
||||
// Update data and increment visits by 1.
|
||||
long incVisits = 1;
|
||||
if (valuesForUpdate.containsKey(History.VISITS)) {
|
||||
// Use a given visit count, if found.
|
||||
Long additional = valuesForUpdate.getAsLong(History.VISITS);
|
||||
if (additional != null) {
|
||||
incVisits = additional;
|
||||
}
|
||||
// Remove the visits from this set of values so we can pass the visits
|
||||
// as an expression.
|
||||
valuesForUpdate.remove(History.VISITS);
|
||||
}
|
||||
final long incVisits = 1;
|
||||
|
||||
// Create a separate set of values that will be updated as an expression.
|
||||
final ContentValues visits = new ContentValues();
|
||||
visits.put(History.VISITS, History.VISITS + " + " + incVisits);
|
||||
|
||||
final ContentValues[] valuesAndVisits = { valuesForUpdate, visits };
|
||||
final ContentValues[] valuesAndVisits = { values, visits };
|
||||
final UpdateOperation[] ops = { UpdateOperation.ASSIGN, UpdateOperation.EXPRESSION };
|
||||
|
||||
return DBUtils.updateArrays(db, TABLE_HISTORY, valuesAndVisits, ops, selection, selectionArgs);
|
||||
}
|
||||
|
||||
private long insertVisitForHistory(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
trace("Inserting visit for history on URI: " + uri);
|
||||
|
||||
final SQLiteDatabase db = getReadableDatabase(uri);
|
||||
|
||||
final Cursor cursor = db.query(
|
||||
History.TABLE_NAME, new String[] {History.GUID}, selection, selectionArgs,
|
||||
null, null, null);
|
||||
if (cursor == null) {
|
||||
Log.e(LOGTAG, "Null cursor while trying to insert visit for history URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
final ContentValues[] visitValues;
|
||||
try {
|
||||
visitValues = new ContentValues[cursor.getCount()];
|
||||
|
||||
if (!cursor.moveToFirst()) {
|
||||
Log.e(LOGTAG, "No history records found while inserting visit(s) for history URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sync works in microseconds, so we store visit timestamps in microseconds as well.
|
||||
// History timestamps are in milliseconds.
|
||||
// This is the conversion point for locally generated visits.
|
||||
final long visitDate;
|
||||
if (values.containsKey(History.DATE_LAST_VISITED)) {
|
||||
visitDate = values.getAsLong(History.DATE_LAST_VISITED) * 1000;
|
||||
} else {
|
||||
visitDate = System.currentTimeMillis() * 1000;
|
||||
}
|
||||
|
||||
final int guidColumn = cursor.getColumnIndexOrThrow(History.GUID);
|
||||
while (!cursor.isAfterLast()) {
|
||||
final ContentValues visit = new ContentValues();
|
||||
visit.put(Visits.HISTORY_GUID, cursor.getString(guidColumn));
|
||||
visit.put(Visits.DATE_VISITED, visitDate);
|
||||
visitValues[cursor.getPosition()] = visit;
|
||||
cursor.moveToNext();
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
if (visitValues.length == 1) {
|
||||
return insertVisit(Visits.CONTENT_URI, visitValues[0]);
|
||||
} else {
|
||||
return bulkInsert(Visits.CONTENT_URI, visitValues);
|
||||
}
|
||||
}
|
||||
|
||||
private long insertVisit(Uri uri, ContentValues values) {
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
|
||||
debug("Inserting history in database with URL: " + uri);
|
||||
beginWrite(db);
|
||||
|
||||
// We ignore insert conflicts here to simplify inserting visits records coming in from Sync.
|
||||
// Visits table has a unique index on (history_guid,date), so a conflict might arise when we're
|
||||
// trying to insert history record visits coming in from sync which are already present locally
|
||||
// as a result of previous sync operations.
|
||||
// An alternative to doing this is to filter out already present records when we're doing history inserts
|
||||
// from Sync, which is a costly operation to do en masse.
|
||||
return db.insertWithOnConflict(
|
||||
TABLE_VISITS, null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
|
||||
private void updateFaviconIdsForUrl(SQLiteDatabase db, String pageUrl, Long faviconId) {
|
||||
ContentValues updateValues = new ContentValues(1);
|
||||
updateValues.put(FaviconColumns.FAVICON_ID, faviconId);
|
||||
|
@ -1625,6 +1731,61 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
return updated;
|
||||
}
|
||||
|
||||
private int deleteVisitsForHistory(Uri uri, String selection, String[] selectionArgs) {
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
|
||||
final Cursor cursor = db.query(
|
||||
History.TABLE_NAME, new String[] {History.GUID}, selection, selectionArgs,
|
||||
null, null, null);
|
||||
if (cursor == null) {
|
||||
Log.e(LOGTAG, "Null cursor while trying to delete visits for history URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ArrayList<String> historyGUIDs = new ArrayList<>();
|
||||
try {
|
||||
if (!cursor.moveToFirst()) {
|
||||
trace("No history items for which to remove visits matched for URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
final int historyColumn = cursor.getColumnIndexOrThrow(History.GUID);
|
||||
while (!cursor.isAfterLast()) {
|
||||
historyGUIDs.add(cursor.getString(historyColumn));
|
||||
cursor.moveToNext();
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Due to SQLite's maximum variable limitation, we need to chunk our delete statements.
|
||||
// For example, if there were 1200 GUIDs, this will perform 2 delete statements.
|
||||
int deleted = 0;
|
||||
for (int chunk = 0; chunk <= historyGUIDs.size() / DBUtils.SQLITE_MAX_VARIABLE_NUMBER; chunk++) {
|
||||
final int chunkStart = chunk * DBUtils.SQLITE_MAX_VARIABLE_NUMBER;
|
||||
int chunkEnd = (chunk + 1) * DBUtils.SQLITE_MAX_VARIABLE_NUMBER;
|
||||
if (chunkEnd > historyGUIDs.size()) {
|
||||
chunkEnd = historyGUIDs.size();
|
||||
}
|
||||
final List<String> chunkGUIDs = historyGUIDs.subList(chunkStart, chunkEnd);
|
||||
deleted += db.delete(
|
||||
Visits.TABLE_NAME,
|
||||
DBUtils.computeSQLInClause(chunkGUIDs.size(), Visits.HISTORY_GUID),
|
||||
chunkGUIDs.toArray(new String[chunkGUIDs.size()])
|
||||
);
|
||||
}
|
||||
|
||||
return deleted;
|
||||
}
|
||||
|
||||
private int deleteVisits(Uri uri, String selection, String[] selectionArgs) {
|
||||
debug("Deleting visits for URI: " + uri);
|
||||
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
|
||||
beginWrite(db);
|
||||
return db.delete(TABLE_VISITS, selection, selectionArgs);
|
||||
}
|
||||
|
||||
private int deleteBookmarks(Uri uri, String selection, String[] selectionArgs) {
|
||||
debug("Deleting bookmarks for URI: " + uri);
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ import java.util.Map;
|
|||
public class DBUtils {
|
||||
private static final String LOGTAG = "GeckoDBUtils";
|
||||
|
||||
public static final int SQLITE_MAX_VARIABLE_NUMBER = 999;
|
||||
|
||||
public static final String qualifyColumn(String table, String column) {
|
||||
return table + "." + column;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public class BrowserContractHelpers extends BrowserContract {
|
|||
public static final Uri BOOKMARKS_PARENTS_CONTENT_URI = withSyncAndDeletedAndProfile(Bookmarks.PARENTS_CONTENT_URI);
|
||||
public static final Uri BOOKMARKS_POSITIONS_CONTENT_URI = withSyncAndDeletedAndProfile(Bookmarks.POSITIONS_CONTENT_URI);
|
||||
public static final Uri HISTORY_CONTENT_URI = withSyncAndDeletedAndProfile(History.CONTENT_URI);
|
||||
public static final Uri VISITS_CONTENT_URI = withSyncAndDeletedAndProfile(Visits.CONTENT_URI);
|
||||
public static final Uri SCHEMA_CONTENT_URI = withSyncAndDeletedAndProfile(Schema.CONTENT_URI);
|
||||
public static final Uri PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(Passwords.CONTENT_URI);
|
||||
public static final Uri DELETED_PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(DeletedPasswords.CONTENT_URI);
|
||||
|
|
|
@ -0,0 +1,338 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mozilla.gecko.background.testhelpers.TestRunner;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(TestRunner.class)
|
||||
/**
|
||||
* Testing insertion/deletion of visits as by-product of updating history records through BrowserProvider
|
||||
*/
|
||||
public class BrowserProviderHistoryVisitsTest extends BrowserProviderHistoryVisitsTestBase {
|
||||
@Test
|
||||
/**
|
||||
* Testing updating history records without affecting visits
|
||||
*/
|
||||
public void testUpdateNoVisit() throws Exception {
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID");
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(0, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
ContentValues historyUpdate = new ContentValues();
|
||||
historyUpdate.put(History.TITLE, "Mozilla!");
|
||||
assertEquals(1,
|
||||
historyClient.update(
|
||||
historyTestUri, historyUpdate, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
)
|
||||
);
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(0, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
ContentValues historyToInsert = new ContentValues();
|
||||
historyToInsert.put(History.URL, "https://www.eff.org");
|
||||
assertEquals(1,
|
||||
historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
|
||||
historyToInsert, null, null
|
||||
)
|
||||
);
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(0, cursor.getCount());
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Testing INCREMENT_VISITS flag for multiple history records at once
|
||||
*/
|
||||
public void testUpdateMultipleHistoryIncrementVisit() throws Exception {
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID");
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID2");
|
||||
|
||||
// test that visits get inserted when updating existing history records
|
||||
assertEquals(2, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
|
||||
Cursor cursor = visitsClient.query(
|
||||
visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(2, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
|
||||
String guid1 = cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID));
|
||||
cursor.moveToNext();
|
||||
String guid2 = cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID));
|
||||
cursor.close();
|
||||
|
||||
assertNotEquals(guid1, guid2);
|
||||
|
||||
assertTrue(guid1.equals("testGUID") || guid1.equals("testGUID2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Testing INCREMENT_VISITS flag and its interplay with INSERT_IF_NEEDED
|
||||
*/
|
||||
public void testUpdateHistoryIncrementVisit() throws Exception {
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID");
|
||||
|
||||
// test that visit gets inserted when updating an existing histor record
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
|
||||
Cursor cursor = visitsClient.query(
|
||||
visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
assertEquals(
|
||||
"testGUID",
|
||||
cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID))
|
||||
);
|
||||
cursor.close();
|
||||
|
||||
// test that visit gets inserted when updatingOrInserting a new history record
|
||||
ContentValues historyItem = new ContentValues();
|
||||
historyItem.put(History.URL, "https://www.eff.org");
|
||||
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
|
||||
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
|
||||
historyItem, null, null
|
||||
));
|
||||
|
||||
cursor = historyClient.query(
|
||||
historyTestUri,
|
||||
new String[] {History.GUID}, History.URL + " = ?", new String[] {"https://www.eff.org"}, null
|
||||
);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
String insertedGUID = cursor.getString(cursor.getColumnIndex(History.GUID));
|
||||
cursor.close();
|
||||
|
||||
cursor = visitsClient.query(
|
||||
visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(2, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
assertEquals(insertedGUID,
|
||||
cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID))
|
||||
);
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that for locally generated visits, we store their timestamps in microseconds, and not in
|
||||
* milliseconds like history does.
|
||||
*/
|
||||
public void testTimestampConversionOnInsertion() throws Exception {
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID");
|
||||
|
||||
Long lastVisited = System.currentTimeMillis();
|
||||
ContentValues updatedVisitedTime = new ContentValues();
|
||||
updatedVisitedTime.put(History.DATE_LAST_VISITED, lastVisited);
|
||||
|
||||
// test with last visited date passed in
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
updatedVisitedTime, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, new String[] {BrowserContract.Visits.DATE_VISITED}, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
|
||||
assertEquals(lastVisited * 1000, cursor.getLong(cursor.getColumnIndex(BrowserContract.Visits.DATE_VISITED)));
|
||||
cursor.close();
|
||||
|
||||
// test without last visited date
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, new String[] {BrowserContract.Visits.DATE_VISITED}, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(2, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
|
||||
// CP should generate time off of current time upon insertion and convert to microseconds.
|
||||
// This also tests correct ordering (DESC on date).
|
||||
assertTrue(lastVisited * 1000 < cursor.getLong(cursor.getColumnIndex(BrowserContract.Visits.DATE_VISITED)));
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* This should perform `DELETE FROM visits WHERE history_guid in IN (?, ?, ?, ..., ?)` sort of statement
|
||||
* SQLite has a variable count limit (999 by default), so we're testing here that our deletion
|
||||
* code does the right thing and chunks deletes to account for this limitation.
|
||||
*/
|
||||
public void testDeletingLotsOfHistory() throws Exception {
|
||||
Uri incrementUri = historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build();
|
||||
|
||||
// insert bunch of history records, and for each insert a visit
|
||||
for (int i = 0; i < 2100; i++) {
|
||||
final String url = "https://www.mozilla" + i + ".org";
|
||||
insertHistoryItem(url, "testGUID" + i);
|
||||
assertEquals(1, historyClient.update(incrementUri, new ContentValues(), History.URL + " = ?", new String[] {url}));
|
||||
}
|
||||
|
||||
// sanity check
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(2100, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
// delete all of the history items - this will trigger chunked deletion of visits as well
|
||||
assertEquals(2100,
|
||||
historyClient.delete(historyTestUri, null, null)
|
||||
);
|
||||
|
||||
// check that all visits where deleted
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(0, cursor.getCount());
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test visit deletion as by-product of history deletion - both explicit (from outside of Sync),
|
||||
* and implicit (cascaded, from Sync).
|
||||
*/
|
||||
public void testDeletingHistory() throws Exception {
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID");
|
||||
insertHistoryItem("https://www.eff.org", "testGUID2");
|
||||
|
||||
// insert some visits
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.eff.org"}
|
||||
));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(3, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
// test that corresponding visit records are deleted if Sync isn't involved
|
||||
assertEquals(1,
|
||||
historyClient.delete(historyTestUri, History.URL + " = ?", new String[] {"https://www.mozilla.org"})
|
||||
);
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
// test that corresponding visit records are deleted if Sync is involved
|
||||
// insert some more visits
|
||||
ContentValues moz = new ContentValues();
|
||||
moz.put(History.URL, "https://www.mozilla.org");
|
||||
moz.put(History.GUID, "testGUID3");
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
|
||||
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
|
||||
moz, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
|
||||
.appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.eff.org"}
|
||||
));
|
||||
|
||||
assertEquals(1,
|
||||
historyClient.delete(
|
||||
historyTestUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_SYNC, "true").build(),
|
||||
History.URL + " = ?", new String[] {"https://www.eff.org"})
|
||||
);
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, new String[] {BrowserContract.Visits.HISTORY_GUID}, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
assertEquals("testGUID3", cursor.getString(cursor.getColumnIndex(BrowserContract.Visits.HISTORY_GUID)));
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that changes to History GUID are cascaded to individual visits.
|
||||
* See UPDATE CASCADED on Visit's HISTORY_GUID foreign key.
|
||||
*/
|
||||
public void testHistoryGUIDUpdate() throws Exception {
|
||||
insertHistoryItem("https://www.mozilla.org", "testGUID");
|
||||
insertHistoryItem("https://www.eff.org", "testGUID2");
|
||||
|
||||
// insert some visits
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
|
||||
new ContentValues(), History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
|
||||
// change testGUID -> testGUIDNew
|
||||
ContentValues newGuid = new ContentValues();
|
||||
newGuid.put(History.GUID, "testGUIDNew");
|
||||
assertEquals(1, historyClient.update(
|
||||
historyTestUri, newGuid, History.URL + " = ?", new String[] {"https://www.mozilla.org"}
|
||||
));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, BrowserContract.Visits.HISTORY_GUID + " = ?", new String[] {"testGUIDNew"}, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(2, cursor.getCount());
|
||||
cursor.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentValues;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
|
||||
import org.robolectric.shadows.ShadowContentResolver;
|
||||
|
||||
public class BrowserProviderHistoryVisitsTestBase {
|
||||
protected BrowserProvider provider;
|
||||
protected ContentProviderClient historyClient;
|
||||
protected ContentProviderClient visitsClient;
|
||||
protected Uri historyTestUri;
|
||||
protected Uri visitsTestUri;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
provider = new BrowserProvider();
|
||||
provider.onCreate();
|
||||
ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY_URI.toString(), provider);
|
||||
|
||||
final ShadowContentResolver cr = new ShadowContentResolver();
|
||||
historyClient = cr.acquireContentProviderClient(BrowserContractHelpers.HISTORY_CONTENT_URI);
|
||||
visitsClient = cr.acquireContentProviderClient(BrowserContractHelpers.VISITS_CONTENT_URI);
|
||||
|
||||
historyTestUri = testUri(BrowserContract.History.CONTENT_URI);
|
||||
visitsTestUri = testUri(BrowserContract.Visits.CONTENT_URI);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
historyClient.release();
|
||||
visitsClient.release();
|
||||
provider.shutdown();
|
||||
}
|
||||
|
||||
protected Uri testUri(Uri baseUri) {
|
||||
return baseUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_TEST, "1").build();
|
||||
}
|
||||
|
||||
protected Uri insertHistoryItem(String url, String guid) throws RemoteException {
|
||||
ContentValues historyItem = new ContentValues();
|
||||
historyItem.put(BrowserContract.History.URL, url);
|
||||
historyItem.put(BrowserContract.History.GUID, guid);
|
||||
|
||||
return historyClient.insert(historyTestUri, historyItem);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mozilla.gecko.background.testhelpers.TestRunner;
|
||||
import org.mozilla.gecko.db.BrowserContract.Visits;
|
||||
|
||||
@RunWith(TestRunner.class)
|
||||
/**
|
||||
* Testing direct interactions with visits through BrowserProvider
|
||||
*/
|
||||
public class BrowserProviderVisitsTest extends BrowserProviderHistoryVisitsTestBase {
|
||||
@Test
|
||||
/**
|
||||
* Test that default visit parameters are set on insert.
|
||||
*/
|
||||
public void testDefaultVisit() throws RemoteException {
|
||||
String url = "https://www.mozilla.org";
|
||||
String guid = "testGuid";
|
||||
|
||||
assertNotNull(insertHistoryItem(url, guid));
|
||||
|
||||
ContentValues visitItem = new ContentValues();
|
||||
Long visitedDate = System.currentTimeMillis();
|
||||
visitItem.put(Visits.HISTORY_GUID, guid);
|
||||
visitItem.put(Visits.DATE_VISITED, visitedDate);
|
||||
Uri insertedVisitUri = visitsClient.insert(visitsTestUri, visitItem);
|
||||
assertNotNull(insertedVisitUri);
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
try {
|
||||
assertTrue(cursor.moveToFirst());
|
||||
String insertedGuid = cursor.getString(cursor.getColumnIndex(Visits.HISTORY_GUID));
|
||||
assertEquals(guid, insertedGuid);
|
||||
|
||||
Long insertedDate = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(visitedDate, insertedDate);
|
||||
|
||||
Integer insertedType = cursor.getInt(cursor.getColumnIndex(Visits.VISIT_TYPE));
|
||||
assertEquals(insertedType, Integer.valueOf(1));
|
||||
|
||||
Integer insertedIsLocal = cursor.getInt(cursor.getColumnIndex(Visits.IS_LOCAL));
|
||||
assertEquals(insertedIsLocal, Integer.valueOf(1));
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that we can't insert visit for non-existing GUID.
|
||||
*/
|
||||
public void testMissingHistoryGuid() throws RemoteException {
|
||||
ContentValues visitItem = new ContentValues();
|
||||
visitItem.put(Visits.HISTORY_GUID, "blah");
|
||||
visitItem.put(Visits.DATE_VISITED, System.currentTimeMillis());
|
||||
assertNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that visit insert uses non-conflict insert.
|
||||
*/
|
||||
public void testNonConflictInsert() throws RemoteException {
|
||||
String url = "https://www.mozilla.org";
|
||||
String guid = "testGuid";
|
||||
|
||||
assertNotNull(insertHistoryItem(url, guid));
|
||||
|
||||
ContentValues visitItem = new ContentValues();
|
||||
Long visitedDate = System.currentTimeMillis();
|
||||
visitItem.put(Visits.HISTORY_GUID, guid);
|
||||
visitItem.put(Visits.DATE_VISITED, visitedDate);
|
||||
Uri insertedVisitUri = visitsClient.insert(visitsTestUri, visitItem);
|
||||
assertNotNull(insertedVisitUri);
|
||||
|
||||
Uri insertedVisitUri2 = visitsClient.insert(visitsTestUri, visitItem);
|
||||
assertEquals(insertedVisitUri, insertedVisitUri2);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that non-default visit parameters won't get overridden.
|
||||
*/
|
||||
public void testNonDefaultInsert() throws RemoteException {
|
||||
assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
|
||||
|
||||
Integer typeToInsert = 5;
|
||||
Integer isLocalToInsert = 0;
|
||||
|
||||
ContentValues visitItem = new ContentValues();
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
visitItem.put(Visits.DATE_VISITED, System.currentTimeMillis());
|
||||
visitItem.put(Visits.VISIT_TYPE, typeToInsert);
|
||||
visitItem.put(Visits.IS_LOCAL, isLocalToInsert);
|
||||
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
try {
|
||||
assertTrue(cursor.moveToFirst());
|
||||
|
||||
Integer insertedVisitType = cursor.getInt(cursor.getColumnIndex(Visits.VISIT_TYPE));
|
||||
assertEquals(typeToInsert, insertedVisitType);
|
||||
|
||||
Integer insertedIsLocal = cursor.getInt(cursor.getColumnIndex(Visits.IS_LOCAL));
|
||||
assertEquals(isLocalToInsert, insertedIsLocal);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that default sorting order (DATE_VISITED DESC) is set if we don't specify any sorting params
|
||||
*/
|
||||
public void testDefaultSortingOrder() throws RemoteException {
|
||||
assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
|
||||
|
||||
Long time1 = System.currentTimeMillis();
|
||||
Long time2 = time1 + 100;
|
||||
Long time3 = time1 + 200;
|
||||
|
||||
ContentValues visitItem = new ContentValues();
|
||||
visitItem.put(Visits.DATE_VISITED, time1);
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem.put(Visits.DATE_VISITED, time3);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem.put(Visits.DATE_VISITED, time2);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
try {
|
||||
assertEquals(3, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
|
||||
Long timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(time3, timeInserted);
|
||||
|
||||
cursor.moveToNext();
|
||||
|
||||
timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(time2, timeInserted);
|
||||
|
||||
cursor.moveToNext();
|
||||
|
||||
timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(time1, timeInserted);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test that if we pass sorting params, they're not overridden
|
||||
*/
|
||||
public void testNonDefaultSortingOrder() throws RemoteException {
|
||||
assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
|
||||
|
||||
Long time1 = System.currentTimeMillis();
|
||||
Long time2 = time1 + 100;
|
||||
Long time3 = time1 + 200;
|
||||
|
||||
ContentValues visitItem = new ContentValues();
|
||||
visitItem.put(Visits.DATE_VISITED, time1);
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem.put(Visits.DATE_VISITED, time3);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem.put(Visits.DATE_VISITED, time2);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, Visits.DATE_VISITED + " ASC");
|
||||
assertNotNull(cursor);
|
||||
assertEquals(3, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
|
||||
Long timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(time1, timeInserted);
|
||||
|
||||
cursor.moveToNext();
|
||||
|
||||
timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(time2, timeInserted);
|
||||
|
||||
cursor.moveToNext();
|
||||
|
||||
timeInserted = cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED));
|
||||
assertEquals(time3, timeInserted);
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Tests deletion of all visits, and by some selection (GUID, IS_LOCAL)
|
||||
*/
|
||||
public void testVisitDeletion() throws RemoteException {
|
||||
assertNotNull(insertHistoryItem("https://www.mozilla.org", "testGuid"));
|
||||
assertNotNull(insertHistoryItem("https://www.eff.org", "testGuid2"));
|
||||
|
||||
Long time1 = System.currentTimeMillis();
|
||||
|
||||
ContentValues visitItem = new ContentValues();
|
||||
visitItem.put(Visits.DATE_VISITED, time1);
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem = new ContentValues();
|
||||
visitItem.put(Visits.DATE_VISITED, time1 + 100);
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
ContentValues visitItem2 = new ContentValues();
|
||||
visitItem2.put(Visits.DATE_VISITED, time1);
|
||||
visitItem2.put(Visits.HISTORY_GUID, "testGuid2");
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem2));
|
||||
|
||||
Cursor cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(3, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
assertEquals(3, visitsClient.delete(visitsTestUri, null, null));
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(0, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
// test selective deletion - by IS_LOCAL
|
||||
visitItem = new ContentValues();
|
||||
visitItem.put(Visits.DATE_VISITED, time1);
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
visitItem.put(Visits.IS_LOCAL, 0);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem = new ContentValues();
|
||||
visitItem.put(Visits.DATE_VISITED, time1 + 100);
|
||||
visitItem.put(Visits.HISTORY_GUID, "testGuid");
|
||||
visitItem.put(Visits.IS_LOCAL, 1);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem));
|
||||
|
||||
visitItem2 = new ContentValues();
|
||||
visitItem2.put(Visits.DATE_VISITED, time1);
|
||||
visitItem2.put(Visits.HISTORY_GUID, "testGuid2");
|
||||
visitItem2.put(Visits.IS_LOCAL, 0);
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem2));
|
||||
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(3, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
assertEquals(2,
|
||||
visitsClient.delete(visitsTestUri, Visits.IS_LOCAL + " = ?", new String[]{"0"}));
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
assertEquals(time1 + 100, cursor.getLong(cursor.getColumnIndex(Visits.DATE_VISITED)));
|
||||
assertEquals("testGuid", cursor.getString(cursor.getColumnIndex(Visits.HISTORY_GUID)));
|
||||
assertEquals(1, cursor.getInt(cursor.getColumnIndex(Visits.IS_LOCAL)));
|
||||
cursor.close();
|
||||
|
||||
// test selective deletion - by HISTORY_GUID
|
||||
assertNotNull(visitsClient.insert(visitsTestUri, visitItem2));
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(2, cursor.getCount());
|
||||
cursor.close();
|
||||
|
||||
assertEquals(1,
|
||||
visitsClient.delete(visitsTestUri, Visits.HISTORY_GUID + " = ?", new String[]{"testGuid"}));
|
||||
cursor = visitsClient.query(visitsTestUri, null, null, null, null);
|
||||
assertNotNull(cursor);
|
||||
assertEquals(1, cursor.getCount());
|
||||
assertTrue(cursor.moveToFirst());
|
||||
assertEquals("testGuid2", cursor.getString(cursor.getColumnIndex(Visits.HISTORY_GUID)));
|
||||
cursor.close();
|
||||
}
|
||||
}
|
|
@ -1324,7 +1324,10 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.TITLE)), TEST_TITLE,
|
||||
"Inserted history entry has correct specified title");
|
||||
|
||||
// Update the history entry, specifying additional visit count
|
||||
// Update the history entry, specifying additional visit count.
|
||||
// The expectation is that the value is ignored, and count is bumped by 1 only.
|
||||
// At the same time, a visit is inserted into the visits table.
|
||||
// See junit4 tests in BrowserProviderHistoryVisitsTest.
|
||||
values = new ContentValues();
|
||||
values.put(BrowserContract.History.VISITS, 10);
|
||||
|
||||
|
@ -1341,7 +1344,7 @@ public class testBrowserProvider extends ContentProviderTest {
|
|||
"Updated history entry has correct unchanged title");
|
||||
mAsserter.is(c.getString(c.getColumnIndex(BrowserContract.History.URL)), TEST_URL_2,
|
||||
"Updated history entry has correct unchanged URL");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 20L,
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.VISITS)), 11L,
|
||||
"Updated history entry has correct number of visits");
|
||||
mAsserter.is(c.getLong(c.getColumnIndex(BrowserContract.History.DATE_CREATED)), dateCreated,
|
||||
"Updated history entry has same creation date");
|
||||
|
|
Загрузка…
Ссылка в новой задаче