michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: package org.mozilla.gecko.background.db; michael@0: michael@0: import java.util.ArrayList; michael@0: michael@0: import org.json.simple.JSONArray; michael@0: import org.mozilla.gecko.background.sync.helpers.BookmarkHelpers; michael@0: import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate; michael@0: import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate; michael@0: import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate; michael@0: import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate; michael@0: import org.mozilla.gecko.background.sync.helpers.ExpectInvalidTypeStoreDelegate; michael@0: import org.mozilla.gecko.db.BrowserContract; michael@0: import org.mozilla.gecko.sync.Utils; michael@0: import org.mozilla.gecko.sync.repositories.InactiveSessionException; michael@0: import org.mozilla.gecko.sync.repositories.NullCursorException; michael@0: import org.mozilla.gecko.sync.repositories.RepositorySession; michael@0: import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksDataAccessor; michael@0: import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository; michael@0: import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepositorySession; michael@0: import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepository; michael@0: import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor; michael@0: import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers; michael@0: import org.mozilla.gecko.sync.repositories.android.RepoUtils; michael@0: import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate; michael@0: import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord; michael@0: import org.mozilla.gecko.sync.repositories.domain.Record; michael@0: michael@0: import android.content.ContentValues; michael@0: import android.content.Context; michael@0: import android.database.Cursor; michael@0: michael@0: public class TestAndroidBrowserBookmarksRepository extends AndroidBrowserRepositoryTestCase { michael@0: michael@0: @Override michael@0: protected AndroidBrowserRepository getRepository() { michael@0: michael@0: /** michael@0: * Override this chain in order to avoid our test code having to create two michael@0: * sessions all the time. michael@0: */ michael@0: return new AndroidBrowserBookmarksRepository() { michael@0: @Override michael@0: protected void sessionCreator(RepositorySessionCreationDelegate delegate, Context context) { michael@0: AndroidBrowserBookmarksRepositorySession session; michael@0: session = new AndroidBrowserBookmarksRepositorySession(this, context) { michael@0: @Override michael@0: protected synchronized void trackGUID(String guid) { michael@0: System.out.println("Ignoring trackGUID call: this is a test!"); michael@0: } michael@0: }; michael@0: delegate.deferredCreationDelegate().onSessionCreated(session); michael@0: } michael@0: }; michael@0: } michael@0: michael@0: @Override michael@0: protected AndroidBrowserRepositoryDataAccessor getDataAccessor() { michael@0: return new AndroidBrowserBookmarksDataAccessor(getApplicationContext()); michael@0: } michael@0: michael@0: /** michael@0: * Hook to return an ExpectFetchDelegate, possibly with special GUIDs ignored. michael@0: */ michael@0: @Override michael@0: public ExpectFetchDelegate preparedExpectFetchDelegate(Record[] expected) { michael@0: ExpectFetchDelegate delegate = new ExpectFetchDelegate(expected); michael@0: delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); michael@0: return delegate; michael@0: } michael@0: michael@0: /** michael@0: * Hook to return an ExpectGuidsSinceDelegate expecting only special GUIDs (if there are any). michael@0: */ michael@0: public ExpectGuidsSinceDelegate preparedExpectOnlySpecialGuidsSinceDelegate() { michael@0: ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet().toArray(new String[] {})); michael@0: return delegate; michael@0: } michael@0: michael@0: /** michael@0: * Hook to return an ExpectGuidsSinceDelegate, possibly with special GUIDs ignored. michael@0: */ michael@0: @Override michael@0: public ExpectGuidsSinceDelegate preparedExpectGuidsSinceDelegate(String[] expected) { michael@0: ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(expected); michael@0: delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); michael@0: return delegate; michael@0: } michael@0: michael@0: /** michael@0: * Hook to return an ExpectFetchSinceDelegate, possibly with special GUIDs ignored. michael@0: */ michael@0: public ExpectFetchSinceDelegate preparedExpectFetchSinceDelegate(long timestamp, String[] expected) { michael@0: ExpectFetchSinceDelegate delegate = new ExpectFetchSinceDelegate(timestamp, expected); michael@0: delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); michael@0: return delegate; michael@0: } michael@0: michael@0: // NOTE NOTE NOTE michael@0: // Must store folder before records if we we are checking that the michael@0: // records returned are the same as those sent in. If the folder isn't stored michael@0: // first, the returned records won't be identical to those stored because we michael@0: // aren't able to find the parent name/guid when we do a fetch. If you don't want michael@0: // to store a folder first, store your record in "mobile" or one of the folders michael@0: // that always exists. michael@0: michael@0: public void testFetchOneWithChildren() { michael@0: BookmarkRecord folder = BookmarkHelpers.createFolder1(); michael@0: BookmarkRecord bookmark1 = BookmarkHelpers.createBookmark1(); michael@0: BookmarkRecord bookmark2 = BookmarkHelpers.createBookmark2(); michael@0: michael@0: RepositorySession session = createAndBeginSession(); michael@0: michael@0: Record[] records = new Record[] { folder, bookmark1, bookmark2 }; michael@0: performWait(storeManyRunnable(session, records)); michael@0: michael@0: AndroidBrowserRepositoryDataAccessor helper = getDataAccessor(); michael@0: helper.dumpDB(); michael@0: closeDataAccessor(helper); michael@0: michael@0: String[] guids = new String[] { folder.guid }; michael@0: Record[] expected = new Record[] { folder }; michael@0: performWait(fetchRunnable(session, guids, expected)); michael@0: dispose(session); michael@0: } michael@0: michael@0: @Override michael@0: public void testFetchAll() { michael@0: Record[] expected = new Record[3]; michael@0: expected[0] = BookmarkHelpers.createFolder1(); michael@0: expected[1] = BookmarkHelpers.createBookmark1(); michael@0: expected[2] = BookmarkHelpers.createBookmark2(); michael@0: basicFetchAllTest(expected); michael@0: } michael@0: michael@0: @Override michael@0: public void testGuidsSinceReturnMultipleRecords() { michael@0: BookmarkRecord record0 = BookmarkHelpers.createBookmark1(); michael@0: BookmarkRecord record1 = BookmarkHelpers.createBookmark2(); michael@0: guidsSinceReturnMultipleRecords(record0, record1); michael@0: } michael@0: michael@0: @Override michael@0: public void testGuidsSinceReturnNoRecords() { michael@0: guidsSinceReturnNoRecords(BookmarkHelpers.createBookmarkInMobileFolder1()); michael@0: } michael@0: michael@0: @Override michael@0: public void testFetchSinceOneRecord() { michael@0: fetchSinceOneRecord(BookmarkHelpers.createBookmarkInMobileFolder1(), michael@0: BookmarkHelpers.createBookmarkInMobileFolder2()); michael@0: } michael@0: michael@0: @Override michael@0: public void testFetchSinceReturnNoRecords() { michael@0: fetchSinceReturnNoRecords(BookmarkHelpers.createBookmark1()); michael@0: } michael@0: michael@0: @Override michael@0: public void testFetchOneRecordByGuid() { michael@0: fetchOneRecordByGuid(BookmarkHelpers.createBookmarkInMobileFolder1(), michael@0: BookmarkHelpers.createBookmarkInMobileFolder2()); michael@0: } michael@0: michael@0: @Override michael@0: public void testFetchMultipleRecordsByGuids() { michael@0: BookmarkRecord record0 = BookmarkHelpers.createFolder1(); michael@0: BookmarkRecord record1 = BookmarkHelpers.createBookmark1(); michael@0: BookmarkRecord record2 = BookmarkHelpers.createBookmark2(); michael@0: fetchMultipleRecordsByGuids(record0, record1, record2); michael@0: } michael@0: michael@0: @Override michael@0: public void testFetchNoRecordByGuid() { michael@0: fetchNoRecordByGuid(BookmarkHelpers.createBookmark1()); michael@0: } michael@0: michael@0: michael@0: @Override michael@0: public void testWipe() { michael@0: doWipe(BookmarkHelpers.createBookmarkInMobileFolder1(), michael@0: BookmarkHelpers.createBookmarkInMobileFolder2()); michael@0: } michael@0: michael@0: @Override michael@0: public void testStore() { michael@0: basicStoreTest(BookmarkHelpers.createBookmark1()); michael@0: } michael@0: michael@0: michael@0: public void testStoreFolder() { michael@0: basicStoreTest(BookmarkHelpers.createFolder1()); michael@0: } michael@0: michael@0: /** michael@0: * TODO: 2011-12-24, tests disabled because we no longer fail michael@0: * a store call if we get an unknown record type. michael@0: */ michael@0: /* michael@0: * Test storing each different type of Bookmark record. michael@0: * We expect any records with type other than "bookmark" michael@0: * or "folder" to fail. For now we throw these away. michael@0: */ michael@0: /* michael@0: public void testStoreMicrosummary() { michael@0: basicStoreFailTest(BookmarkHelpers.createMicrosummary()); michael@0: } michael@0: michael@0: public void testStoreQuery() { michael@0: basicStoreFailTest(BookmarkHelpers.createQuery()); michael@0: } michael@0: michael@0: public void testStoreLivemark() { michael@0: basicStoreFailTest(BookmarkHelpers.createLivemark()); michael@0: } michael@0: michael@0: public void testStoreSeparator() { michael@0: basicStoreFailTest(BookmarkHelpers.createSeparator()); michael@0: } michael@0: */ michael@0: michael@0: protected void basicStoreFailTest(Record record) { michael@0: final RepositorySession session = createAndBeginSession(); michael@0: performWait(storeRunnable(session, record, new ExpectInvalidTypeStoreDelegate())); michael@0: dispose(session); michael@0: } michael@0: michael@0: /* michael@0: * Re-parenting tests michael@0: */ michael@0: // Insert two records missing parent, then insert their parent. michael@0: // Make sure they end up with the correct parent on fetch. michael@0: public void testBasicReparenting() throws InactiveSessionException { michael@0: Record[] expected = new Record[] { michael@0: BookmarkHelpers.createBookmark1(), michael@0: BookmarkHelpers.createBookmark2(), michael@0: BookmarkHelpers.createFolder1() michael@0: }; michael@0: doMultipleFolderReparentingTest(expected); michael@0: } michael@0: michael@0: // Insert 3 folders and 4 bookmarks in different orders michael@0: // and make sure they come out parented correctly michael@0: public void testMultipleFolderReparenting1() throws InactiveSessionException { michael@0: Record[] expected = new Record[] { michael@0: BookmarkHelpers.createBookmark1(), michael@0: BookmarkHelpers.createBookmark2(), michael@0: BookmarkHelpers.createBookmark3(), michael@0: BookmarkHelpers.createFolder1(), michael@0: BookmarkHelpers.createBookmark4(), michael@0: BookmarkHelpers.createFolder3(), michael@0: BookmarkHelpers.createFolder2(), michael@0: }; michael@0: doMultipleFolderReparentingTest(expected); michael@0: } michael@0: michael@0: public void testMultipleFolderReparenting2() throws InactiveSessionException { michael@0: Record[] expected = new Record[] { michael@0: BookmarkHelpers.createBookmark1(), michael@0: BookmarkHelpers.createBookmark2(), michael@0: BookmarkHelpers.createBookmark3(), michael@0: BookmarkHelpers.createFolder1(), michael@0: BookmarkHelpers.createBookmark4(), michael@0: BookmarkHelpers.createFolder3(), michael@0: BookmarkHelpers.createFolder2(), michael@0: }; michael@0: doMultipleFolderReparentingTest(expected); michael@0: } michael@0: michael@0: public void testMultipleFolderReparenting3() throws InactiveSessionException { michael@0: Record[] expected = new Record[] { michael@0: BookmarkHelpers.createBookmark1(), michael@0: BookmarkHelpers.createBookmark2(), michael@0: BookmarkHelpers.createBookmark3(), michael@0: BookmarkHelpers.createFolder1(), michael@0: BookmarkHelpers.createBookmark4(), michael@0: BookmarkHelpers.createFolder3(), michael@0: BookmarkHelpers.createFolder2(), michael@0: }; michael@0: doMultipleFolderReparentingTest(expected); michael@0: } michael@0: michael@0: private void doMultipleFolderReparentingTest(Record[] expected) throws InactiveSessionException { michael@0: final RepositorySession session = createAndBeginSession(); michael@0: doStore(session, expected); michael@0: ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected); michael@0: performWait(fetchAllRunnable(session, delegate)); michael@0: performWait(finishRunnable(session, new ExpectFinishDelegate())); michael@0: } michael@0: michael@0: /* michael@0: * Test storing identical records with different guids. michael@0: * For bookmarks identical is defined by the following fields michael@0: * being the same: title, uri, type, parentName michael@0: */ michael@0: @Override michael@0: public void testStoreIdenticalExceptGuid() { michael@0: storeIdenticalExceptGuid(BookmarkHelpers.createBookmarkInMobileFolder1()); michael@0: } michael@0: michael@0: /* michael@0: * More complicated situation in which we insert a folder michael@0: * followed by a couple of its children. We then insert michael@0: * the folder again but with a different guid. Children michael@0: * must still get correct parent when they are fetched. michael@0: * Store a record after with the new guid as the parent michael@0: * and make sure it works as well. michael@0: */ michael@0: public void testStoreIdenticalFoldersWithChildren() { michael@0: final RepositorySession session = createAndBeginSession(); michael@0: Record record0 = BookmarkHelpers.createFolder1(); michael@0: michael@0: // Get timestamp so that the conflicting folder that we store below is newer. michael@0: // Children won't come back on this fetch since they haven't been stored, so remove them michael@0: // before our delegate throws a failure. michael@0: BookmarkRecord rec0 = (BookmarkRecord) record0; michael@0: rec0.children = new JSONArray(); michael@0: performWait(storeRunnable(session, record0)); michael@0: michael@0: ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { rec0 }); michael@0: performWait(fetchRunnable(session, new String[] { record0.guid }, timestampDelegate)); michael@0: michael@0: AndroidBrowserRepositoryDataAccessor helper = getDataAccessor(); michael@0: helper.dumpDB(); michael@0: closeDataAccessor(helper); michael@0: michael@0: Record record1 = BookmarkHelpers.createBookmark1(); michael@0: Record record2 = BookmarkHelpers.createBookmark2(); michael@0: Record record3 = BookmarkHelpers.createFolder1(); michael@0: BookmarkRecord bmk3 = (BookmarkRecord) record3; michael@0: record3.guid = Utils.generateGuid(); michael@0: record3.lastModified = timestampDelegate.records.get(0).lastModified + 3000; michael@0: assert(!record0.guid.equals(record3.guid)); michael@0: michael@0: // Store an additional record after inserting the duplicate folder michael@0: // with new GUID. Make sure it comes back as well. michael@0: Record record4 = BookmarkHelpers.createBookmark3(); michael@0: BookmarkRecord bmk4 = (BookmarkRecord) record4; michael@0: bmk4.parentID = bmk3.guid; michael@0: bmk4.parentName = bmk3.parentName; michael@0: michael@0: doStore(session, new Record[] { michael@0: record1, record2, record3, bmk4 michael@0: }); michael@0: BookmarkRecord bmk1 = (BookmarkRecord) record1; michael@0: bmk1.parentID = record3.guid; michael@0: BookmarkRecord bmk2 = (BookmarkRecord) record2; michael@0: bmk2.parentID = record3.guid; michael@0: Record[] expect = new Record[] { michael@0: bmk1, bmk2, record3 michael@0: }; michael@0: fetchAllRunnable(session, preparedExpectFetchDelegate(expect)); michael@0: dispose(session); michael@0: } michael@0: michael@0: @Override michael@0: public void testRemoteNewerTimeStamp() { michael@0: BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); michael@0: BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); michael@0: remoteNewerTimeStamp(local, remote); michael@0: } michael@0: michael@0: @Override michael@0: public void testLocalNewerTimeStamp() { michael@0: BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); michael@0: BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); michael@0: localNewerTimeStamp(local, remote); michael@0: } michael@0: michael@0: @Override michael@0: public void testDeleteRemoteNewer() { michael@0: BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); michael@0: BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); michael@0: deleteRemoteNewer(local, remote); michael@0: } michael@0: michael@0: @Override michael@0: public void testDeleteLocalNewer() { michael@0: BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); michael@0: BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); michael@0: deleteLocalNewer(local, remote); michael@0: } michael@0: michael@0: @Override michael@0: public void testDeleteRemoteLocalNonexistent() { michael@0: BookmarkRecord remote = BookmarkHelpers.createBookmark2(); michael@0: deleteRemoteLocalNonexistent(remote); michael@0: } michael@0: michael@0: @Override michael@0: public void testCleanMultipleRecords() { michael@0: cleanMultipleRecords( michael@0: BookmarkHelpers.createBookmarkInMobileFolder1(), michael@0: BookmarkHelpers.createBookmarkInMobileFolder2(), michael@0: BookmarkHelpers.createBookmark1(), michael@0: BookmarkHelpers.createBookmark2(), michael@0: BookmarkHelpers.createFolder1()); michael@0: } michael@0: michael@0: public void testBasicPositioning() { michael@0: final RepositorySession session = createAndBeginSession(); michael@0: Record[] expected = new Record[] { michael@0: BookmarkHelpers.createBookmark1(), michael@0: BookmarkHelpers.createFolder1(), michael@0: BookmarkHelpers.createBookmark2() michael@0: }; michael@0: System.out.println("TEST: Inserting " + expected[0].guid + ", " michael@0: + expected[1].guid + ", " michael@0: + expected[2].guid); michael@0: doStore(session, expected); michael@0: michael@0: ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected); michael@0: performWait(fetchAllRunnable(session, delegate)); michael@0: michael@0: int found = 0; michael@0: boolean foundFolder = false; michael@0: for (int i = 0; i < delegate.records.size(); i++) { michael@0: BookmarkRecord rec = (BookmarkRecord) delegate.records.get(i); michael@0: if (rec.guid.equals(expected[0].guid)) { michael@0: assertEquals(0, ((BookmarkRecord) delegate.records.get(i)).androidPosition); michael@0: found++; michael@0: } else if (rec.guid.equals(expected[2].guid)) { michael@0: assertEquals(1, ((BookmarkRecord) delegate.records.get(i)).androidPosition); michael@0: found++; michael@0: } else if (rec.guid.equals(expected[1].guid)) { michael@0: foundFolder = true; michael@0: } else { michael@0: System.out.println("TEST: found " + rec.guid); michael@0: } michael@0: } michael@0: assertTrue(foundFolder); michael@0: assertEquals(2, found); michael@0: dispose(session); michael@0: } michael@0: michael@0: public void testSqlInjectPurgeDeleteAndUpdateByGuid() { michael@0: // Some setup. michael@0: RepositorySession session = createAndBeginSession(); michael@0: AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); michael@0: michael@0: ContentValues cv = new ContentValues(); michael@0: cv.put(BrowserContract.SyncColumns.IS_DELETED, 1); michael@0: michael@0: // Create and insert 2 bookmarks, 2nd one is evil (attempts injection). michael@0: BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); michael@0: BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); michael@0: bmk2.guid = "' or '1'='1"; michael@0: michael@0: db.insert(bmk1); michael@0: db.insert(bmk2); michael@0: michael@0: // Test 1 - updateByGuid() handles evil bookmarks correctly. michael@0: db.updateByGuid(bmk2.guid, cv); michael@0: michael@0: // Query bookmarks table. michael@0: Cursor cur = getAllBookmarks(); michael@0: int numBookmarks = cur.getCount(); michael@0: michael@0: // Ensure only the evil bookmark is marked for deletion. michael@0: try { michael@0: cur.moveToFirst(); michael@0: while (!cur.isAfterLast()) { michael@0: String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); michael@0: boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; michael@0: michael@0: if (guid.equals(bmk2.guid)) { michael@0: assertTrue(deleted); michael@0: } else { michael@0: assertFalse(deleted); michael@0: } michael@0: cur.moveToNext(); michael@0: } michael@0: } finally { michael@0: cur.close(); michael@0: } michael@0: michael@0: // Test 2 - Ensure purgeDelete()'s call to delete() deletes only 1 record. michael@0: try { michael@0: db.purgeDeleted(); michael@0: } catch (NullCursorException e) { michael@0: e.printStackTrace(); michael@0: } michael@0: michael@0: cur = getAllBookmarks(); michael@0: int numBookmarksAfterDeletion = cur.getCount(); michael@0: michael@0: // Ensure we have only 1 deleted row. michael@0: assertEquals(numBookmarksAfterDeletion, numBookmarks - 1); michael@0: michael@0: // Ensure only the evil bookmark is deleted. michael@0: try { michael@0: cur.moveToFirst(); michael@0: while (!cur.isAfterLast()) { michael@0: String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); michael@0: boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; michael@0: michael@0: if (guid.equals(bmk2.guid)) { michael@0: fail("Evil guid was not deleted!"); michael@0: } else { michael@0: assertFalse(deleted); michael@0: } michael@0: cur.moveToNext(); michael@0: } michael@0: } finally { michael@0: cur.close(); michael@0: } michael@0: dispose(session); michael@0: } michael@0: michael@0: protected Cursor getAllBookmarks() { michael@0: Context context = getApplicationContext(); michael@0: Cursor cur = context.getContentResolver().query(BrowserContractHelpers.BOOKMARKS_CONTENT_URI, michael@0: BrowserContractHelpers.BookmarkColumns, null, null, null); michael@0: return cur; michael@0: } michael@0: michael@0: public void testSqlInjectFetch() { michael@0: // Some setup. michael@0: RepositorySession session = createAndBeginSession(); michael@0: AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); michael@0: michael@0: // Create and insert 4 bookmarks, last one is evil (attempts injection). michael@0: BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); michael@0: BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); michael@0: BookmarkRecord bmk3 = BookmarkHelpers.createBookmark3(); michael@0: BookmarkRecord bmk4 = BookmarkHelpers.createBookmark4(); michael@0: bmk4.guid = "' or '1'='1"; michael@0: michael@0: db.insert(bmk1); michael@0: db.insert(bmk2); michael@0: db.insert(bmk3); michael@0: db.insert(bmk4); michael@0: michael@0: // Perform a fetch. michael@0: Cursor cur = null; michael@0: try { michael@0: cur = db.fetch(new String[] { bmk3.guid, bmk4.guid }); michael@0: } catch (NullCursorException e1) { michael@0: e1.printStackTrace(); michael@0: } michael@0: michael@0: // Ensure the correct number (2) of records were fetched and with the correct guids. michael@0: if (cur == null) { michael@0: fail("No records were fetched."); michael@0: } michael@0: michael@0: try { michael@0: if (cur.getCount() != 2) { michael@0: fail("Wrong number of guids fetched!"); michael@0: } michael@0: cur.moveToFirst(); michael@0: while (!cur.isAfterLast()) { michael@0: String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); michael@0: if (!guid.equals(bmk3.guid) && !guid.equals(bmk4.guid)) { michael@0: fail("Wrong guids were fetched!"); michael@0: } michael@0: cur.moveToNext(); michael@0: } michael@0: } finally { michael@0: cur.close(); michael@0: } michael@0: dispose(session); michael@0: } michael@0: michael@0: public void testSqlInjectDelete() { michael@0: // Some setup. michael@0: RepositorySession session = createAndBeginSession(); michael@0: AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); michael@0: michael@0: // Create and insert 2 bookmarks, 2nd one is evil (attempts injection). michael@0: BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); michael@0: BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); michael@0: bmk2.guid = "' or '1'='1"; michael@0: michael@0: db.insert(bmk1); michael@0: db.insert(bmk2); michael@0: michael@0: // Note size of table before delete. michael@0: Cursor cur = getAllBookmarks(); michael@0: int numBookmarks = cur.getCount(); michael@0: michael@0: db.purgeGuid(bmk2.guid); michael@0: michael@0: // Note size of table after delete. michael@0: cur = getAllBookmarks(); michael@0: int numBookmarksAfterDelete = cur.getCount(); michael@0: michael@0: // Ensure size of table after delete is *only* 1 less. michael@0: assertEquals(numBookmarksAfterDelete, numBookmarks - 1); michael@0: michael@0: try { michael@0: cur.moveToFirst(); michael@0: while (!cur.isAfterLast()) { michael@0: String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); michael@0: if (guid.equals(bmk2.guid)) { michael@0: fail("Guid was not deleted!"); michael@0: } michael@0: cur.moveToNext(); michael@0: } michael@0: } finally { michael@0: cur.close(); michael@0: } michael@0: dispose(session); michael@0: } michael@0: michael@0: /** michael@0: * Verify that data accessor's bulkInsert actually inserts. michael@0: * @throws NullCursorException michael@0: */ michael@0: public void testBulkInsert() throws NullCursorException { michael@0: RepositorySession session = createAndBeginSession(); michael@0: AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); michael@0: michael@0: // Have to set androidID of parent manually. michael@0: Cursor cur = db.fetch(new String[] { "mobile" } ); michael@0: assertEquals(1, cur.getCount()); michael@0: cur.moveToFirst(); michael@0: int mobileAndroidID = RepoUtils.getIntFromCursor(cur, BrowserContract.Bookmarks._ID); michael@0: michael@0: BookmarkRecord bookmark1 = BookmarkHelpers.createBookmarkInMobileFolder1(); michael@0: BookmarkRecord bookmark2 = BookmarkHelpers.createBookmarkInMobileFolder2(); michael@0: bookmark1.androidParentID = mobileAndroidID; michael@0: bookmark2.androidParentID = mobileAndroidID; michael@0: ArrayList recordList = new ArrayList(); michael@0: recordList.add(bookmark1); michael@0: recordList.add(bookmark2); michael@0: db.bulkInsert(recordList); michael@0: michael@0: String[] guids = new String[] { bookmark1.guid, bookmark2.guid }; michael@0: Record[] expected = new Record[] { bookmark1, bookmark2 }; michael@0: performWait(fetchRunnable(session, guids, expected)); michael@0: dispose(session); michael@0: } michael@0: }