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