Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | package org.mozilla.gecko.background.db; |
michael@0 | 5 | |
michael@0 | 6 | import java.util.ArrayList; |
michael@0 | 7 | |
michael@0 | 8 | import org.json.simple.JSONArray; |
michael@0 | 9 | import org.mozilla.gecko.background.sync.helpers.BookmarkHelpers; |
michael@0 | 10 | import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate; |
michael@0 | 11 | import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate; |
michael@0 | 12 | import org.mozilla.gecko.background.sync.helpers.ExpectFinishDelegate; |
michael@0 | 13 | import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate; |
michael@0 | 14 | import org.mozilla.gecko.background.sync.helpers.ExpectInvalidTypeStoreDelegate; |
michael@0 | 15 | import org.mozilla.gecko.db.BrowserContract; |
michael@0 | 16 | import org.mozilla.gecko.sync.Utils; |
michael@0 | 17 | import org.mozilla.gecko.sync.repositories.InactiveSessionException; |
michael@0 | 18 | import org.mozilla.gecko.sync.repositories.NullCursorException; |
michael@0 | 19 | import org.mozilla.gecko.sync.repositories.RepositorySession; |
michael@0 | 20 | import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksDataAccessor; |
michael@0 | 21 | import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository; |
michael@0 | 22 | import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepositorySession; |
michael@0 | 23 | import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepository; |
michael@0 | 24 | import org.mozilla.gecko.sync.repositories.android.AndroidBrowserRepositoryDataAccessor; |
michael@0 | 25 | import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers; |
michael@0 | 26 | import org.mozilla.gecko.sync.repositories.android.RepoUtils; |
michael@0 | 27 | import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate; |
michael@0 | 28 | import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord; |
michael@0 | 29 | import org.mozilla.gecko.sync.repositories.domain.Record; |
michael@0 | 30 | |
michael@0 | 31 | import android.content.ContentValues; |
michael@0 | 32 | import android.content.Context; |
michael@0 | 33 | import android.database.Cursor; |
michael@0 | 34 | |
michael@0 | 35 | public class TestAndroidBrowserBookmarksRepository extends AndroidBrowserRepositoryTestCase { |
michael@0 | 36 | |
michael@0 | 37 | @Override |
michael@0 | 38 | protected AndroidBrowserRepository getRepository() { |
michael@0 | 39 | |
michael@0 | 40 | /** |
michael@0 | 41 | * Override this chain in order to avoid our test code having to create two |
michael@0 | 42 | * sessions all the time. |
michael@0 | 43 | */ |
michael@0 | 44 | return new AndroidBrowserBookmarksRepository() { |
michael@0 | 45 | @Override |
michael@0 | 46 | protected void sessionCreator(RepositorySessionCreationDelegate delegate, Context context) { |
michael@0 | 47 | AndroidBrowserBookmarksRepositorySession session; |
michael@0 | 48 | session = new AndroidBrowserBookmarksRepositorySession(this, context) { |
michael@0 | 49 | @Override |
michael@0 | 50 | protected synchronized void trackGUID(String guid) { |
michael@0 | 51 | System.out.println("Ignoring trackGUID call: this is a test!"); |
michael@0 | 52 | } |
michael@0 | 53 | }; |
michael@0 | 54 | delegate.deferredCreationDelegate().onSessionCreated(session); |
michael@0 | 55 | } |
michael@0 | 56 | }; |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | @Override |
michael@0 | 60 | protected AndroidBrowserRepositoryDataAccessor getDataAccessor() { |
michael@0 | 61 | return new AndroidBrowserBookmarksDataAccessor(getApplicationContext()); |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | /** |
michael@0 | 65 | * Hook to return an ExpectFetchDelegate, possibly with special GUIDs ignored. |
michael@0 | 66 | */ |
michael@0 | 67 | @Override |
michael@0 | 68 | public ExpectFetchDelegate preparedExpectFetchDelegate(Record[] expected) { |
michael@0 | 69 | ExpectFetchDelegate delegate = new ExpectFetchDelegate(expected); |
michael@0 | 70 | delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); |
michael@0 | 71 | return delegate; |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | /** |
michael@0 | 75 | * Hook to return an ExpectGuidsSinceDelegate expecting only special GUIDs (if there are any). |
michael@0 | 76 | */ |
michael@0 | 77 | public ExpectGuidsSinceDelegate preparedExpectOnlySpecialGuidsSinceDelegate() { |
michael@0 | 78 | ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet().toArray(new String[] {})); |
michael@0 | 79 | return delegate; |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | /** |
michael@0 | 83 | * Hook to return an ExpectGuidsSinceDelegate, possibly with special GUIDs ignored. |
michael@0 | 84 | */ |
michael@0 | 85 | @Override |
michael@0 | 86 | public ExpectGuidsSinceDelegate preparedExpectGuidsSinceDelegate(String[] expected) { |
michael@0 | 87 | ExpectGuidsSinceDelegate delegate = new ExpectGuidsSinceDelegate(expected); |
michael@0 | 88 | delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); |
michael@0 | 89 | return delegate; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | /** |
michael@0 | 93 | * Hook to return an ExpectFetchSinceDelegate, possibly with special GUIDs ignored. |
michael@0 | 94 | */ |
michael@0 | 95 | public ExpectFetchSinceDelegate preparedExpectFetchSinceDelegate(long timestamp, String[] expected) { |
michael@0 | 96 | ExpectFetchSinceDelegate delegate = new ExpectFetchSinceDelegate(timestamp, expected); |
michael@0 | 97 | delegate.ignore.addAll(AndroidBrowserBookmarksRepositorySession.SPECIAL_GUIDS_MAP.keySet()); |
michael@0 | 98 | return delegate; |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | // NOTE NOTE NOTE |
michael@0 | 102 | // Must store folder before records if we we are checking that the |
michael@0 | 103 | // records returned are the same as those sent in. If the folder isn't stored |
michael@0 | 104 | // first, the returned records won't be identical to those stored because we |
michael@0 | 105 | // aren't able to find the parent name/guid when we do a fetch. If you don't want |
michael@0 | 106 | // to store a folder first, store your record in "mobile" or one of the folders |
michael@0 | 107 | // that always exists. |
michael@0 | 108 | |
michael@0 | 109 | public void testFetchOneWithChildren() { |
michael@0 | 110 | BookmarkRecord folder = BookmarkHelpers.createFolder1(); |
michael@0 | 111 | BookmarkRecord bookmark1 = BookmarkHelpers.createBookmark1(); |
michael@0 | 112 | BookmarkRecord bookmark2 = BookmarkHelpers.createBookmark2(); |
michael@0 | 113 | |
michael@0 | 114 | RepositorySession session = createAndBeginSession(); |
michael@0 | 115 | |
michael@0 | 116 | Record[] records = new Record[] { folder, bookmark1, bookmark2 }; |
michael@0 | 117 | performWait(storeManyRunnable(session, records)); |
michael@0 | 118 | |
michael@0 | 119 | AndroidBrowserRepositoryDataAccessor helper = getDataAccessor(); |
michael@0 | 120 | helper.dumpDB(); |
michael@0 | 121 | closeDataAccessor(helper); |
michael@0 | 122 | |
michael@0 | 123 | String[] guids = new String[] { folder.guid }; |
michael@0 | 124 | Record[] expected = new Record[] { folder }; |
michael@0 | 125 | performWait(fetchRunnable(session, guids, expected)); |
michael@0 | 126 | dispose(session); |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | @Override |
michael@0 | 130 | public void testFetchAll() { |
michael@0 | 131 | Record[] expected = new Record[3]; |
michael@0 | 132 | expected[0] = BookmarkHelpers.createFolder1(); |
michael@0 | 133 | expected[1] = BookmarkHelpers.createBookmark1(); |
michael@0 | 134 | expected[2] = BookmarkHelpers.createBookmark2(); |
michael@0 | 135 | basicFetchAllTest(expected); |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | @Override |
michael@0 | 139 | public void testGuidsSinceReturnMultipleRecords() { |
michael@0 | 140 | BookmarkRecord record0 = BookmarkHelpers.createBookmark1(); |
michael@0 | 141 | BookmarkRecord record1 = BookmarkHelpers.createBookmark2(); |
michael@0 | 142 | guidsSinceReturnMultipleRecords(record0, record1); |
michael@0 | 143 | } |
michael@0 | 144 | |
michael@0 | 145 | @Override |
michael@0 | 146 | public void testGuidsSinceReturnNoRecords() { |
michael@0 | 147 | guidsSinceReturnNoRecords(BookmarkHelpers.createBookmarkInMobileFolder1()); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | @Override |
michael@0 | 151 | public void testFetchSinceOneRecord() { |
michael@0 | 152 | fetchSinceOneRecord(BookmarkHelpers.createBookmarkInMobileFolder1(), |
michael@0 | 153 | BookmarkHelpers.createBookmarkInMobileFolder2()); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | @Override |
michael@0 | 157 | public void testFetchSinceReturnNoRecords() { |
michael@0 | 158 | fetchSinceReturnNoRecords(BookmarkHelpers.createBookmark1()); |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | @Override |
michael@0 | 162 | public void testFetchOneRecordByGuid() { |
michael@0 | 163 | fetchOneRecordByGuid(BookmarkHelpers.createBookmarkInMobileFolder1(), |
michael@0 | 164 | BookmarkHelpers.createBookmarkInMobileFolder2()); |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | @Override |
michael@0 | 168 | public void testFetchMultipleRecordsByGuids() { |
michael@0 | 169 | BookmarkRecord record0 = BookmarkHelpers.createFolder1(); |
michael@0 | 170 | BookmarkRecord record1 = BookmarkHelpers.createBookmark1(); |
michael@0 | 171 | BookmarkRecord record2 = BookmarkHelpers.createBookmark2(); |
michael@0 | 172 | fetchMultipleRecordsByGuids(record0, record1, record2); |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | @Override |
michael@0 | 176 | public void testFetchNoRecordByGuid() { |
michael@0 | 177 | fetchNoRecordByGuid(BookmarkHelpers.createBookmark1()); |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | |
michael@0 | 181 | @Override |
michael@0 | 182 | public void testWipe() { |
michael@0 | 183 | doWipe(BookmarkHelpers.createBookmarkInMobileFolder1(), |
michael@0 | 184 | BookmarkHelpers.createBookmarkInMobileFolder2()); |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | @Override |
michael@0 | 188 | public void testStore() { |
michael@0 | 189 | basicStoreTest(BookmarkHelpers.createBookmark1()); |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | |
michael@0 | 193 | public void testStoreFolder() { |
michael@0 | 194 | basicStoreTest(BookmarkHelpers.createFolder1()); |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | /** |
michael@0 | 198 | * TODO: 2011-12-24, tests disabled because we no longer fail |
michael@0 | 199 | * a store call if we get an unknown record type. |
michael@0 | 200 | */ |
michael@0 | 201 | /* |
michael@0 | 202 | * Test storing each different type of Bookmark record. |
michael@0 | 203 | * We expect any records with type other than "bookmark" |
michael@0 | 204 | * or "folder" to fail. For now we throw these away. |
michael@0 | 205 | */ |
michael@0 | 206 | /* |
michael@0 | 207 | public void testStoreMicrosummary() { |
michael@0 | 208 | basicStoreFailTest(BookmarkHelpers.createMicrosummary()); |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | public void testStoreQuery() { |
michael@0 | 212 | basicStoreFailTest(BookmarkHelpers.createQuery()); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | public void testStoreLivemark() { |
michael@0 | 216 | basicStoreFailTest(BookmarkHelpers.createLivemark()); |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | public void testStoreSeparator() { |
michael@0 | 220 | basicStoreFailTest(BookmarkHelpers.createSeparator()); |
michael@0 | 221 | } |
michael@0 | 222 | */ |
michael@0 | 223 | |
michael@0 | 224 | protected void basicStoreFailTest(Record record) { |
michael@0 | 225 | final RepositorySession session = createAndBeginSession(); |
michael@0 | 226 | performWait(storeRunnable(session, record, new ExpectInvalidTypeStoreDelegate())); |
michael@0 | 227 | dispose(session); |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | /* |
michael@0 | 231 | * Re-parenting tests |
michael@0 | 232 | */ |
michael@0 | 233 | // Insert two records missing parent, then insert their parent. |
michael@0 | 234 | // Make sure they end up with the correct parent on fetch. |
michael@0 | 235 | public void testBasicReparenting() throws InactiveSessionException { |
michael@0 | 236 | Record[] expected = new Record[] { |
michael@0 | 237 | BookmarkHelpers.createBookmark1(), |
michael@0 | 238 | BookmarkHelpers.createBookmark2(), |
michael@0 | 239 | BookmarkHelpers.createFolder1() |
michael@0 | 240 | }; |
michael@0 | 241 | doMultipleFolderReparentingTest(expected); |
michael@0 | 242 | } |
michael@0 | 243 | |
michael@0 | 244 | // Insert 3 folders and 4 bookmarks in different orders |
michael@0 | 245 | // and make sure they come out parented correctly |
michael@0 | 246 | public void testMultipleFolderReparenting1() throws InactiveSessionException { |
michael@0 | 247 | Record[] expected = new Record[] { |
michael@0 | 248 | BookmarkHelpers.createBookmark1(), |
michael@0 | 249 | BookmarkHelpers.createBookmark2(), |
michael@0 | 250 | BookmarkHelpers.createBookmark3(), |
michael@0 | 251 | BookmarkHelpers.createFolder1(), |
michael@0 | 252 | BookmarkHelpers.createBookmark4(), |
michael@0 | 253 | BookmarkHelpers.createFolder3(), |
michael@0 | 254 | BookmarkHelpers.createFolder2(), |
michael@0 | 255 | }; |
michael@0 | 256 | doMultipleFolderReparentingTest(expected); |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | public void testMultipleFolderReparenting2() throws InactiveSessionException { |
michael@0 | 260 | Record[] expected = new Record[] { |
michael@0 | 261 | BookmarkHelpers.createBookmark1(), |
michael@0 | 262 | BookmarkHelpers.createBookmark2(), |
michael@0 | 263 | BookmarkHelpers.createBookmark3(), |
michael@0 | 264 | BookmarkHelpers.createFolder1(), |
michael@0 | 265 | BookmarkHelpers.createBookmark4(), |
michael@0 | 266 | BookmarkHelpers.createFolder3(), |
michael@0 | 267 | BookmarkHelpers.createFolder2(), |
michael@0 | 268 | }; |
michael@0 | 269 | doMultipleFolderReparentingTest(expected); |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | public void testMultipleFolderReparenting3() throws InactiveSessionException { |
michael@0 | 273 | Record[] expected = new Record[] { |
michael@0 | 274 | BookmarkHelpers.createBookmark1(), |
michael@0 | 275 | BookmarkHelpers.createBookmark2(), |
michael@0 | 276 | BookmarkHelpers.createBookmark3(), |
michael@0 | 277 | BookmarkHelpers.createFolder1(), |
michael@0 | 278 | BookmarkHelpers.createBookmark4(), |
michael@0 | 279 | BookmarkHelpers.createFolder3(), |
michael@0 | 280 | BookmarkHelpers.createFolder2(), |
michael@0 | 281 | }; |
michael@0 | 282 | doMultipleFolderReparentingTest(expected); |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | private void doMultipleFolderReparentingTest(Record[] expected) throws InactiveSessionException { |
michael@0 | 286 | final RepositorySession session = createAndBeginSession(); |
michael@0 | 287 | doStore(session, expected); |
michael@0 | 288 | ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected); |
michael@0 | 289 | performWait(fetchAllRunnable(session, delegate)); |
michael@0 | 290 | performWait(finishRunnable(session, new ExpectFinishDelegate())); |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | /* |
michael@0 | 294 | * Test storing identical records with different guids. |
michael@0 | 295 | * For bookmarks identical is defined by the following fields |
michael@0 | 296 | * being the same: title, uri, type, parentName |
michael@0 | 297 | */ |
michael@0 | 298 | @Override |
michael@0 | 299 | public void testStoreIdenticalExceptGuid() { |
michael@0 | 300 | storeIdenticalExceptGuid(BookmarkHelpers.createBookmarkInMobileFolder1()); |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | /* |
michael@0 | 304 | * More complicated situation in which we insert a folder |
michael@0 | 305 | * followed by a couple of its children. We then insert |
michael@0 | 306 | * the folder again but with a different guid. Children |
michael@0 | 307 | * must still get correct parent when they are fetched. |
michael@0 | 308 | * Store a record after with the new guid as the parent |
michael@0 | 309 | * and make sure it works as well. |
michael@0 | 310 | */ |
michael@0 | 311 | public void testStoreIdenticalFoldersWithChildren() { |
michael@0 | 312 | final RepositorySession session = createAndBeginSession(); |
michael@0 | 313 | Record record0 = BookmarkHelpers.createFolder1(); |
michael@0 | 314 | |
michael@0 | 315 | // Get timestamp so that the conflicting folder that we store below is newer. |
michael@0 | 316 | // Children won't come back on this fetch since they haven't been stored, so remove them |
michael@0 | 317 | // before our delegate throws a failure. |
michael@0 | 318 | BookmarkRecord rec0 = (BookmarkRecord) record0; |
michael@0 | 319 | rec0.children = new JSONArray(); |
michael@0 | 320 | performWait(storeRunnable(session, record0)); |
michael@0 | 321 | |
michael@0 | 322 | ExpectFetchDelegate timestampDelegate = preparedExpectFetchDelegate(new Record[] { rec0 }); |
michael@0 | 323 | performWait(fetchRunnable(session, new String[] { record0.guid }, timestampDelegate)); |
michael@0 | 324 | |
michael@0 | 325 | AndroidBrowserRepositoryDataAccessor helper = getDataAccessor(); |
michael@0 | 326 | helper.dumpDB(); |
michael@0 | 327 | closeDataAccessor(helper); |
michael@0 | 328 | |
michael@0 | 329 | Record record1 = BookmarkHelpers.createBookmark1(); |
michael@0 | 330 | Record record2 = BookmarkHelpers.createBookmark2(); |
michael@0 | 331 | Record record3 = BookmarkHelpers.createFolder1(); |
michael@0 | 332 | BookmarkRecord bmk3 = (BookmarkRecord) record3; |
michael@0 | 333 | record3.guid = Utils.generateGuid(); |
michael@0 | 334 | record3.lastModified = timestampDelegate.records.get(0).lastModified + 3000; |
michael@0 | 335 | assert(!record0.guid.equals(record3.guid)); |
michael@0 | 336 | |
michael@0 | 337 | // Store an additional record after inserting the duplicate folder |
michael@0 | 338 | // with new GUID. Make sure it comes back as well. |
michael@0 | 339 | Record record4 = BookmarkHelpers.createBookmark3(); |
michael@0 | 340 | BookmarkRecord bmk4 = (BookmarkRecord) record4; |
michael@0 | 341 | bmk4.parentID = bmk3.guid; |
michael@0 | 342 | bmk4.parentName = bmk3.parentName; |
michael@0 | 343 | |
michael@0 | 344 | doStore(session, new Record[] { |
michael@0 | 345 | record1, record2, record3, bmk4 |
michael@0 | 346 | }); |
michael@0 | 347 | BookmarkRecord bmk1 = (BookmarkRecord) record1; |
michael@0 | 348 | bmk1.parentID = record3.guid; |
michael@0 | 349 | BookmarkRecord bmk2 = (BookmarkRecord) record2; |
michael@0 | 350 | bmk2.parentID = record3.guid; |
michael@0 | 351 | Record[] expect = new Record[] { |
michael@0 | 352 | bmk1, bmk2, record3 |
michael@0 | 353 | }; |
michael@0 | 354 | fetchAllRunnable(session, preparedExpectFetchDelegate(expect)); |
michael@0 | 355 | dispose(session); |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | @Override |
michael@0 | 359 | public void testRemoteNewerTimeStamp() { |
michael@0 | 360 | BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); |
michael@0 | 361 | BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); |
michael@0 | 362 | remoteNewerTimeStamp(local, remote); |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | @Override |
michael@0 | 366 | public void testLocalNewerTimeStamp() { |
michael@0 | 367 | BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); |
michael@0 | 368 | BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); |
michael@0 | 369 | localNewerTimeStamp(local, remote); |
michael@0 | 370 | } |
michael@0 | 371 | |
michael@0 | 372 | @Override |
michael@0 | 373 | public void testDeleteRemoteNewer() { |
michael@0 | 374 | BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); |
michael@0 | 375 | BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); |
michael@0 | 376 | deleteRemoteNewer(local, remote); |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | @Override |
michael@0 | 380 | public void testDeleteLocalNewer() { |
michael@0 | 381 | BookmarkRecord local = BookmarkHelpers.createBookmarkInMobileFolder1(); |
michael@0 | 382 | BookmarkRecord remote = BookmarkHelpers.createBookmarkInMobileFolder2(); |
michael@0 | 383 | deleteLocalNewer(local, remote); |
michael@0 | 384 | } |
michael@0 | 385 | |
michael@0 | 386 | @Override |
michael@0 | 387 | public void testDeleteRemoteLocalNonexistent() { |
michael@0 | 388 | BookmarkRecord remote = BookmarkHelpers.createBookmark2(); |
michael@0 | 389 | deleteRemoteLocalNonexistent(remote); |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | @Override |
michael@0 | 393 | public void testCleanMultipleRecords() { |
michael@0 | 394 | cleanMultipleRecords( |
michael@0 | 395 | BookmarkHelpers.createBookmarkInMobileFolder1(), |
michael@0 | 396 | BookmarkHelpers.createBookmarkInMobileFolder2(), |
michael@0 | 397 | BookmarkHelpers.createBookmark1(), |
michael@0 | 398 | BookmarkHelpers.createBookmark2(), |
michael@0 | 399 | BookmarkHelpers.createFolder1()); |
michael@0 | 400 | } |
michael@0 | 401 | |
michael@0 | 402 | public void testBasicPositioning() { |
michael@0 | 403 | final RepositorySession session = createAndBeginSession(); |
michael@0 | 404 | Record[] expected = new Record[] { |
michael@0 | 405 | BookmarkHelpers.createBookmark1(), |
michael@0 | 406 | BookmarkHelpers.createFolder1(), |
michael@0 | 407 | BookmarkHelpers.createBookmark2() |
michael@0 | 408 | }; |
michael@0 | 409 | System.out.println("TEST: Inserting " + expected[0].guid + ", " |
michael@0 | 410 | + expected[1].guid + ", " |
michael@0 | 411 | + expected[2].guid); |
michael@0 | 412 | doStore(session, expected); |
michael@0 | 413 | |
michael@0 | 414 | ExpectFetchDelegate delegate = preparedExpectFetchDelegate(expected); |
michael@0 | 415 | performWait(fetchAllRunnable(session, delegate)); |
michael@0 | 416 | |
michael@0 | 417 | int found = 0; |
michael@0 | 418 | boolean foundFolder = false; |
michael@0 | 419 | for (int i = 0; i < delegate.records.size(); i++) { |
michael@0 | 420 | BookmarkRecord rec = (BookmarkRecord) delegate.records.get(i); |
michael@0 | 421 | if (rec.guid.equals(expected[0].guid)) { |
michael@0 | 422 | assertEquals(0, ((BookmarkRecord) delegate.records.get(i)).androidPosition); |
michael@0 | 423 | found++; |
michael@0 | 424 | } else if (rec.guid.equals(expected[2].guid)) { |
michael@0 | 425 | assertEquals(1, ((BookmarkRecord) delegate.records.get(i)).androidPosition); |
michael@0 | 426 | found++; |
michael@0 | 427 | } else if (rec.guid.equals(expected[1].guid)) { |
michael@0 | 428 | foundFolder = true; |
michael@0 | 429 | } else { |
michael@0 | 430 | System.out.println("TEST: found " + rec.guid); |
michael@0 | 431 | } |
michael@0 | 432 | } |
michael@0 | 433 | assertTrue(foundFolder); |
michael@0 | 434 | assertEquals(2, found); |
michael@0 | 435 | dispose(session); |
michael@0 | 436 | } |
michael@0 | 437 | |
michael@0 | 438 | public void testSqlInjectPurgeDeleteAndUpdateByGuid() { |
michael@0 | 439 | // Some setup. |
michael@0 | 440 | RepositorySession session = createAndBeginSession(); |
michael@0 | 441 | AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); |
michael@0 | 442 | |
michael@0 | 443 | ContentValues cv = new ContentValues(); |
michael@0 | 444 | cv.put(BrowserContract.SyncColumns.IS_DELETED, 1); |
michael@0 | 445 | |
michael@0 | 446 | // Create and insert 2 bookmarks, 2nd one is evil (attempts injection). |
michael@0 | 447 | BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); |
michael@0 | 448 | BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); |
michael@0 | 449 | bmk2.guid = "' or '1'='1"; |
michael@0 | 450 | |
michael@0 | 451 | db.insert(bmk1); |
michael@0 | 452 | db.insert(bmk2); |
michael@0 | 453 | |
michael@0 | 454 | // Test 1 - updateByGuid() handles evil bookmarks correctly. |
michael@0 | 455 | db.updateByGuid(bmk2.guid, cv); |
michael@0 | 456 | |
michael@0 | 457 | // Query bookmarks table. |
michael@0 | 458 | Cursor cur = getAllBookmarks(); |
michael@0 | 459 | int numBookmarks = cur.getCount(); |
michael@0 | 460 | |
michael@0 | 461 | // Ensure only the evil bookmark is marked for deletion. |
michael@0 | 462 | try { |
michael@0 | 463 | cur.moveToFirst(); |
michael@0 | 464 | while (!cur.isAfterLast()) { |
michael@0 | 465 | String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); |
michael@0 | 466 | boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; |
michael@0 | 467 | |
michael@0 | 468 | if (guid.equals(bmk2.guid)) { |
michael@0 | 469 | assertTrue(deleted); |
michael@0 | 470 | } else { |
michael@0 | 471 | assertFalse(deleted); |
michael@0 | 472 | } |
michael@0 | 473 | cur.moveToNext(); |
michael@0 | 474 | } |
michael@0 | 475 | } finally { |
michael@0 | 476 | cur.close(); |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | // Test 2 - Ensure purgeDelete()'s call to delete() deletes only 1 record. |
michael@0 | 480 | try { |
michael@0 | 481 | db.purgeDeleted(); |
michael@0 | 482 | } catch (NullCursorException e) { |
michael@0 | 483 | e.printStackTrace(); |
michael@0 | 484 | } |
michael@0 | 485 | |
michael@0 | 486 | cur = getAllBookmarks(); |
michael@0 | 487 | int numBookmarksAfterDeletion = cur.getCount(); |
michael@0 | 488 | |
michael@0 | 489 | // Ensure we have only 1 deleted row. |
michael@0 | 490 | assertEquals(numBookmarksAfterDeletion, numBookmarks - 1); |
michael@0 | 491 | |
michael@0 | 492 | // Ensure only the evil bookmark is deleted. |
michael@0 | 493 | try { |
michael@0 | 494 | cur.moveToFirst(); |
michael@0 | 495 | while (!cur.isAfterLast()) { |
michael@0 | 496 | String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); |
michael@0 | 497 | boolean deleted = RepoUtils.getLongFromCursor(cur, BrowserContract.SyncColumns.IS_DELETED) == 1; |
michael@0 | 498 | |
michael@0 | 499 | if (guid.equals(bmk2.guid)) { |
michael@0 | 500 | fail("Evil guid was not deleted!"); |
michael@0 | 501 | } else { |
michael@0 | 502 | assertFalse(deleted); |
michael@0 | 503 | } |
michael@0 | 504 | cur.moveToNext(); |
michael@0 | 505 | } |
michael@0 | 506 | } finally { |
michael@0 | 507 | cur.close(); |
michael@0 | 508 | } |
michael@0 | 509 | dispose(session); |
michael@0 | 510 | } |
michael@0 | 511 | |
michael@0 | 512 | protected Cursor getAllBookmarks() { |
michael@0 | 513 | Context context = getApplicationContext(); |
michael@0 | 514 | Cursor cur = context.getContentResolver().query(BrowserContractHelpers.BOOKMARKS_CONTENT_URI, |
michael@0 | 515 | BrowserContractHelpers.BookmarkColumns, null, null, null); |
michael@0 | 516 | return cur; |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | public void testSqlInjectFetch() { |
michael@0 | 520 | // Some setup. |
michael@0 | 521 | RepositorySession session = createAndBeginSession(); |
michael@0 | 522 | AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); |
michael@0 | 523 | |
michael@0 | 524 | // Create and insert 4 bookmarks, last one is evil (attempts injection). |
michael@0 | 525 | BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); |
michael@0 | 526 | BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); |
michael@0 | 527 | BookmarkRecord bmk3 = BookmarkHelpers.createBookmark3(); |
michael@0 | 528 | BookmarkRecord bmk4 = BookmarkHelpers.createBookmark4(); |
michael@0 | 529 | bmk4.guid = "' or '1'='1"; |
michael@0 | 530 | |
michael@0 | 531 | db.insert(bmk1); |
michael@0 | 532 | db.insert(bmk2); |
michael@0 | 533 | db.insert(bmk3); |
michael@0 | 534 | db.insert(bmk4); |
michael@0 | 535 | |
michael@0 | 536 | // Perform a fetch. |
michael@0 | 537 | Cursor cur = null; |
michael@0 | 538 | try { |
michael@0 | 539 | cur = db.fetch(new String[] { bmk3.guid, bmk4.guid }); |
michael@0 | 540 | } catch (NullCursorException e1) { |
michael@0 | 541 | e1.printStackTrace(); |
michael@0 | 542 | } |
michael@0 | 543 | |
michael@0 | 544 | // Ensure the correct number (2) of records were fetched and with the correct guids. |
michael@0 | 545 | if (cur == null) { |
michael@0 | 546 | fail("No records were fetched."); |
michael@0 | 547 | } |
michael@0 | 548 | |
michael@0 | 549 | try { |
michael@0 | 550 | if (cur.getCount() != 2) { |
michael@0 | 551 | fail("Wrong number of guids fetched!"); |
michael@0 | 552 | } |
michael@0 | 553 | cur.moveToFirst(); |
michael@0 | 554 | while (!cur.isAfterLast()) { |
michael@0 | 555 | String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); |
michael@0 | 556 | if (!guid.equals(bmk3.guid) && !guid.equals(bmk4.guid)) { |
michael@0 | 557 | fail("Wrong guids were fetched!"); |
michael@0 | 558 | } |
michael@0 | 559 | cur.moveToNext(); |
michael@0 | 560 | } |
michael@0 | 561 | } finally { |
michael@0 | 562 | cur.close(); |
michael@0 | 563 | } |
michael@0 | 564 | dispose(session); |
michael@0 | 565 | } |
michael@0 | 566 | |
michael@0 | 567 | public void testSqlInjectDelete() { |
michael@0 | 568 | // Some setup. |
michael@0 | 569 | RepositorySession session = createAndBeginSession(); |
michael@0 | 570 | AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); |
michael@0 | 571 | |
michael@0 | 572 | // Create and insert 2 bookmarks, 2nd one is evil (attempts injection). |
michael@0 | 573 | BookmarkRecord bmk1 = BookmarkHelpers.createBookmark1(); |
michael@0 | 574 | BookmarkRecord bmk2 = BookmarkHelpers.createBookmark2(); |
michael@0 | 575 | bmk2.guid = "' or '1'='1"; |
michael@0 | 576 | |
michael@0 | 577 | db.insert(bmk1); |
michael@0 | 578 | db.insert(bmk2); |
michael@0 | 579 | |
michael@0 | 580 | // Note size of table before delete. |
michael@0 | 581 | Cursor cur = getAllBookmarks(); |
michael@0 | 582 | int numBookmarks = cur.getCount(); |
michael@0 | 583 | |
michael@0 | 584 | db.purgeGuid(bmk2.guid); |
michael@0 | 585 | |
michael@0 | 586 | // Note size of table after delete. |
michael@0 | 587 | cur = getAllBookmarks(); |
michael@0 | 588 | int numBookmarksAfterDelete = cur.getCount(); |
michael@0 | 589 | |
michael@0 | 590 | // Ensure size of table after delete is *only* 1 less. |
michael@0 | 591 | assertEquals(numBookmarksAfterDelete, numBookmarks - 1); |
michael@0 | 592 | |
michael@0 | 593 | try { |
michael@0 | 594 | cur.moveToFirst(); |
michael@0 | 595 | while (!cur.isAfterLast()) { |
michael@0 | 596 | String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.SyncColumns.GUID); |
michael@0 | 597 | if (guid.equals(bmk2.guid)) { |
michael@0 | 598 | fail("Guid was not deleted!"); |
michael@0 | 599 | } |
michael@0 | 600 | cur.moveToNext(); |
michael@0 | 601 | } |
michael@0 | 602 | } finally { |
michael@0 | 603 | cur.close(); |
michael@0 | 604 | } |
michael@0 | 605 | dispose(session); |
michael@0 | 606 | } |
michael@0 | 607 | |
michael@0 | 608 | /** |
michael@0 | 609 | * Verify that data accessor's bulkInsert actually inserts. |
michael@0 | 610 | * @throws NullCursorException |
michael@0 | 611 | */ |
michael@0 | 612 | public void testBulkInsert() throws NullCursorException { |
michael@0 | 613 | RepositorySession session = createAndBeginSession(); |
michael@0 | 614 | AndroidBrowserRepositoryDataAccessor db = getDataAccessor(); |
michael@0 | 615 | |
michael@0 | 616 | // Have to set androidID of parent manually. |
michael@0 | 617 | Cursor cur = db.fetch(new String[] { "mobile" } ); |
michael@0 | 618 | assertEquals(1, cur.getCount()); |
michael@0 | 619 | cur.moveToFirst(); |
michael@0 | 620 | int mobileAndroidID = RepoUtils.getIntFromCursor(cur, BrowserContract.Bookmarks._ID); |
michael@0 | 621 | |
michael@0 | 622 | BookmarkRecord bookmark1 = BookmarkHelpers.createBookmarkInMobileFolder1(); |
michael@0 | 623 | BookmarkRecord bookmark2 = BookmarkHelpers.createBookmarkInMobileFolder2(); |
michael@0 | 624 | bookmark1.androidParentID = mobileAndroidID; |
michael@0 | 625 | bookmark2.androidParentID = mobileAndroidID; |
michael@0 | 626 | ArrayList<Record> recordList = new ArrayList<Record>(); |
michael@0 | 627 | recordList.add(bookmark1); |
michael@0 | 628 | recordList.add(bookmark2); |
michael@0 | 629 | db.bulkInsert(recordList); |
michael@0 | 630 | |
michael@0 | 631 | String[] guids = new String[] { bookmark1.guid, bookmark2.guid }; |
michael@0 | 632 | Record[] expected = new Record[] { bookmark1, bookmark2 }; |
michael@0 | 633 | performWait(fetchRunnable(session, guids, expected)); |
michael@0 | 634 | dispose(session); |
michael@0 | 635 | } |
michael@0 | 636 | } |