mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 05:15:45 +00:00
Bug 1180287 - Hide client records that are likely to be duplicates or stale. r=rnewman
This commit is contained in:
parent
990cd338d8
commit
b46a958ebe
@ -8,22 +8,23 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.db.BrowserContract.Clients;
|
||||
import org.mozilla.gecko.db.BrowserContract.Tabs;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteQueryBuilder;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class TabsProvider extends SharedBrowserDatabaseProvider {
|
||||
private static final long ONE_DAY_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
|
||||
private static final long ONE_WEEK_IN_MILLISECONDS = 7 * ONE_DAY_IN_MILLISECONDS;
|
||||
private static final long THREE_WEEKS_IN_MILLISECONDS = 3 * ONE_WEEK_IN_MILLISECONDS;
|
||||
|
||||
static final String TABLE_TABS = "tabs";
|
||||
static final String TABLE_CLIENTS = "clients";
|
||||
|
||||
@ -33,6 +34,31 @@ public class TabsProvider extends SharedBrowserDatabaseProvider {
|
||||
static final int CLIENTS_ID = 603;
|
||||
static final int CLIENTS_RECENCY = 604;
|
||||
|
||||
// Exclude clients that are more than three weeks old and also any duplicates that are older than one week old.
|
||||
static final String EXCLUDE_STALE_CLIENTS_SUBQUERY =
|
||||
"(SELECT " + Clients.GUID +
|
||||
", " + Clients.NAME +
|
||||
", " + Clients.LAST_MODIFIED +
|
||||
", " + Clients.DEVICE_TYPE +
|
||||
" FROM " + TABLE_CLIENTS +
|
||||
" WHERE " + Clients.LAST_MODIFIED + " > %1$s " +
|
||||
" GROUP BY " + Clients.NAME +
|
||||
" UNION ALL " +
|
||||
" SELECT c." + Clients.GUID + " AS " + Clients.GUID +
|
||||
", c." + Clients.NAME + " AS " + Clients.NAME +
|
||||
", c." + Clients.LAST_MODIFIED + " AS " + Clients.LAST_MODIFIED +
|
||||
", c." + Clients.DEVICE_TYPE + " AS " + Clients.DEVICE_TYPE +
|
||||
" FROM " + TABLE_CLIENTS + " AS c " +
|
||||
" JOIN (" +
|
||||
" SELECT " + Clients.GUID +
|
||||
", " + "MAX( " + Clients.LAST_MODIFIED + ") AS " + Clients.LAST_MODIFIED +
|
||||
" FROM " + TABLE_CLIENTS +
|
||||
" WHERE (" + Clients.LAST_MODIFIED + " < %1$s" + " AND " + Clients.LAST_MODIFIED + " > %2$s) AND " +
|
||||
Clients.NAME + " NOT IN " + "( SELECT " + Clients.NAME + " FROM " + TABLE_CLIENTS + " WHERE " + Clients.LAST_MODIFIED + " > %1$s)" +
|
||||
" GROUP BY " + Clients.NAME +
|
||||
") AS c2" +
|
||||
" ON c." + Clients.GUID + " = c2." + Clients.GUID + ")";
|
||||
|
||||
static final String DEFAULT_TABS_SORT_ORDER = Clients.LAST_MODIFIED + " DESC, " + Tabs.LAST_USED + " DESC";
|
||||
static final String DEFAULT_CLIENTS_SORT_ORDER = Clients.LAST_MODIFIED + " DESC";
|
||||
static final String DEFAULT_CLIENTS_RECENCY_SORT_ORDER = "COALESCE(MAX(" + Tabs.LAST_USED + "), " + Clients.LAST_MODIFIED + ") DESC";
|
||||
@ -295,8 +321,15 @@ public class TabsProvider extends SharedBrowserDatabaseProvider {
|
||||
debug("Using sort order " + sortOrder + ".");
|
||||
}
|
||||
|
||||
final long oneWeekAgo = System.currentTimeMillis() - ONE_WEEK_IN_MILLISECONDS;
|
||||
final long threeWeeksAgo = System.currentTimeMillis() - THREE_WEEKS_IN_MILLISECONDS;
|
||||
|
||||
final String excludeStaleClientsTable = String.format(EXCLUDE_STALE_CLIENTS_SUBQUERY, oneWeekAgo, threeWeeksAgo);
|
||||
|
||||
qb.setProjectionMap(CLIENTS_RECENCY_PROJECTION_MAP);
|
||||
qb.setTables(TABLE_CLIENTS + " LEFT OUTER JOIN " + TABLE_TABS +
|
||||
|
||||
// Use a subquery to quietly exclude stale duplicate client records.
|
||||
qb.setTables(excludeStaleClientsTable + " AS " + TABLE_CLIENTS + " LEFT OUTER JOIN " + TABLE_TABS +
|
||||
" ON (" + projectColumn(TABLE_CLIENTS, Clients.GUID) +
|
||||
" = " + projectColumn(TABLE_TABS,Tabs.CLIENT_GUID) + ")");
|
||||
groupBy = projectColumn(TABLE_CLIENTS, Clients.GUID);
|
||||
|
@ -6,21 +6,25 @@ package org.mozilla.tests.browser.junit3;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.background.db.CursorDumper;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.LocalTabsAccessor;
|
||||
import org.mozilla.gecko.db.RemoteClient;
|
||||
import org.mozilla.gecko.db.TabsAccessor;
|
||||
import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TestRemoteTabs extends InstrumentationTestCase {
|
||||
private static final long ONE_DAY_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
|
||||
private static final long ONE_WEEK_IN_MILLISECONDS = 7 * ONE_DAY_IN_MILLISECONDS;
|
||||
private static final long THREE_WEEKS_IN_MILLISECONDS = 3 * ONE_WEEK_IN_MILLISECONDS;
|
||||
|
||||
public void testGetClientsWithoutTabsByRecencyFromCursor() throws Exception {
|
||||
final Uri uri = BrowserContractHelpers.CLIENTS_CONTENT_URI;
|
||||
final ContentResolver cr = getInstrumentation().getTargetContext().getContentResolver();
|
||||
@ -124,4 +128,89 @@ public class TestRemoteTabs extends InstrumentationTestCase {
|
||||
cpc.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetRecentRemoteClientsUpToOneWeekOld() throws Exception {
|
||||
final Uri uri = BrowserContractHelpers.CLIENTS_CONTENT_URI;
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
final String profileName = GeckoProfile.get(context).getName();
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
final ContentProviderClient cpc = cr.acquireContentProviderClient(uri);
|
||||
final LocalTabsAccessor accessor = new LocalTabsAccessor(profileName);
|
||||
|
||||
try {
|
||||
// Start Clean
|
||||
cpc.delete(uri, null, null);
|
||||
final Cursor allClients = cpc.query(uri, null, null, null, null);
|
||||
try {
|
||||
assertEquals(0, allClients.getCount());
|
||||
} finally {
|
||||
allClients.close();
|
||||
}
|
||||
|
||||
// Insert a local and remote1 client record, neither with tabs.
|
||||
final long now = System.currentTimeMillis();
|
||||
// Local client has GUID = null.
|
||||
final ContentValues local = new ContentValues();
|
||||
local.put(BrowserContract.Clients.NAME, "local");
|
||||
local.put(BrowserContract.Clients.LAST_MODIFIED, now + 1);
|
||||
// Remote clients have GUID != null.
|
||||
final ContentValues remote1 = new ContentValues();
|
||||
remote1.put(BrowserContract.Clients.GUID, "guid1");
|
||||
remote1.put(BrowserContract.Clients.NAME, "remote1");
|
||||
remote1.put(BrowserContract.Clients.LAST_MODIFIED, now + 2);
|
||||
|
||||
// Insert a Remote Client that is 6 days old.
|
||||
final ContentValues remote2 = new ContentValues();
|
||||
remote2.put(BrowserContract.Clients.GUID, "guid2");
|
||||
remote2.put(BrowserContract.Clients.NAME, "remote2");
|
||||
remote2.put(BrowserContract.Clients.LAST_MODIFIED, now - ONE_WEEK_IN_MILLISECONDS + ONE_DAY_IN_MILLISECONDS);
|
||||
|
||||
// Insert a Remote Client with the same name as previous but with more than 3 weeks old
|
||||
final ContentValues remote3 = new ContentValues();
|
||||
remote3.put(BrowserContract.Clients.GUID, "guid21");
|
||||
remote3.put(BrowserContract.Clients.NAME, "remote2");
|
||||
remote3.put(BrowserContract.Clients.LAST_MODIFIED, now - THREE_WEEKS_IN_MILLISECONDS - ONE_DAY_IN_MILLISECONDS);
|
||||
|
||||
// Insert another remote client with the same name as previous but with 3 weeks - 1 day old.
|
||||
final ContentValues remote4 = new ContentValues();
|
||||
remote4.put(BrowserContract.Clients.GUID, "guid22");
|
||||
remote4.put(BrowserContract.Clients.NAME, "remote2");
|
||||
remote4.put(BrowserContract.Clients.LAST_MODIFIED, now - THREE_WEEKS_IN_MILLISECONDS + ONE_DAY_IN_MILLISECONDS);
|
||||
|
||||
// Insert a Remote Client that is exactly one week old.
|
||||
final ContentValues remote5 = new ContentValues();
|
||||
remote5.put(BrowserContract.Clients.GUID, "guid3");
|
||||
remote5.put(BrowserContract.Clients.NAME, "remote3");
|
||||
remote5.put(BrowserContract.Clients.LAST_MODIFIED, now - ONE_WEEK_IN_MILLISECONDS);
|
||||
|
||||
ContentValues[] values = new ContentValues[]{local, remote1, remote2, remote3, remote4, remote5};
|
||||
int inserted = cpc.bulkInsert(uri, values);
|
||||
assertEquals(values.length, inserted);
|
||||
|
||||
final Cursor remoteClients =
|
||||
accessor.getRemoteClientsByRecencyCursor(context);
|
||||
|
||||
try {
|
||||
CursorDumper.dumpCursor(remoteClients);
|
||||
// Local client is not included.
|
||||
// (remote1, guid1), (remote2, guid2), (remote3, guid3) are expected.
|
||||
assertEquals(3, remoteClients.getCount());
|
||||
|
||||
// Check the inner data, according to recency.
|
||||
List<RemoteClient> recentRemoteClientsList =
|
||||
accessor.getClientsWithoutTabsByRecencyFromCursor(remoteClients);
|
||||
assertEquals(3, recentRemoteClientsList.size());
|
||||
assertEquals("remote1", recentRemoteClientsList.get(0).name);
|
||||
assertEquals("guid1", recentRemoteClientsList.get(0).guid);
|
||||
assertEquals("remote2", recentRemoteClientsList.get(1).name);
|
||||
assertEquals("guid2", recentRemoteClientsList.get(1).guid);
|
||||
assertEquals("remote3", recentRemoteClientsList.get(2).name);
|
||||
assertEquals("guid3", recentRemoteClientsList.get(2).guid);
|
||||
} finally {
|
||||
remoteClients.close();
|
||||
}
|
||||
} finally {
|
||||
cpc.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user