1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/tests/background/junit3/src/db/TestAndroidBrowserBookmarksRepository.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,636 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +package org.mozilla.gecko.background.db; 1.8 + 1.9 +import java.util.ArrayList; 1.10 + 1.11 +import org.json.simple.JSONArray; 1.12 +import org.mozilla.gecko.background.sync.helpers.BookmarkHelpers; 1.13 +import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate; 1.14 +import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate; 1.15 +import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate; 1.16 +import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate; 1.17 +import org.mozilla.gecko.background.sync.helpers.ExpectInvalidTypeStoreDelegate; 1.18 +import org.mozilla.gecko.db.BrowserContract; 1.19 +import org.mozilla.gecko.sync.Utils; 1.20 +import org.mozilla.gecko.sync.repositories.InactiveSessionException; 1.21 +import org.mozilla.gecko.sync.repositories.NullCursorException; 1.22 +import org.mozilla.gecko.sync.repositories.RepositorySession; 1.23 +import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksDataAccessor; 1.24 +import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository; 1.25 +import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepositorySession; 1.26 +import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepository; 1.27 +import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor; 1.28 +import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers; 1.29 +import org.mozilla.gecko.sync.repositories.android.RepoUtils; 1.30 +import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate; 1.31 +import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord; 1.32 +import org.mozilla.gecko.sync.repositories.domain.Record; 1.33 + 1.34 +import android.content.ContentValues; 1.35 +import android.content.Context; 1.36 +import android.database.Cursor; 1.37 + 1.38 +public class TestAndroidBrowserBookmarksRepository extends AndroidBrowserRepositoryTestCase { 1.39 + 1.40 + @Override 1.41 + protected AndroidBrowserRepository getRepository() { 1.42 + 1.43 + /** 1.44 + * Override this chain in order to avoid our test code having to create two 1.45 + * sessions all the time. 1.46 + */ 1.47 + return new AndroidBrowserBookmarksRepository() { 1.48 + @Override 1.49 + protected void sessionCreator(RepositorySessionCreationDelegate delegate, Context context) { 1.50 + AndroidBrowserBookmarksRepositorySession session; 1.51 + session = new AndroidBrowserBookmarksRepositorySession(this, context) { 1.52 + @Override 1.53 + protected synchronized void trackGUID(String guid) { 1.54 + System.out.println("Ignoring trackGUID call: this is a test!"); 1.55 + } 1.56 + }; 1.57 + delegate.deferredCreationDelegate().onSessionCreated(session); 1.58 + } 1.59 + }; 1.60 + } 1.61 + 1.62 + @Override 1.63 + protected AndroidBrowserRepositoryDataAccessor getDataAccessor() { 1.64 + return new AndroidBrowserBookmarksDataAccessor(getApplicationContext()); 1.65 + } 1.66 + 1.67 + /** 1.68 + * Hook to return an ExpectFetchDelegate, possibly with special GUIDs ignored. 1.69 + */ 1.70 + @Override 1.71 + public ExpectFetchDelegate preparedExpectFetchDelegate(Record[] expected) { 1.72 + ExpectFetchDelegate delegate = new ExpectFetchDelegate(expected); 1.73 + delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); 1.74 + return delegate; 1.75 + } 1.76 + 1.77 + /** 1.78 + * Hook to return an ExpectGuidsSinceDelegate expecting only special GUIDs (if there are any). 1.79 + */ 1.80 + public ExpectGuidsSinceDelegate preparedExpectOnlySpecialGuidsSinceDelegate() { 1.81 + ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet().toArray(new String[] {})); 1.82 + return delegate; 1.83 + } 1.84 + 1.85 + /** 1.86 + * Hook to return an ExpectGuidsSinceDelegate, possibly with special GUIDs ignored. 1.87 + */ 1.88 + @Override 1.89 + public ExpectGuidsSinceDelegate preparedExpectGuidsSinceDelegate(String[] expected) { 1.90 + ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(expected); 1.91 + delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); 1.92 + return delegate; 1.93 + } 1.94 + 1.95 + /** 1.96 + * Hook to return an ExpectFetchSinceDelegate, possibly with special GUIDs ignored. 1.97 + */ 1.98 + public ExpectFetchSinceDelegate preparedExpectFetchSinceDelegate(long timestamp, String[] expected) { 1.99 + ExpectFetchSinceDelegate delegate = new ExpectFetchSinceDelegate(timestamp, expected); 1.100 + delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); 1.101 + return delegate; 1.102 + } 1.103 + 1.104 + // NOTE NOTE NOTE 1.105 + // Must store folder before records if we we are checking that the 1.106 + // records returned are the same as those sent in. If the folder isn't stored 1.107 + // first, the returned records won't be identical to those stored because we 1.108 + // aren't able to find the parent name/guid when we do a fetch. If you don't want 1.109 + // to store a folder first, store your record in "mobile" or one of the folders 1.110 + // that always exists. 1.111 + 1.112 + public void testFetchOneWithChildren() { 1.113 + BookmarkRecord folder = BookmarkHelpers.createFolder1(); 1.114 + BookmarkRecord bookmark1 = BookmarkHelpers.createBookmark1(); 1.115 + BookmarkRecord bookmark2 = BookmarkHelpers.createBookmark2(); 1.116 + 1.117 + RepositorySession session = createAndBeginSession(); 1.118 + 1.119 + Record[] records = new Record[] { folder, bookmark1, bookmark2 }; 1.120 + performWait(storeManyRunnable(session, records)); 1.121 + 1.122 + AndroidBrowserRepositoryDataAccessor helper = getDataAccessor(); 1.123 + helper.dumpDB(); 1.124 + closeDataAccessor(helper); 1.125 + 1.126 + String[] guids = new String[] { folder.guid }; 1.127 + Record[] expected = new Record[] { folder }; 1.128 + performWait(fetchRunnable(session, guids, expected)); 1.129 + dispose(session); 1.130 + } 1.131 + 1.132 + @Override 1.133 + public void testFetchAll() { 1.134 + Record[] expected = new Record[3]; 1.135 + expected[0] = BookmarkHelpers.createFolder1(); 1.136 + expected[1] = BookmarkHelpers.createBookmark1(); 1.137 + expected[2] = BookmarkHelpers.createBookmark2(); 1.138 + basicFetchAllTest(expected); 1.139 + } 1.140 + 1.141 + @Override 1.142 + public void testGuidsSinceReturnMultipleRecords() { 1.143 + BookmarkRecord record0 = BookmarkHelpers.createBookmark1(); 1.144 + BookmarkRecord record1 = BookmarkHelpers.createBookmark2(); 1.145 + guidsSinceReturnMultipleRecords(record0, record1); 1.146 + } 1.147 + 1.148 + @Override 1.149 + public void testGuidsSinceReturnNoRecords() { 1.150 + guidsSinceReturnNoRecords(BookmarkHelpers.createBookmarkInMobileFolder1()); 1.151 + } 1.152 + 1.153 + @Override 1.154 + public void testFetchSinceOneRecord() { 1.155 + fetchSinceOneRecord(BookmarkHelpers.createBookmarkInMobileFolder1(), 1.156 + BookmarkHelpers.createBookmarkInMobileFolder2()); 1.157 + } 1.158 + 1.159 + @Override 1.160 + public void testFetchSinceReturnNoRecords() { 1.161 + fetchSinceReturnNoRecords(BookmarkHelpers.createBookmark1()); 1.162 + } 1.163 + 1.164 + @Override 1.165 + public void testFetchOneRecordByGuid() { 1.166 + fetchOneRecordByGuid(BookmarkHelpers.createBookmarkInMobileFolder1(), 1.167 + BookmarkHelpers.createBookmarkInMobileFolder2()); 1.168 + } 1.169 + 1.170 + @Override 1.171 + public void testFetchMultipleRecordsByGuids() { 1.172 + BookmarkRecord record0 = BookmarkHelpers.createFolder1(); 1.173 + BookmarkRecord record1 = BookmarkHelpers.createBookmark1(); 1.174 + BookmarkRecord record2 = BookmarkHelpers.createBookmark2(); 1.175 + fetchMultipleRecordsByGuids(record0, record1, record2); 1.176 + } 1.177 + 1.178 + @Override 1.179 + public void testFetchNoRecordByGuid() { 1.180 + fetchNoRecordByGuid(BookmarkHelpers.createBookmark1()); 1.181 + } 1.182 + 1.183 + 1.184 + @Override 1.185 + public void testWipe() { 1.186 + doWipe(BookmarkHelpers.createBookmarkInMobileFolder1(), 1.187 + BookmarkHelpers.createBookmarkInMobileFolder2()); 1.188 + } 1.189 + 1.190 + @Override 1.191 + public void testStore() { 1.192 + basicStoreTest(BookmarkHelpers.createBookmark1()); 1.193 + } 1.194 + 1.195 + 1.196 + public void testStoreFolder() { 1.197 + basicStoreTest(BookmarkHelpers.createFolder1()); 1.198 + } 1.199 + 1.200 + /** 1.201 + * TODO: 2011-12-24, tests disabled because we no longer fail 1.202 + * a store call if we get an unknown record type. 1.203 + */ 1.204 + /* 1.205 + * Test storing each different type of Bookmark record. 1.206 + * We expect any records with type other than "bookmark" 1.207 + * or "folder" to fail. For now we throw these away. 1.208 + */ 1.209 + /* 1.210 + public void testStoreMicrosummary() { 1.211 + basicStoreFailTest(BookmarkHelpers.createMicrosummary()); 1.212 + } 1.213 + 1.214 + public void testStoreQuery() { 1.215 + basicStoreFailTest(BookmarkHelpers.createQuery()); 1.216 + } 1.217 + 1.218 + public void testStoreLivemark() { 1.219 + basicStoreFailTest(BookmarkHelpers.createLivemark()); 1.220 + } 1.221 + 1.222 + public void testStoreSeparator() { 1.223 + basicStoreFailTest(BookmarkHelpers.createSeparator()); 1.224 + } 1.225 + */ 1.226 + 1.227 + protected void basicStoreFailTest(Record record) { 1.228 + final RepositorySession session = createAndBeginSession(); 1.229 + performWait(storeRunnable(session, record, new ExpectInvalidTypeStoreDelegate())); 1.230 + dispose(session); 1.231 + } 1.232 + 1.233 + /* 1.234 + * Re-parenting tests 1.235 + */ 1.236 + // Insert two records missing parent, then insert their parent. 1.237 + // Make sure they end up with the correct parent on fetch. 1.238 + public void testBasicReparenting() throws InactiveSessionException { 1.239 + Record[] expected = new Record[] { 1.240 + BookmarkHelpers.createBookmark1(), 1.241 + BookmarkHelpers.createBookmark2(), 1.242 + BookmarkHelpers.createFolder1() 1.243 + }; 1.244 + doMultipleFolderReparentingTest(expected); 1.245 + } 1.246 + 1.247 + // Insert 3 folders and 4 bookmarks in different orders 1.248 + // and make sure they come out parented correctly 1.249 + public void testMultipleFolderReparenting1() throws InactiveSessionException { 1.250 + Record[] expected = new Record[] { 1.251 + BookmarkHelpers.createBookmark1(), 1.252 + BookmarkHelpers.createBookmark2(), 1.253 + BookmarkHelpers.createBookmark3(), 1.254 + BookmarkHelpers.createFolder1(), 1.255 + BookmarkHelpers.createBookmark4(), 1.256 + BookmarkHelpers.createFolder3(), 1.257 + BookmarkHelpers.createFolder2(), 1.258 + }; 1.259 + doMultipleFolderReparentingTest(expected); 1.260 + } 1.261 + 1.262 + public void testMultipleFolderReparenting2() throws InactiveSessionException { 1.263 + Record[] expected = new Record[] { 1.264 + BookmarkHelpers.createBookmark1(), 1.265 + BookmarkHelpers.createBookmark2(), 1.266 + BookmarkHelpers.createBookmark3(), 1.267 + BookmarkHelpers.createFolder1(), 1.268 + BookmarkHelpers.createBookmark4(), 1.269 + BookmarkHelpers.createFolder3(), 1.270 + BookmarkHelpers.createFolder2(), 1.271 + }; 1.272 + doMultipleFolderReparentingTest(expected); 1.273 + } 1.274 + 1.275 + public void testMultipleFolderReparenting3() throws InactiveSessionException { 1.276 + Record[] expected = new Record[] { 1.277 + BookmarkHelpers.createBookmark1(), 1.278 + BookmarkHelpers.createBookmark2(), 1.279 + BookmarkHelpers.createBookmark3(), 1.280 + BookmarkHelpers.createFolder1(), 1.281 + BookmarkHelpers.createBookmark4(), 1.282 + BookmarkHelpers.createFolder3(), 1.283 + BookmarkHelpers.createFolder2(), 1.284 + }; 1.285 + doMultipleFolderReparentingTest(expected); 1.286 + } 1.287 + 1.288 + private void doMultipleFolderReparentingTest(Record[] expected) throws InactiveSessionException { 1.289 + final RepositorySession session = createAndBeginSession(); 1.290 + doStore(session, expected); 1.291 + ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected); 1.292 + performWait(fetchAllRunnable(session, delegate)); 1.293 + performWait(finishRunnable(session, new ExpectFinishDelegate())); 1.294 + } 1.295 + 1.296 + /* 1.297 + * Test storing identical records with different guids. 1.298 + * For bookmarks identical is defined by the following fields 1.299 + * being the same: title, uri, type, parentName 1.300 + */ 1.301 + @Override 1.302 + public void testStoreIdenticalExceptGuid() { 1.303 + storeIdenticalExceptGuid(BookmarkHelpers.createBookmarkInMobileFolder1()); 1.304 + } 1.305 + 1.306 + /* 1.307 + * More complicated situation in which we insert a folder 1.308 + * followed by a couple of its children. We then insert 1.309 + * the folder again but with a different guid. Children 1.310 + * must still get correct parent when they are fetched. 1.311 + * Store a record after with the new guid as the parent 1.312 + * and make sure it works as well. 1.313 + */ 1.314 + public void testStoreIdenticalFoldersWithChildren() { 1.315 + final RepositorySession session = createAndBeginSession(); 1.316 + Record record0 = BookmarkHelpers.createFolder1(); 1.317 + 1.318 + // Get timestamp so that the conflicting folder that we store below is newer. 1.319 + // Children won't come back on this fetch since they haven't been stored, so remove them 1.320 + // before our delegate throws a failure. 1.321 + BookmarkRecord rec0 = (BookmarkRecord) record0; 1.322 + rec0.children = new JSONArray(); 1.323 + performWait(storeRunnable(session, record0)); 1.324 + 1.325 + ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { rec0 }); 1.326 + performWait(fetchRunnable(session, new String[] { record0.guid }, timestampDelegate)); 1.327 + 1.328 + AndroidBrowserRepositoryDataAccessor helper = getDataAccessor(); 1.329 + helper.dumpDB(); 1.330 + closeDataAccessor(helper); 1.331 + 1.332 + Record record1 = BookmarkHelpers.createBookmark1(); 1.333 + Record record2 = BookmarkHelpers.createBookmark2(); 1.334 + Record record3 = BookmarkHelpers.createFolder1(); 1.335 + BookmarkRecord bmk3 = (BookmarkRecord) record3; 1.336 + record3.guid = Utils.generateGuid(); 1.337 + record3.lastModified = timestampDelegate.records.get(0).lastModified + 3000; 1.338 + assert(!record0.guid.equals(record3.guid)); 1.339 + 1.340 + // Store an additional record after inserting the duplicate folder 1.341 + // with new GUID. Make sure it comes back as well. 1.342 + Record record4 = BookmarkHelpers.createBookmark3(); 1.343 + BookmarkRecord bmk4 = (BookmarkRecord) record4; 1.344 + bmk4.parentID = bmk3.guid; 1.345 + bmk4.parentName = bmk3.parentName; 1.346 + 1.347 + doStore(session, new Record[] { 1.348 + record1, record2, record3, bmk4 1.349 + }); 1.350 + BookmarkRecord bmk1 = (BookmarkRecord) record1; 1.351 + bmk1.parentID = record3.guid; 1.352 + BookmarkRecord bmk2 = (BookmarkRecord) record2; 1.353 + bmk2.parentID = record3.guid; 1.354 + Record[] expect = new Record[] { 1.355 + bmk1, bmk2, record3 1.356 + }; 1.357 + fetchAllRunnable(session, preparedExpectFetchDelegate(expect)); 1.358 + dispose(session); 1.359 + } 1.360 + 1.361 + @Override 1.362 + public void testRemoteNewerTimeStamp() { 1.363 + BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); 1.364 + BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); 1.365 + remoteNewerTimeStamp(local, remote); 1.366 + } 1.367 + 1.368 + @Override 1.369 + public void testLocalNewerTimeStamp() { 1.370 + BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); 1.371 + BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); 1.372 + localNewerTimeStamp(local, remote); 1.373 + } 1.374 + 1.375 + @Override 1.376 + public void testDeleteRemoteNewer() { 1.377 + BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); 1.378 + BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); 1.379 + deleteRemoteNewer(local, remote); 1.380 + } 1.381 + 1.382 + @Override 1.383 + public void testDeleteLocalNewer() { 1.384 + BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); 1.385 + BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); 1.386 + deleteLocalNewer(local, remote); 1.387 + } 1.388 + 1.389 + @Override 1.390 + public void testDeleteRemoteLocalNonexistent() { 1.391 + BookmarkRecord remote = BookmarkHelpers.createBookmark2(); 1.392 + deleteRemoteLocalNonexistent(remote); 1.393 + } 1.394 + 1.395 + @Override 1.396 + public void testCleanMultipleRecords() { 1.397 + cleanMultipleRecords( 1.398 + BookmarkHelpers.createBookmarkInMobileFolder1(), 1.399 + BookmarkHelpers.createBookmarkInMobileFolder2(), 1.400 + BookmarkHelpers.createBookmark1(), 1.401 + BookmarkHelpers.createBookmark2(), 1.402 + BookmarkHelpers.createFolder1()); 1.403 + } 1.404 + 1.405 + public void testBasicPositioning() { 1.406 + final RepositorySession session = createAndBeginSession(); 1.407 + Record[] expected = new Record[] { 1.408 + BookmarkHelpers.createBookmark1(), 1.409 + BookmarkHelpers.createFolder1(), 1.410 + BookmarkHelpers.createBookmark2() 1.411 + }; 1.412 + System.out.println("TEST: Inserting " + expected[0].guid + ", " 1.413 + + expected[1].guid + ", " 1.414 + + expected[2].guid); 1.415 + doStore(session, expected); 1.416 + 1.417 + ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected); 1.418 + performWait(fetchAllRunnable(session, delegate)); 1.419 + 1.420 + int found = 0; 1.421 + boolean foundFolder = false; 1.422 + for (int i = 0; i < delegate.records.size(); i++) { 1.423 + BookmarkRecord rec = (BookmarkRecord) delegate.records.get(i); 1.424 + if (rec.guid.equals(expected[0].guid)) { 1.425 + assertEquals(0, ((BookmarkRecord) delegate.records.get(i)).androidPosition); 1.426 + found++; 1.427 + } else if (rec.guid.equals(expected[2].guid)) { 1.428 + assertEquals(1, ((BookmarkRecord) delegate.records.get(i)).androidPosition); 1.429 + found++; 1.430 + } else if (rec.guid.equals(expected[1].guid)) { 1.431 + foundFolder = true; 1.432 + } else { 1.433 + System.out.println("TEST: found " + rec.guid); 1.434 + } 1.435 + } 1.436 + assertTrue(foundFolder); 1.437 + assertEquals(2, found); 1.438 + dispose(session); 1.439 + } 1.440 + 1.441 + public void testSqlInjectPurgeDeleteAndUpdateByGuid() { 1.442 + // Some setup. 1.443 + RepositorySession session = createAndBeginSession(); 1.444 + AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); 1.445 + 1.446 + ContentValues cv = new ContentValues(); 1.447 + cv.put(BrowserContract.SyncColumns.IS_DELETED, 1); 1.448 + 1.449 + // Create and insert 2 bookmarks, 2nd one is evil (attempts injection). 1.450 + BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); 1.451 + BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); 1.452 + bmk2.guid = "' or '1'='1"; 1.453 + 1.454 + db.insert(bmk1); 1.455 + db.insert(bmk2); 1.456 + 1.457 + // Test 1 - updateByGuid() handles evil bookmarks correctly. 1.458 + db.updateByGuid(bmk2.guid, cv); 1.459 + 1.460 + // Query bookmarks table. 1.461 + Cursor cur = getAllBookmarks(); 1.462 + int numBookmarks = cur.getCount(); 1.463 + 1.464 + // Ensure only the evil bookmark is marked for deletion. 1.465 + try { 1.466 + cur.moveToFirst(); 1.467 + while (!cur.isAfterLast()) { 1.468 + String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); 1.469 + boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; 1.470 + 1.471 + if (guid.equals(bmk2.guid)) { 1.472 + assertTrue(deleted); 1.473 + } else { 1.474 + assertFalse(deleted); 1.475 + } 1.476 + cur.moveToNext(); 1.477 + } 1.478 + } finally { 1.479 + cur.close(); 1.480 + } 1.481 + 1.482 + // Test 2 - Ensure purgeDelete()'s call to delete() deletes only 1 record. 1.483 + try { 1.484 + db.purgeDeleted(); 1.485 + } catch (NullCursorException e) { 1.486 + e.printStackTrace(); 1.487 + } 1.488 + 1.489 + cur = getAllBookmarks(); 1.490 + int numBookmarksAfterDeletion = cur.getCount(); 1.491 + 1.492 + // Ensure we have only 1 deleted row. 1.493 + assertEquals(numBookmarksAfterDeletion, numBookmarks - 1); 1.494 + 1.495 + // Ensure only the evil bookmark is deleted. 1.496 + try { 1.497 + cur.moveToFirst(); 1.498 + while (!cur.isAfterLast()) { 1.499 + String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); 1.500 + boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; 1.501 + 1.502 + if (guid.equals(bmk2.guid)) { 1.503 + fail("Evil guid was not deleted!"); 1.504 + } else { 1.505 + assertFalse(deleted); 1.506 + } 1.507 + cur.moveToNext(); 1.508 + } 1.509 + } finally { 1.510 + cur.close(); 1.511 + } 1.512 + dispose(session); 1.513 + } 1.514 + 1.515 + protected Cursor getAllBookmarks() { 1.516 + Context context = getApplicationContext(); 1.517 + Cursor cur = context.getContentResolver().query(BrowserContractHelpers.BOOKMARKS_CONTENT_URI, 1.518 + BrowserContractHelpers.BookmarkColumns, null, null, null); 1.519 + return cur; 1.520 + } 1.521 + 1.522 + public void testSqlInjectFetch() { 1.523 + // Some setup. 1.524 + RepositorySession session = createAndBeginSession(); 1.525 + AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); 1.526 + 1.527 + // Create and insert 4 bookmarks, last one is evil (attempts injection). 1.528 + BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); 1.529 + BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); 1.530 + BookmarkRecord bmk3 = BookmarkHelpers.createBookmark3(); 1.531 + BookmarkRecord bmk4 = BookmarkHelpers.createBookmark4(); 1.532 + bmk4.guid = "' or '1'='1"; 1.533 + 1.534 + db.insert(bmk1); 1.535 + db.insert(bmk2); 1.536 + db.insert(bmk3); 1.537 + db.insert(bmk4); 1.538 + 1.539 + // Perform a fetch. 1.540 + Cursor cur = null; 1.541 + try { 1.542 + cur = db.fetch(new String[] { bmk3.guid, bmk4.guid }); 1.543 + } catch (NullCursorException e1) { 1.544 + e1.printStackTrace(); 1.545 + } 1.546 + 1.547 + // Ensure the correct number (2) of records were fetched and with the correct guids. 1.548 + if (cur == null) { 1.549 + fail("No records were fetched."); 1.550 + } 1.551 + 1.552 + try { 1.553 + if (cur.getCount() != 2) { 1.554 + fail("Wrong number of guids fetched!"); 1.555 + } 1.556 + cur.moveToFirst(); 1.557 + while (!cur.isAfterLast()) { 1.558 + String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); 1.559 + if (!guid.equals(bmk3.guid) && !guid.equals(bmk4.guid)) { 1.560 + fail("Wrong guids were fetched!"); 1.561 + } 1.562 + cur.moveToNext(); 1.563 + } 1.564 + } finally { 1.565 + cur.close(); 1.566 + } 1.567 + dispose(session); 1.568 + } 1.569 + 1.570 + public void testSqlInjectDelete() { 1.571 + // Some setup. 1.572 + RepositorySession session = createAndBeginSession(); 1.573 + AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); 1.574 + 1.575 + // Create and insert 2 bookmarks, 2nd one is evil (attempts injection). 1.576 + BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); 1.577 + BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); 1.578 + bmk2.guid = "' or '1'='1"; 1.579 + 1.580 + db.insert(bmk1); 1.581 + db.insert(bmk2); 1.582 + 1.583 + // Note size of table before delete. 1.584 + Cursor cur = getAllBookmarks(); 1.585 + int numBookmarks = cur.getCount(); 1.586 + 1.587 + db.purgeGuid(bmk2.guid); 1.588 + 1.589 + // Note size of table after delete. 1.590 + cur = getAllBookmarks(); 1.591 + int numBookmarksAfterDelete = cur.getCount(); 1.592 + 1.593 + // Ensure size of table after delete is *only* 1 less. 1.594 + assertEquals(numBookmarksAfterDelete, numBookmarks - 1); 1.595 + 1.596 + try { 1.597 + cur.moveToFirst(); 1.598 + while (!cur.isAfterLast()) { 1.599 + String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); 1.600 + if (guid.equals(bmk2.guid)) { 1.601 + fail("Guid was not deleted!"); 1.602 + } 1.603 + cur.moveToNext(); 1.604 + } 1.605 + } finally { 1.606 + cur.close(); 1.607 + } 1.608 + dispose(session); 1.609 + } 1.610 + 1.611 + /** 1.612 + * Verify that data accessor's bulkInsert actually inserts. 1.613 + * @throws NullCursorException 1.614 + */ 1.615 + public void testBulkInsert() throws NullCursorException { 1.616 + RepositorySession session = createAndBeginSession(); 1.617 + AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); 1.618 + 1.619 + // Have to set androidID of parent manually. 1.620 + Cursor cur = db.fetch(new String[] { "mobile" } ); 1.621 + assertEquals(1, cur.getCount()); 1.622 + cur.moveToFirst(); 1.623 + int mobileAndroidID = RepoUtils.getIntFromCursor(cur, BrowserContract.Bookmarks._ID); 1.624 + 1.625 + BookmarkRecord bookmark1 = BookmarkHelpers.createBookmarkInMobileFolder1(); 1.626 + BookmarkRecord bookmark2 = BookmarkHelpers.createBookmarkInMobileFolder2(); 1.627 + bookmark1.androidParentID = mobileAndroidID; 1.628 + bookmark2.androidParentID = mobileAndroidID; 1.629 + ArrayList<Record> recordList = new ArrayList<Record>(); 1.630 + recordList.add(bookmark1); 1.631 + recordList.add(bookmark2); 1.632 + db.bulkInsert(recordList); 1.633 + 1.634 + String[] guids = new String[] { bookmark1.guid, bookmark2.guid }; 1.635 + Record[] expected = new Record[] { bookmark1, bookmark2 }; 1.636 + performWait(fetchRunnable(session, guids, expected)); 1.637 + dispose(session); 1.638 + } 1.639 +}