Bug 1274029 - Part 5: Unit tests for aggregate updates r=sebastian
authorGrigory Kruglov <gkruglov@mozilla.com>
Wed, 01 Jun 2016 10:21:14 -0700
changeset 338901 4ecfc31fd9bddd906532482338273b752a37cf12
parent 338900 ea45ad32acf03ea698f60f9c9346e9ce5b43e183
child 338902 9575e608cabe6f7ed7cf73475558ddbe9938bf9b
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssebastian
bugs1274029
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1274029 - Part 5: Unit tests for aggregate updates r=sebastian MozReview-Commit-ID: 9EljLhpySAj
mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryVisitsTestBase.java
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserProviderHistoryTest.java
@@ -136,32 +136,174 @@ public class BrowserProviderHistoryTest 
         /**
          * Normal expiration should leave 15 thumbnails
          * See {@link BrowserProvider.DEFAULT_EXPIRY_THUMBNAIL_COUNT}
          */
         assertRowCount(thumbnailClient, thumbnailTestUri, 15);
     }
 
     /**
+     * Test that we update aggregates at the appropriate times. Local visit aggregates are only updated
+     * when updating history record with PARAM_INCREMENT_VISITS=true. Remote aggregate values are updated
+     * only if set directly. Aggregate values are not set when inserting a new history record via insertHistory.
+     * Local aggregate values are set when inserting a new history record via update.
+     * @throws Exception
+     */
+    @Test
+    public void testHistoryVisitAggregates() throws Exception {
+        final long baseDate = System.currentTimeMillis();
+        final String url = "https://www.mozilla.org";
+        final Uri historyIncrementVisitsUri = historyTestUri.buildUpon()
+                .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true")
+                .appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
+
+        // Test default values
+        insertHistoryItem(url, null, baseDate, null);
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                0, 0, 0, 0, 0);
+
+        // Test setting visit count on new history item creation
+        final String url2 = "https://www.eff.org";
+        insertHistoryItem(url2, null, baseDate, 17);
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url2},
+                17, 0, 0, 0, 0);
+
+        // Test setting visit count on new history item creation via .update
+        final String url3 = "https://www.torproject.org";
+        final ContentValues cv = new ContentValues();
+        cv.put(BrowserContract.History.URL, url3);
+        cv.put(BrowserContract.History.VISITS, 13);
+        cv.put(BrowserContract.History.DATE_LAST_VISITED, baseDate);
+        historyClient.update(historyIncrementVisitsUri, cv, BrowserContract.History.URL + " = ?", new String[] {url3});
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url3},
+                13, 13, baseDate, 0, 0);
+
+        // Test that updating meta doesn't touch aggregates
+        cv.clear();
+        cv.put(BrowserContract.History.TITLE, "New title");
+        historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                0, 0, 0, 0, 0);
+
+        // Test that incrementing visits without specifying visit count updates local aggregate values
+        final long lastVisited = System.currentTimeMillis();
+        cv.clear();
+        cv.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited);
+        historyClient.update(historyIncrementVisitsUri,
+                cv, BrowserContract.History.URL + " = ?", new String[] {url});
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                1, 1, lastVisited, 0, 0);
+
+        // Test that incrementing visits by a specified visit count updates local aggregate values
+        // We don't support bumping visit count by more than 1. This doesn't make sense when we keep
+        // detailed information about our individual visits.
+        final long lastVisited2 = System.currentTimeMillis();
+        cv.clear();
+        cv.put(BrowserContract.History.DATE_LAST_VISITED, lastVisited2);
+        cv.put(BrowserContract.History.VISITS, 10);
+        historyClient.update(
+                historyTestUri.buildUpon()
+                        .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build(),
+                cv, BrowserContract.History.URL + " = ?", new String[] {url});
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                2, 2, lastVisited2, 0, 0);
+
+        // Test that we can directly update aggregate values
+        // NB: visits is unchanged (2)
+        final long lastVisited3 = System.currentTimeMillis();
+        cv.clear();
+        cv.put(BrowserContract.History.LOCAL_DATE_LAST_VISITED, lastVisited3);
+        cv.put(BrowserContract.History.LOCAL_VISITS, 19);
+        cv.put(BrowserContract.History.REMOTE_DATE_LAST_VISITED, lastVisited3 - 100);
+        cv.put(BrowserContract.History.REMOTE_VISITS, 3);
+        historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                2, 19, lastVisited3, 3, lastVisited3 - 100);
+
+        // Test that we can set remote aggregate count to a specific value
+        cv.clear();
+        cv.put(BrowserContract.History.REMOTE_VISITS, 5);
+        historyClient.update(historyTestUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                2, 19, lastVisited3, 5, lastVisited3 - 100);
+
+        // Test that we can increment remote aggregate value by setting a query param in the URI
+        final Uri historyIncrementRemoteAggregateUri = historyTestUri.buildUpon()
+                .appendQueryParameter(BrowserContract.PARAM_INCREMENT_REMOTE_AGGREGATES, "true")
+                .build();
+        cv.clear();
+        cv.put(BrowserContract.History.REMOTE_DATE_LAST_VISITED, lastVisited3);
+        cv.put(BrowserContract.History.REMOTE_VISITS, 3);
+        historyClient.update(historyIncrementRemoteAggregateUri, cv, BrowserContract.History.URL + " = ?", new String[] {url});
+        // NB: remoteVisits=8. Previous value was 5, and we're incrementing by 3.
+        assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                2, 19, lastVisited3, 8, lastVisited3);
+
+        // Test that we throw when trying to increment REMOTE_VISITS without passing in "increment by" value
+        cv.clear();
+        try {
+            historyClient.update(historyIncrementRemoteAggregateUri, cv, BrowserContract.History.URL + " = ?", new String[]{url});
+            assertTrue("Expected to throw IllegalArgumentException", false);
+        } catch (IllegalArgumentException e) {
+            assertTrue(true);
+
+            // NB: same values as above, to ensure throwing update didn't actually change anything.
+            assertHistoryAggregates(BrowserContract.History.URL + " = ?", new String[] {url},
+                    2, 19, lastVisited3, 8, lastVisited3);
+        }
+    }
+
+    private void assertHistoryAggregates(String selection, String[] selectionArg, int visits, int localVisits, long localLastVisited, int remoteVisits, long remoteLastVisited) throws Exception {
+        final Cursor c = historyClient.query(historyTestUri, new String[] {
+                BrowserContract.History.VISITS,
+                BrowserContract.History.LOCAL_VISITS,
+                BrowserContract.History.REMOTE_VISITS,
+                BrowserContract.History.LOCAL_DATE_LAST_VISITED,
+                BrowserContract.History.REMOTE_DATE_LAST_VISITED
+        }, selection, selectionArg, null);
+
+        assertNotNull(c);
+        try {
+            assertTrue(c.moveToFirst());
+
+            final int visitsCol = c.getColumnIndexOrThrow(BrowserContract.History.VISITS);
+            final int localVisitsCol = c.getColumnIndexOrThrow(BrowserContract.History.LOCAL_VISITS);
+            final int remoteVisitsCol = c.getColumnIndexOrThrow(BrowserContract.History.REMOTE_VISITS);
+            final int localDateLastVisitedCol = c.getColumnIndexOrThrow(BrowserContract.History.LOCAL_DATE_LAST_VISITED);
+            final int remoteDateLastVisitedCol = c.getColumnIndexOrThrow(BrowserContract.History.REMOTE_DATE_LAST_VISITED);
+
+            assertEquals(visits, c.getInt(visitsCol));
+
+            assertEquals(localVisits, c.getInt(localVisitsCol));
+            assertEquals(localLastVisited, c.getLong(localDateLastVisitedCol));
+
+            assertEquals(remoteVisits, c.getInt(remoteVisitsCol));
+            assertEquals(remoteLastVisited, c.getLong(remoteDateLastVisitedCol));
+        } finally {
+            c.close();
+        }
+    }
+
+    /**
      * Insert <code>count</code> history records with thumbnails, and for a third of records insert a visit.
      * Inserting visits only for some of the history records is in order to ensure we're correctly JOIN-ing
      * History and Visits tables in the Combined view.
      * Will ensure that date_created and date_modified for new records are the same as last visited date.
      *
      * @param count number of history records to insert
      * @param baseTime timestamp which will be used as a basis for last visited date
      * @throws RemoteException
      */
     private void insertHistory(int count, long baseTime) throws RemoteException {
         Uri incrementUri = historyTestUri.buildUpon()
                 .appendQueryParameter(BrowserContract.PARAM_INCREMENT_VISITS, "true").build();
 
         for (int i = 0; i < count; i++) {
             final String url = "https://www.mozilla" + i + ".org";
-            insertHistoryItem(url, "testGUID" + i, baseTime - i);
+            insertHistoryItem(url, "testGUID" + i, baseTime - i, null);
             if (i % 3 == 0) {
                 assertEquals(1, historyClient.update(incrementUri, new ContentValues(), BrowserContract.History.URL + " = ?", new String[]{url}));
             }
 
             // inserting a new entry sets the date created and modified automatically, so let's reset them
             ContentValues cv = new ContentValues();
             cv.put(BrowserContract.History.DATE_CREATED, baseTime - i);
             cv.put(BrowserContract.History.DATE_MODIFIED, baseTime - i);
--- 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
@@ -41,20 +41,25 @@ public class BrowserProviderHistoryVisit
         provider.shutdown();
     }
 
     protected 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());
+        return insertHistoryItem(url, guid, System.currentTimeMillis(), null);
     }
 
-    protected Uri insertHistoryItem(String url, String guid, Long lastVisited) throws RemoteException {
+    protected Uri insertHistoryItem(String url, String guid, Long lastVisited, Integer visitCount) throws RemoteException {
         ContentValues historyItem = new ContentValues();
         historyItem.put(BrowserContract.History.URL, url);
-        historyItem.put(BrowserContract.History.GUID, guid);
+        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);
 
         return historyClient.insert(historyTestUri, historyItem);
     }
 }