new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHighlightsTest.java
@@ -0,0 +1,346 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.gecko.db;
+
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mozilla.gecko.background.testhelpers.TestRunner;
+import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
+import org.mozilla.gecko.sync.setup.Constants;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import static org.mozilla.gecko.db.BrowserContract.PARAM_PROFILE;
+
+/**
+ * Unit tests for the highlights query (Activity Stream).
+ */
+@RunWith(TestRunner.class)
+public class BrowserProviderHighlightsTest extends BrowserProviderHistoryVisitsTestBase {
+ private ContentProviderClient highlightsClient;
+ private ContentProviderClient bookmarksClient;
+
+ private Uri highlightsTestUri;
+ private Uri bookmarksTestUri;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final Uri highlightsClientUri = BrowserContract.Highlights.CONTENT_URI.buildUpon()
+ .appendQueryParameter(PARAM_PROFILE, Constants.DEFAULT_PROFILE)
+ .build();
+
+ highlightsClient = contentResolver.acquireContentProviderClient(highlightsClientUri);
+ bookmarksClient = contentResolver.acquireContentProviderClient(BrowserContractHelpers.BOOKMARKS_CONTENT_URI);
+
+ highlightsTestUri = testUri(BrowserContract.Highlights.CONTENT_URI);
+ bookmarksTestUri = testUri(BrowserContract.Bookmarks.CONTENT_URI);
+ }
+
+ @After
+ public void tearDown() {
+ highlightsClient.release();
+ bookmarksClient.release();
+
+ super.tearDown();
+ }
+
+ /**
+ * Scenario: Empty database, no history, no bookmarks.
+ *
+ * Assert that:
+ * - Empty cursor (not null) is returned.
+ */
+ @Test
+ public void testEmptyDatabase() throws Exception {
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(0, cursor.getCount());
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: The database only contains very recent history (now, 5 minutes ago, 20 minutes).
+ *
+ * Assert that:
+ * - No highlight is returned from recent history.
+ */
+ @Test
+ public void testOnlyRecentHistory() throws Exception {
+ final long now = System.currentTimeMillis();
+ final long fiveMinutesAgo = now - 1000 * 60 * 5;
+ final long twentyMinutes = now - 1000 * 60 * 20;
+
+ insertHistoryItem(createUniqueUrl(), createGUID(), now, 1, createUniqueTitle());
+ insertHistoryItem(createUniqueUrl(), createGUID(), fiveMinutesAgo, 1, createUniqueTitle());
+ insertHistoryItem(createUniqueUrl(), createGUID(), twentyMinutes, 1, createUniqueTitle());
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(0, cursor.getCount());
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: The database contains recent (but not too fresh) history (1 hour, 5 days).
+ *
+ * Assert that:
+ * - Highlights are returned from history.
+ */
+ @Test
+ public void testHighlightsArePickedFromHistory() throws Exception {
+ final String url1 = createUniqueUrl();
+ final String url2 = createUniqueUrl();
+ final String title1 = createUniqueTitle();
+ final String title2 = createUniqueTitle();
+
+ final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
+ final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
+
+ insertHistoryItem(url1, createGUID(), oneHourAgo, 1, title1);
+ insertHistoryItem(url2, createGUID(), fiveDaysAgo, 1, title2);
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(2, cursor.getCount());
+
+ assertCursorContainsEntry(cursor, url1, title1);
+ assertCursorContainsEntry(cursor, url2, title2);
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: The database contains history that is visited frequently and rarely.
+ *
+ * Assert that:
+ * - Highlights are picked from rarely visited websites.
+ * - Highlights are not picked from frequently visited websites.
+ */
+ @Test
+ public void testOftenVisitedPagesAreNotPicked() throws Exception {
+ final String url1 = createUniqueUrl();
+ final String title1 = createUniqueTitle();
+
+ final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
+ final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
+
+ insertHistoryItem(url1, createGUID(), oneHourAgo, 2, title1);
+ insertHistoryItem(createUniqueUrl(), createGUID(), fiveDaysAgo, 25, createUniqueTitle());
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ // Verify that only the first URL (with one visit) is picked and the second URL with 25 visits is ignored.
+
+ Assert.assertEquals(1, cursor.getCount());
+
+ cursor.moveToNext();
+ assertCursor(cursor, url1, title1);
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: The database contains history with and without titles.
+ *
+ * Assert that:
+ * - History without titles is not picked for highlights.
+ */
+ @Test
+ public void testHistoryWithoutTitlesIsNotPicked() throws Exception {
+ final String url1 = createUniqueUrl();
+ final String url2 = createUniqueUrl();
+ final String title1 = "";
+ final String title2 = createUniqueTitle();
+
+ final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
+ final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
+
+ insertHistoryItem(url1, createGUID(), oneHourAgo, 1, title1);
+ insertHistoryItem(url2, createGUID(), fiveDaysAgo, 1, title2);
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ // Only one bookmark will be picked for highlights
+ Assert.assertEquals(1, cursor.getCount());
+
+ cursor.moveToNext();
+ assertCursor(cursor, url2, title2);
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: Database contains two bookmarks (unvisited).
+ *
+ * Assert that:
+ * - One bookmark is picked for highlights.
+ */
+ @Test
+ public void testPickingBookmarkForHighlights() throws Exception {
+ final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
+ final long fiveDaysAgo = System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 5;
+
+ final String url1 = createUniqueUrl();
+ final String url2 = createUniqueUrl();
+ final String title1 = createUniqueTitle();
+ final String title2 = createUniqueTitle();
+
+ insertBookmarkItem(url1, title1, oneHourAgo);
+ insertBookmarkItem(url2, title2, fiveDaysAgo);
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(1, cursor.getCount());
+
+ cursor.moveToNext();
+ assertCursor(cursor, url1, title1);
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: Database contains an often visited bookmark.
+ *
+ * Assert that:
+ * - Bookmark is not selected for highlights.
+ */
+ @Test
+ public void testOftenVisitedBookmarksWillNotBePicked() throws Exception {
+ final String url = createUniqueUrl();
+ final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
+
+ insertBookmarkItem(url, createUniqueTitle(), oneHourAgo);
+ insertHistoryItem(url, createGUID(), oneHourAgo, 25, createUniqueTitle());
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(0, cursor.getCount());
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: Database contains URL as bookmark and in history (not visited often).
+ *
+ * Assert that:
+ * - URL is not picked twice (as bookmark and from history)
+ */
+ @Test
+ public void testSameUrlIsNotPickedFromHistoryAndBookmarks() throws Exception {
+ final String url = createUniqueUrl();
+
+ final long oneHourAgo = System.currentTimeMillis() - 1000 * 60 * 60;
+
+ // Insert bookmark that is picked for highlights
+ insertBookmarkItem(url, createUniqueTitle(), oneHourAgo);
+ // Insert history for same URL that would be picked for highlights too
+ insertHistoryItem(url, createGUID(), oneHourAgo, 2, createUniqueTitle());
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(1, cursor.getCount());
+
+ cursor.close();
+ }
+
+ /**
+ * Scenario: Database contains only old bookmarks.
+ *
+ * Assert that:
+ * - Old bookmarks are not selected as highlight.
+ */
+ @Test
+ public void testVeryOldBookmarksAreNotSelected() throws Exception {
+ final long oneWeekAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+ final long oneMonthAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31);
+ final long oneYearAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(365);
+
+ insertBookmarkItem(createUniqueUrl(), createUniqueTitle(), oneWeekAgo);
+ insertBookmarkItem(createUniqueUrl(), createUniqueTitle(), oneMonthAgo);
+ insertBookmarkItem(createUniqueUrl(), createUniqueTitle(), oneYearAgo);
+
+ final Cursor cursor = highlightsClient.query(highlightsTestUri, null, null, null, null);
+ Assert.assertNotNull(cursor);
+
+ Assert.assertEquals(0, cursor.getCount());
+
+ cursor.close();
+ }
+
+ private void insertBookmarkItem(String url, String title, long createdAt) throws RemoteException {
+ ContentValues values = new ContentValues();
+
+ values.put(BrowserContract.Bookmarks.URL, url);
+ values.put(BrowserContract.Bookmarks.TITLE, title);
+ values.put(BrowserContract.Bookmarks.PARENT, 0);
+ values.put(BrowserContract.Bookmarks.TYPE, BrowserContract.Bookmarks.TYPE_BOOKMARK);
+ values.put(BrowserContract.Bookmarks.DATE_CREATED, createdAt);
+
+ bookmarksClient.insert(bookmarksTestUri, values);
+ }
+
+ private void assertCursor(Cursor cursor, String url, String title) {
+ final String actualTitle = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.TITLE));
+ Assert.assertEquals(title, actualTitle);
+
+ final String actualUrl = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
+ Assert.assertEquals(url, actualUrl);
+ }
+
+ private void assertCursorContainsEntry(Cursor cursor, String url, String title) {
+ cursor.moveToFirst();
+
+ do {
+ final String actualTitle = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.TITLE));
+ final String actualUrl = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
+
+ if (actualTitle.equals(title) && actualUrl.equals(url)) {
+ return;
+ }
+ } while (cursor.moveToNext());
+
+ Assert.fail("Could not find entry title=" + title + ", url=" + url);
+ }
+
+ private String createUniqueUrl() {
+ return new Uri.Builder()
+ .scheme("https")
+ .authority(UUID.randomUUID().toString() + ".example.org")
+ .appendPath(UUID.randomUUID().toString())
+ .appendPath(UUID.randomUUID().toString())
+ .build()
+ .toString();
+ }
+
+ private String createUniqueTitle() {
+ return "Title " + UUID.randomUUID().toString();
+ }
+
+ private String createGUID() {
+ return UUID.randomUUID().toString();
+ }
+}
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java
@@ -8,58 +8,69 @@ import android.content.ContentValues;
import android.net.Uri;
import android.os.RemoteException;
import org.junit.After;
import org.junit.Before;
import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
import org.robolectric.shadows.ShadowContentResolver;
+import java.util.UUID;
+
public class BrowserProviderHistoryVisitsTestBase {
- protected BrowserProvider provider;
- protected ContentProviderClient historyClient;
- protected ContentProviderClient visitsClient;
- protected Uri historyTestUri;
- protected Uri visitsTestUri;
+ /* package-private */ ShadowContentResolver contentResolver;
+ /* package-private */ ContentProviderClient historyClient;
+ /* package-private */ ContentProviderClient visitsClient;
+ /* package-private */ Uri historyTestUri;
+ /* package-private */ Uri visitsTestUri;
+
+ private BrowserProvider provider;
@Before
public void setUp() throws Exception {
provider = new BrowserProvider();
provider.onCreate();
ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY_URI.toString(), provider);
- final ShadowContentResolver cr = new ShadowContentResolver();
- historyClient = cr.acquireContentProviderClient(BrowserContractHelpers.HISTORY_CONTENT_URI);
- visitsClient = cr.acquireContentProviderClient(BrowserContractHelpers.VISITS_CONTENT_URI);
+ contentResolver = new ShadowContentResolver();
+ historyClient = contentResolver.acquireContentProviderClient(BrowserContractHelpers.HISTORY_CONTENT_URI);
+ visitsClient = contentResolver.acquireContentProviderClient(BrowserContractHelpers.VISITS_CONTENT_URI);
historyTestUri = testUri(BrowserContract.History.CONTENT_URI);
visitsTestUri = testUri(BrowserContract.Visits.CONTENT_URI);
}
@After
public void tearDown() {
historyClient.release();
visitsClient.release();
provider.shutdown();
}
- protected Uri testUri(Uri baseUri) {
+ /* package-private */ Uri testUri(Uri baseUri) {
return baseUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_TEST, "1").build();
}
- protected Uri insertHistoryItem(String url, String guid) throws RemoteException {
- return insertHistoryItem(url, guid, System.currentTimeMillis(), null);
+ /* package-private */ Uri insertHistoryItem(String url, String guid) throws RemoteException {
+ return insertHistoryItem(url, guid, System.currentTimeMillis(), null, null);
}
- protected Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount) throws RemoteException {
+ /* package-private */ Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount) throws RemoteException {
+ return insertHistoryItem(url, guid, System.currentTimeMillis(), null, null);
+ }
+
+ /* package-private */ Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount, String title) throws RemoteException {
ContentValues historyItem = new ContentValues();
historyItem.put(BrowserContract.History.URL, url);
if (guid != null) {
historyItem.put(BrowserContract.History.GUID, guid);
}
if (visitCount != null) {
historyItem.put(BrowserContract.History.VISITS, visitCount);
}
historyItem.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited);
+ if (title != null) {
+ historyItem.put(BrowserContract.History.TITLE, title);
+ }
return historyClient.insert(historyTestUri, historyItem);
}
}