Support making a "snapshot" of databases during tests.
- We normally use in-memory DBs in unit tests because that's faster.
Add a flag to switch to file-based DBs so we can copy them.
- Also cleaned up the getDatabaseHelper() methods -- we had two,
one with no arguments and the other without, and it wasn't clear
which ones should be used when. Now the one that takes a context
is renamed to make it clear the distinction.
Test: run-all-tests.sh with and without the flag set.
Change-Id: I376674a94e35a3314d91813debbeee5b3814f4a9
diff --git a/src/com/android/providers/contacts/AbstractContactsProvider.java b/src/com/android/providers/contacts/AbstractContactsProvider.java
index 0e67d10..1bc59e7 100644
--- a/src/com/android/providers/contacts/AbstractContactsProvider.java
+++ b/src/com/android/providers/contacts/AbstractContactsProvider.java
@@ -84,7 +84,7 @@
/**
* The DB helper to use for this content provider.
*/
- private SQLiteOpenHelper mDbHelper;
+ private ContactsDatabaseHelper mDbHelper;
/**
* The database helper to serialize all transactions on. If non-null, any new transaction
@@ -133,12 +133,12 @@
@Override
public boolean onCreate() {
Context context = getContext();
- mDbHelper = getDatabaseHelper(context);
+ mDbHelper = newDatabaseHelper(context);
mTransactionHolder = getTransactionHolder();
return true;
}
- public SQLiteOpenHelper getDatabaseHelper() {
+ public ContactsDatabaseHelper getDatabaseHelper() {
return mDbHelper;
}
@@ -345,8 +345,9 @@
/**
* Gets the database helper for this contacts provider. This is called once, during onCreate().
+ * Do not call in other places.
*/
- protected abstract SQLiteOpenHelper getDatabaseHelper(Context context);
+ protected abstract ContactsDatabaseHelper newDatabaseHelper(Context context);
/**
* Gets the thread-local transaction holder to use for keeping track of the transaction. This
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 394a085..83f6195 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -1032,8 +1032,8 @@
* Returns a new instance for unit tests.
*/
@NeededForTesting
- public static ContactsDatabaseHelper getNewInstanceForTest(Context context) {
- return new ContactsDatabaseHelper(context, null, false, /* isTestInstance=*/ true);
+ public static ContactsDatabaseHelper getNewInstanceForTest(Context context, String filename) {
+ return new ContactsDatabaseHelper(context, filename, false, /* isTestInstance=*/ true);
}
protected ContactsDatabaseHelper(
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 0000570..583bedc 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -1582,7 +1582,7 @@
mMetadataSyncEnabled = android.provider.Settings.Global.getInt(
getContext().getContentResolver(), Global.CONTACT_METADATA_SYNC_ENABLED, 0) == 1;
- mContactsHelper = getDatabaseHelper(getContext());
+ mContactsHelper = getDatabaseHelper();
mDbHelper.set(mContactsHelper);
// Set up the DB helper for keeping transactions serialized.
@@ -1611,7 +1611,7 @@
ProviderInfo profileInfo = new ProviderInfo();
profileInfo.authority = ContactsContract.AUTHORITY;
mProfileProvider.attachInfo(getContext(), profileInfo);
- mProfileHelper = mProfileProvider.getDatabaseHelper(getContext());
+ mProfileHelper = mProfileProvider.getDatabaseHelper();
mEnterprisePolicyGuard = new EnterprisePolicyGuard(getContext());
// Initialize the pre-authorized URI duration.
@@ -2060,7 +2060,7 @@
}
@Override
- public ContactsDatabaseHelper getDatabaseHelper(final Context context) {
+ public ContactsDatabaseHelper newDatabaseHelper(final Context context) {
return ContactsDatabaseHelper.getInstance(context);
}
diff --git a/src/com/android/providers/contacts/ProfileDatabaseHelper.java b/src/com/android/providers/contacts/ProfileDatabaseHelper.java
index 5628091..4d605f2 100644
--- a/src/com/android/providers/contacts/ProfileDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ProfileDatabaseHelper.java
@@ -42,8 +42,8 @@
* Returns a new instance for unit tests.
*/
@NeededForTesting
- public static ProfileDatabaseHelper getNewInstanceForTest(Context context) {
- return new ProfileDatabaseHelper(context, null, false, /* isTestInstance=*/ true);
+ public static ProfileDatabaseHelper getNewInstanceForTest(Context context, String filename) {
+ return new ProfileDatabaseHelper(context, filename, false, /* isTestInstance=*/ true);
}
private ProfileDatabaseHelper(
diff --git a/src/com/android/providers/contacts/ProfileProvider.java b/src/com/android/providers/contacts/ProfileProvider.java
index 88ae4c3..73d1215 100644
--- a/src/com/android/providers/contacts/ProfileProvider.java
+++ b/src/com/android/providers/contacts/ProfileProvider.java
@@ -48,10 +48,14 @@
}
@Override
- protected ProfileDatabaseHelper getDatabaseHelper(Context context) {
+ protected ProfileDatabaseHelper newDatabaseHelper(Context context) {
return ProfileDatabaseHelper.getInstance(context);
}
+ public ProfileDatabaseHelper getDatabaseHelper() {
+ return (ProfileDatabaseHelper) super.getDatabaseHelper();
+ }
+
@Override
protected ThreadLocal<ContactsTransaction> getTransactionHolder() {
return mDelegate.getTransactionHolder();
diff --git a/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java b/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java
index 1d0d24a..3d8b8eb 100644
--- a/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java
+++ b/tests/src/com/android/providers/contacts/ContactMetadataProviderTest.java
@@ -103,7 +103,7 @@
// Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
// are using different dbHelpers.
mContactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
- mActor.provider).getDatabaseHelper(getContext()));
+ mActor.provider).getDatabaseHelper());
setupData();
}
diff --git a/tests/src/com/android/providers/contacts/ContactsActor.java b/tests/src/com/android/providers/contacts/ContactsActor.java
index d8c0a09..6927bf2 100644
--- a/tests/src/com/android/providers/contacts/ContactsActor.java
+++ b/tests/src/com/android/providers/contacts/ContactsActor.java
@@ -58,7 +58,6 @@
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.StatusUpdates;
import android.test.IsolatedContext;
-import android.test.RenamingDelegatingContext;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
@@ -370,7 +369,11 @@
public <T extends ContentProvider> T addProvider(Class<T> providerClass,
String authority, Context providerContext) throws Exception {
- T provider = providerClass.newInstance();
+ return addProvider(providerClass.newInstance(), authority, providerContext);
+ }
+
+ public <T extends ContentProvider> T addProvider(T provider,
+ String authority, Context providerContext) throws Exception {
ProviderInfo info = new ProviderInfo();
// Here, authority can have "user-id@". We want to use it for addProvider, but provider
diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
index 10cd2fb..be3a73b 100644
--- a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperTest.java
@@ -41,7 +41,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mDbHelper = getContactsProvider().getDatabaseHelper(getContext());
+ mDbHelper = getContactsProvider().getDatabaseHelper();
mDb = mDbHelper.getWritableDatabase();
}
diff --git a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
index 4db79f2..d543b7e 100644
--- a/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
+++ b/tests/src/com/android/providers/contacts/ContactsDatabaseHelperUpgradeTest.java
@@ -59,6 +59,7 @@
import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
+import com.android.providers.contacts.testutil.TestUtil;
import com.android.providers.contacts.util.PropertyUtils;
import junit.framework.AssertionFailedError;
@@ -89,7 +90,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mHelper = ContactsDatabaseHelper.getNewInstanceForTest(getContext());
+ mHelper = ContactsDatabaseHelper.getNewInstanceForTest(getContext(),
+ TestUtils.getContactsDatabaseFilename(getContext()));
mHelper.onConfigure(mDb);
}
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index a053974..f951f6d 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -1173,7 +1173,7 @@
Uri dataUri = mResolver.insert(Data.CONTENT_URI, values);
final ContactsProvider2 cp = (ContactsProvider2) getProvider();
- final ContactsDatabaseHelper helper = cp.getDatabaseHelper(mContext);
+ final ContactsDatabaseHelper helper = cp.getDatabaseHelper();
String data1 = values.getAsString(Data.DATA1);
String data2 = values.getAsString(Data.DATA2);
String combineString = data1+data2;
@@ -1234,7 +1234,7 @@
// Check for photo data's hashId is correct or not.
final ContactsProvider2 cp = (ContactsProvider2) getProvider();
- final ContactsDatabaseHelper helper = cp.getDatabaseHelper(mContext);
+ final ContactsDatabaseHelper helper = cp.getDatabaseHelper();
String hashId = helper.getPhotoHashId();
assertStoredValue(dataUri, Data.HASH_ID, hashId);
@@ -2067,10 +2067,11 @@
// Note here we use a standalone CP2 so it'll have its own db helper.
// Also use AlteringUserContext here to report the corp user id.
+ final int userId = MockUserManager.CORP_USER.id;
SynchronousContactsProvider2 provider = mActor.addProvider(
- StandaloneContactsProvider2.class,
- "" + MockUserManager.CORP_USER.id + "@com.android.contacts",
- new AlteringUserContext(mActor.getProviderContext(), MockUserManager.CORP_USER.id));
+ new SecondaryUserContactsProvider2(userId),
+ "" + userId + "@com.android.contacts",
+ new AlteringUserContext(mActor.getProviderContext(), userId));
provider.wipeData();
return provider;
}
@@ -3046,7 +3047,7 @@
// Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
// are using different dbHelpers.
contactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
- mActor.provider).getDatabaseHelper(getContext()));
+ mActor.provider).getDatabaseHelper());
// Create an account first.
String backupId = "backupId001";
String accountType = "accountType";
@@ -3102,7 +3103,7 @@
// Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
// are using different dbHelpers.
contactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
- mActor.provider).getDatabaseHelper(getContext()));
+ mActor.provider).getDatabaseHelper());
// Create an account first.
String backupId = "backupId001";
String accountType = "accountType";
@@ -3168,7 +3169,7 @@
// Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
// are using different dbHelpers.
contactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
- mActor.provider).getDatabaseHelper(getContext()));
+ mActor.provider).getDatabaseHelper());
// Enable metadataSync flag.
final ContactsProvider2 cp = (ContactsProvider2) getProvider();
cp.setMetadataSyncForTest(true);
@@ -6792,7 +6793,7 @@
// Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
// are using different dbHelpers.
contactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
- mActor.provider).getDatabaseHelper(getContext()));
+ mActor.provider).getDatabaseHelper());
// Create a doomed metadata.
String backupId = "backupIdForDoomed";
diff --git a/tests/src/com/android/providers/contacts/PhotoStoreTest.java b/tests/src/com/android/providers/contacts/PhotoStoreTest.java
index 4e797f7..8ba0438 100644
--- a/tests/src/com/android/providers/contacts/PhotoStoreTest.java
+++ b/tests/src/com/android/providers/contacts/PhotoStoreTest.java
@@ -56,7 +56,7 @@
mProvider = ((SynchronousContactsProvider2) mActor.provider);
mPhotoStore = mProvider.getPhotoStore();
mProvider.wipeData();
- mDb = mProvider.getDatabaseHelper(getContext()).getReadableDatabase();
+ mDb = mProvider.getDatabaseHelper().getReadableDatabase();
}
@Override
diff --git a/tests/src/com/android/providers/contacts/RenamingDelegatingContext.java b/tests/src/com/android/providers/contacts/RenamingDelegatingContext.java
new file mode 100644
index 0000000..260b730
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/RenamingDelegatingContext.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.contacts;
+
+import android.content.ContentProvider;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.FileUtils;
+import android.util.Log;
+
+import com.google.android.collect.Sets;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.util.Set;
+
+/**
+ * This file was copied from framework/base. The DB related file names now understand fullpath
+ * filenames and will not append the prefix for them.
+ */
+public class RenamingDelegatingContext extends ContextWrapper {
+
+ private Context mFileContext;
+ private String mFilePrefix = null;
+ private File mCacheDir;
+ private final Object mSync = new Object();
+
+ private Set<String> mDatabaseNames = Sets.newHashSet();
+ private Set<String> mFileNames = Sets.newHashSet();
+
+ public static <T extends ContentProvider> T providerWithRenamedContext(
+ Class<T> contentProvider, Context c, String filePrefix)
+ throws IllegalAccessException, InstantiationException {
+ return providerWithRenamedContext(contentProvider, c, filePrefix, false);
+ }
+
+ public static <T extends ContentProvider> T providerWithRenamedContext(
+ Class<T> contentProvider, Context c, String filePrefix,
+ boolean allowAccessToExistingFilesAndDbs)
+ throws IllegalAccessException, InstantiationException {
+ Class<T> mProviderClass = contentProvider;
+ T mProvider = mProviderClass.newInstance();
+ RenamingDelegatingContext mContext = new RenamingDelegatingContext(c, filePrefix);
+ if (allowAccessToExistingFilesAndDbs) {
+ mContext.makeExistingFilesAndDbsAccessible();
+ }
+ mProvider.attachInfoForTesting(mContext, null);
+ return mProvider;
+ }
+
+ /**
+ * Makes accessible all files and databases whose names match the filePrefix that was passed to
+ * the constructor. Normally only files and databases that were created through this context are
+ * accessible.
+ */
+ public void makeExistingFilesAndDbsAccessible() {
+ String[] databaseList = mFileContext.databaseList();
+ for (String diskName : databaseList) {
+ if (shouldDiskNameBeVisible(diskName)) {
+ mDatabaseNames.add(publicNameFromDiskName(diskName));
+ }
+ }
+ String[] fileList = mFileContext.fileList();
+ for (String diskName : fileList) {
+ if (shouldDiskNameBeVisible(diskName)) {
+ mFileNames.add(publicNameFromDiskName(diskName));
+ }
+ }
+ }
+
+ /**
+ * Returns if the given diskName starts with the given prefix or not.
+ * @param diskName name of the database/file.
+ */
+ boolean shouldDiskNameBeVisible(String diskName) {
+ return diskName.startsWith(mFilePrefix);
+ }
+
+ /**
+ * Returns the public name (everything following the prefix) of the given diskName.
+ * @param diskName name of the database/file.
+ */
+ String publicNameFromDiskName(String diskName) {
+ if (!shouldDiskNameBeVisible(diskName)) {
+ throw new IllegalArgumentException("disk file should not be visible: " + diskName);
+ }
+ return diskName.substring(mFilePrefix.length(), diskName.length());
+ }
+
+ /**
+ * @param context : the context that will be delegated.
+ * @param filePrefix : a prefix with which database and file names will be
+ * prefixed.
+ */
+ public RenamingDelegatingContext(Context context, String filePrefix) {
+ super(context);
+ mFileContext = context;
+ mFilePrefix = filePrefix;
+ }
+
+ /**
+ * @param context : the context that will be delegated.
+ * @param fileContext : the context that file and db methods will be delegated to
+ * @param filePrefix : a prefix with which database and file names will be
+ * prefixed.
+ */
+ public RenamingDelegatingContext(Context context, Context fileContext, String filePrefix) {
+ super(context);
+ mFileContext = fileContext;
+ mFilePrefix = filePrefix;
+ }
+
+ public String getDatabasePrefix() {
+ return mFilePrefix;
+ }
+
+ private String renamedFileName(String name) {
+ return mFilePrefix + name;
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name,
+ int mode, SQLiteDatabase.CursorFactory factory) {
+ if (name.startsWith("/")) {
+ return mFileContext.openOrCreateDatabase(name, mode, factory);
+ }
+ final String internalName = renamedFileName(name);
+ if (!mDatabaseNames.contains(name)) {
+ mDatabaseNames.add(name);
+ mFileContext.deleteDatabase(internalName);
+ }
+ return mFileContext.openOrCreateDatabase(internalName, mode, factory);
+ }
+
+ @Override
+ public SQLiteDatabase openOrCreateDatabase(String name,
+ int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
+ if (name.startsWith("/")) {
+ return mFileContext.openOrCreateDatabase(name, mode, factory, errorHandler);
+ }
+ final String internalName = renamedFileName(name);
+ if (!mDatabaseNames.contains(name)) {
+ mDatabaseNames.add(name);
+ mFileContext.deleteDatabase(internalName);
+ }
+ return mFileContext.openOrCreateDatabase(internalName, mode, factory, errorHandler);
+ }
+
+ @Override
+ public boolean deleteDatabase(String name) {
+ if (name.startsWith("/")) {
+ return mFileContext.deleteDatabase(name);
+ }
+ if (mDatabaseNames.contains(name)) {
+ mDatabaseNames.remove(name);
+ return mFileContext.deleteDatabase(renamedFileName(name));
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public File getDatabasePath(String name) {
+ if (name.startsWith("/")) {
+ return mFileContext.getDatabasePath(name);
+ }
+ return mFileContext.getDatabasePath(renamedFileName(name));
+ }
+
+ @Override
+ public String[] databaseList() {
+ return mDatabaseNames.toArray(new String[]{});
+ }
+
+ @Override
+ public FileInputStream openFileInput(String name)
+ throws FileNotFoundException {
+ final String internalName = renamedFileName(name);
+ if (mFileNames.contains(name)) {
+ return mFileContext.openFileInput(internalName);
+ } else {
+ throw new FileNotFoundException(internalName);
+ }
+ }
+
+ @Override
+ public FileOutputStream openFileOutput(String name, int mode)
+ throws FileNotFoundException {
+ mFileNames.add(name);
+ return mFileContext.openFileOutput(renamedFileName(name), mode);
+ }
+
+ @Override
+ public File getFileStreamPath(String name) {
+ return mFileContext.getFileStreamPath(renamedFileName(name));
+ }
+
+ @Override
+ public boolean deleteFile(String name) {
+ if (mFileNames.contains(name)) {
+ mFileNames.remove(name);
+ return mFileContext.deleteFile(renamedFileName(name));
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String[] fileList() {
+ return mFileNames.toArray(new String[]{});
+ }
+
+ /**
+ * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
+ * one) and return it instead. This code is basically getCacheDir(), except it uses the real
+ * cache dir as the parent directory and creates a test cache dir inside that.
+ */
+ @Override
+ public File getCacheDir() {
+ synchronized (mSync) {
+ if (mCacheDir == null) {
+ mCacheDir = new File(mFileContext.getCacheDir(), renamedFileName("cache"));
+ }
+ if (!mCacheDir.exists()) {
+ if(!mCacheDir.mkdirs()) {
+ Log.w("RenamingDelegatingContext", "Unable to create cache directory");
+ return null;
+ }
+ FileUtils.setPermissions(
+ mCacheDir.getPath(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
+ -1, -1);
+ }
+ }
+ return mCacheDir;
+ }
+}
diff --git a/tests/src/com/android/providers/contacts/SecondaryUserContactsProvider2.java b/tests/src/com/android/providers/contacts/SecondaryUserContactsProvider2.java
new file mode 100644
index 0000000..61ae1ca
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/SecondaryUserContactsProvider2.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.providers.contacts;
+
+import android.content.Context;
+
+/**
+ * A subclass of {@link SynchronousContactsProvider2} that uses a different DB for secondary users.
+ */
+public class SecondaryUserContactsProvider2 extends SynchronousContactsProvider2 {
+ private final String mDbSuffix;
+ private ContactsDatabaseHelper mDbHelper;
+
+ public SecondaryUserContactsProvider2(int userId) {
+ mDbSuffix = "-u" + userId;
+ }
+
+ @Override
+ public ContactsDatabaseHelper newDatabaseHelper(final Context context) {
+ if (mDbHelper == null) {
+ mDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context,
+ TestUtils.getContactsDatabaseFilename(context, mDbSuffix));
+ }
+ return mDbHelper;
+ }
+}
diff --git a/tests/src/com/android/providers/contacts/StandaloneContactsProvider2.java b/tests/src/com/android/providers/contacts/StandaloneContactsProvider2.java
deleted file mode 100644
index 8dd09bf..0000000
--- a/tests/src/com/android/providers/contacts/StandaloneContactsProvider2.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.providers.contacts;
-
-import android.content.Context;
-
-/**
- * A subclass of {@link SynchronousContactsProvider2} that doesn't reuse the database helper.
- */
-public class StandaloneContactsProvider2 extends SynchronousContactsProvider2 {
- private static ContactsDatabaseHelper mDbHelper;
-
- public StandaloneContactsProvider2() {
- // No need to wipe data for this instance since it doesn't reuse the db helper.
- setDataWipeEnabled(false);
- }
-
- @Override
- public ContactsDatabaseHelper getDatabaseHelper(final Context context) {
- if (mDbHelper == null) {
- mDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context);
- }
- return mDbHelper;
- }
-
- @Override
- public void setDataWipeEnabled(boolean flag) {
- // No need to wipe data for this instance since it doesn't reuse the db helper.
- super.setDataWipeEnabled(false);
- }
-}
diff --git a/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java b/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java
index 19878f8..c96c5b2 100644
--- a/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java
+++ b/tests/src/com/android/providers/contacts/SynchronousContactsProvider2.java
@@ -34,7 +34,6 @@
private static Boolean sDataWiped = false;
private static ContactsDatabaseHelper sDbHelper;
- private boolean mDataWipeEnabled = true;
private Account mAccount;
private boolean mNetworkNotified;
private boolean mMetadataNetworkNotified;
@@ -42,9 +41,10 @@
private boolean mIsVoiceCapable = true;
@Override
- public ContactsDatabaseHelper getDatabaseHelper(final Context context) {
+ public ContactsDatabaseHelper newDatabaseHelper(final Context context) {
if (sDbHelper == null) {
- sDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context);
+ sDbHelper = ContactsDatabaseHelper.getNewInstanceForTest(context,
+ TestUtils.getContactsDatabaseFilename(getContext()));
}
return sDbHelper;
}
@@ -54,10 +54,6 @@
return new SynchronousProfileProvider(this);
}
- public void setDataWipeEnabled(boolean flag) {
- mDataWipeEnabled = flag;
- }
-
@Override
public void onBegin() {
super.onBegin();
@@ -100,12 +96,10 @@
@Override
public boolean onCreate() {
boolean created = super.onCreate();
- if (mDataWipeEnabled) {
- synchronized (sDataWiped) {
- if (!sDataWiped) {
- sDataWiped = true;
- wipeData();
- }
+ synchronized (sDataWiped) {
+ if (!sDataWiped) {
+ sDataWiped = true;
+ wipeData();
}
}
return created;
@@ -192,7 +186,7 @@
}
public void prepareForFullAggregation(int maxContact) {
- SQLiteDatabase db = getDatabaseHelper(getContext()).getWritableDatabase();
+ SQLiteDatabase db = getDatabaseHelper().getWritableDatabase();
db.execSQL("UPDATE raw_contacts SET aggregation_mode=0,aggregation_needed=1;");
long rowId =
db.compileStatement("SELECT _id FROM raw_contacts LIMIT 1 OFFSET " + maxContact)
@@ -201,12 +195,12 @@
}
public long getRawContactCount() {
- SQLiteDatabase db = getDatabaseHelper(getContext()).getReadableDatabase();
+ SQLiteDatabase db = getDatabaseHelper().getReadableDatabase();
return db.compileStatement("SELECT COUNT(*) FROM raw_contacts").simpleQueryForLong();
}
public long getContactCount() {
- SQLiteDatabase db = getDatabaseHelper(getContext()).getReadableDatabase();
+ SQLiteDatabase db = getDatabaseHelper().getReadableDatabase();
return db.compileStatement("SELECT COUNT(*) FROM contacts").simpleQueryForLong();
}
@@ -214,7 +208,7 @@
public void wipeData() {
Log.i(TAG, "wipeData");
super.wipeData();
- SQLiteDatabase db = getDatabaseHelper(getContext()).getWritableDatabase();
+ SQLiteDatabase db = getDatabaseHelper().getWritableDatabase();
db.execSQL("replace into SQLITE_SEQUENCE (name,seq) values('raw_contacts', 42)");
db.execSQL("replace into SQLITE_SEQUENCE (name,seq) values('contacts', 2009)");
db.execSQL("replace into SQLITE_SEQUENCE (name,seq) values('data', 777)");
diff --git a/tests/src/com/android/providers/contacts/SynchronousProfileProvider.java b/tests/src/com/android/providers/contacts/SynchronousProfileProvider.java
index 308e67a..79356a5 100644
--- a/tests/src/com/android/providers/contacts/SynchronousProfileProvider.java
+++ b/tests/src/com/android/providers/contacts/SynchronousProfileProvider.java
@@ -32,9 +32,10 @@
}
@Override
- protected ProfileDatabaseHelper getDatabaseHelper(final Context context) {
+ protected ProfileDatabaseHelper newDatabaseHelper(final Context context) {
if (sDbHelper == null) {
- sDbHelper = ProfileDatabaseHelper.getNewInstanceForTest(context);
+ sDbHelper = ProfileDatabaseHelper.getNewInstanceForTest(context,
+ TestUtils.getProfileDatabaseFilename(getContext()));
}
return sDbHelper;
}
diff --git a/tests/src/com/android/providers/contacts/TestUtils.java b/tests/src/com/android/providers/contacts/TestUtils.java
index b6d6a27..5e88548 100644
--- a/tests/src/com/android/providers/contacts/TestUtils.java
+++ b/tests/src/com/android/providers/contacts/TestUtils.java
@@ -19,6 +19,8 @@
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.os.FileUtils;
+import android.support.annotation.Nullable;
import android.util.Log;
import junit.framework.Assert;
@@ -28,9 +30,89 @@
import java.io.IOException;
public class TestUtils {
+ private static final String TAG = "ContactsTestUtils";
+
private TestUtils() {
}
+ /**
+ * We normally use in-memory DBs in unit tests, because that's faster, but it's impossible to
+ * look at intermediate databases when something is failing. When this flag is set to true,
+ * we'll switch to file-based DBs, so we can call {@link #createDatabaseSnapshot}
+ * , pull the snapshot DBs and take a look at them.
+ */
+ public static final boolean ENABLE_DATABASE_SNAPSHOT = false; // DO NOT SUBMIT WITH TRUE.
+
+ private static final Object sDatabasePathLock = new Object();
+ private static File sDatabasePath = null;
+
+ private static String getDatabaseFile(Context context, @Nullable String name) {
+ if (!ENABLE_DATABASE_SNAPSHOT) {
+ return null; // Use the in-memory DB.
+ }
+ synchronized (sDatabasePathLock) {
+ if (sDatabasePath == null) {
+ final File path = new File(context.getCacheDir(), "test-db");
+ if (path.exists()) {
+ Assert.assertTrue("Unable to delete directory: " + path,
+ FileUtils.deleteContents(path));
+ } else {
+ Assert.assertTrue("Unable to create directory: " + path, path.mkdirs());
+ }
+
+ sDatabasePath = path;
+ }
+ if (name == null) {
+ return sDatabasePath.getAbsolutePath();
+ } else {
+ return new File(sDatabasePath, name).getAbsolutePath();
+ }
+ }
+ }
+
+ public static String getContactsDatabaseFilename(Context context) {
+ return getContactsDatabaseFilename(context, "");
+ }
+
+ public static String getContactsDatabaseFilename(Context context, String suffix) {
+ return getDatabaseFile(context, "contacts2" + suffix + ".db");
+ }
+
+ public static String getProfileDatabaseFilename(Context context) {
+ return getProfileDatabaseFilename(context, "");
+ }
+
+ public static String getProfileDatabaseFilename(Context context, String suffix) {
+ return getDatabaseFile(context, "profile.db" + suffix + ".db");
+ }
+
+ public static void createDatabaseSnapshot(Context context, String name) {
+ Assert.assertTrue(
+ "ENABLE_DATABASE_SNAPSHOT must be set to true to create database snapshot",
+ ENABLE_DATABASE_SNAPSHOT);
+
+ final File fromDir = new File(getDatabaseFile(context, null));
+ final File toDir = new File(context.getCacheDir(), "snapshot-" + name);
+ if (toDir.exists()) {
+ Assert.assertTrue("Unable to delete directory: " + toDir,
+ FileUtils.deleteContents(toDir));
+ } else {
+ Assert.assertTrue("Unable to create directory: " + toDir, toDir.mkdirs());
+ }
+
+ Log.w(TAG, "Copying database files into '" + toDir + "'...");
+
+ for (File file : fromDir.listFiles()) {
+ try {
+ final File to = new File(toDir, file.getName());
+ FileUtils.copyFileOrThrow(file, to);
+ Log.i(TAG, "Created: " + to);
+ } catch (IOException e) {
+ Assert.fail("Failed to copy file: " + e.toString());
+ }
+ }
+ }
+
/** Convenient method to create a ContentValues */
public static ContentValues cv(Object... namesAndValues) {
Assert.assertTrue((namesAndValues.length % 2) == 0);
diff --git a/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java b/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java
index 0ef020b..568e1e8 100644
--- a/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java
+++ b/tests/src/com/android/providers/contacts/sqlite/DatabaseAnalyzerTest.java
@@ -19,13 +19,15 @@
import android.test.AndroidTestCase;
import com.android.providers.contacts.ContactsDatabaseHelper;
+import com.android.providers.contacts.TestUtils;
import java.util.List;
public class DatabaseAnalyzerTest extends AndroidTestCase {
public void testFindTableViewsAllowingColumns() {
final ContactsDatabaseHelper dbh =
- ContactsDatabaseHelper.getNewInstanceForTest(getContext());
+ ContactsDatabaseHelper.getNewInstanceForTest(getContext(),
+ TestUtils.getContactsDatabaseFilename(getContext()));
try {
final List<String> list = DatabaseAnalyzer.findTableViewsAllowingColumns(
dbh.getReadableDatabase());