summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMarcus Hagerott <mhagerott@google.com>2016-12-20 14:12:37 -0800
committerMarcus Hagerott <mhagerott@google.com>2016-12-20 15:58:59 -0800
commit2054306415223d2f68972d8f663334c2956edd38 (patch)
tree69ae4b20e873e29e2e060df412b6f80dd3ff25a2 /tests
parent24b4613a00504bd2b6d81a7edb7261e0913f932e (diff)
downloadContacts-2054306415223d2f68972d8f663334c2956edd38.tar.gz
Unsuppress SIM import UI test
Test: ran GoogleContactsTests Change-Id: I52e286c35a7b3f95bc2d8ed469b9e4bf473f8f64
Diffstat (limited to 'tests')
-rw-r--r--tests/src/com/android/contacts/activities/SimImportActivityTest.java158
-rw-r--r--tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java206
2 files changed, 323 insertions, 41 deletions
diff --git a/tests/src/com/android/contacts/activities/SimImportActivityTest.java b/tests/src/com/android/contacts/activities/SimImportActivityTest.java
index 8362b9fac..64b86e21e 100644
--- a/tests/src/com/android/contacts/activities/SimImportActivityTest.java
+++ b/tests/src/com/android/contacts/activities/SimImportActivityTest.java
@@ -1,18 +1,37 @@
+/*
+ * Copyright (C) 2016 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.contacts.activities;
import static com.android.contacts.tests.ContactsMatchers.DataCursor.hasMimeType;
import static com.android.contacts.tests.ContactsMatchers.hasRowMatching;
import static com.android.contacts.tests.ContactsMatchers.hasValueForColumn;
-
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Instrumentation;
+import android.content.BroadcastReceiver;
+import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.os.Build;
@@ -20,47 +39,54 @@ import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
+import android.support.v4.content.LocalBroadcastManager;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContentResolver;
+import com.android.contacts.SimImportService;
import com.android.contacts.database.SimContactDao;
+import com.android.contacts.database.SimContactDaoImpl;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.SimCard;
import com.android.contacts.model.SimContact;
import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.test.mocks.ForwardingContentProvider;
+import com.android.contacts.test.mocks.MockContentProvider;
import com.android.contacts.tests.AccountsTestHelper;
import com.android.contacts.tests.ContactsMatchers;
import com.android.contacts.tests.FakeSimContactDao;
import com.android.contacts.tests.StringableCursor;
-
+import com.google.common.base.Function;
import com.google.common.base.Functions;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.TimeUnit;
+
/**
* UI Tests for {@link SimImportActivity}
*
* These should probably be converted to espresso tests because espresso does a better job of
* waiting for the app to be idle once espresso library is added
*/
-@MediumTest
+@LargeTest
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
@TargetApi(Build.VERSION_CODES.M)
public class SimImportActivityTest {
- public static final int TIMEOUT = 1000;
+ public static final int TIMEOUT = 3000;
private Context mContext;
private UiDevice mDevice;
private Instrumentation mInstrumentation;
@@ -111,7 +137,7 @@ public class SimImportActivityTest {
assertTrue(mDevice.hasObject(By.text("Sim One")));
assertTrue(mDevice.hasObject(By.text("Sim Two")));
assertTrue(mDevice.hasObject(By.text("5550103")));
-}
+ }
@Test
public void shouldHaveEmptyState() {
@@ -160,27 +186,64 @@ public class SimImportActivityTest {
assertTrue(mDevice.wait(Until.hasObject(By.textStartsWith("Name One")), TIMEOUT));
}
-
- // TODO: fix this test. This doesn't work because AccountTypeManager returns a stale account
- // list (it doesn't contain the accounts added during the current test run).
- // Could use MockAccountTypeManager but probably ought to look at improving how
- // AccountTypeManager updates it's account list.
- @Suppress
+ /**
+ * Tests a complete import flow
+ *
+ * <p>Test case outline:</p>
+ * <ul>
+ * <li>Load SIM contacts
+ * <li>Change to a specific target account
+ * <li>Deselect 3 specific SIM contacts
+ * <li>Rotate the screen to landscape
+ * <li>Rotate the screen back to portrait
+ * <li>Press the import button
+ * <li>Wait for import to complete
+ * <li>Query contacts in target account and verify that they match selected contacts
+ * <li>Start import activity again
+ * <li>Switch to target account
+ * <li>Verify that previously imported contacts are disabled and not checked
+ * </ul>
+ *
+ * <p>This mocks out the IccProvider and stubs the canReadSimContacts method to make it work on
+ * an emulator but otherwise uses real dependency.
+ * </p>
+ */
@Test
- public void selectionsAreImportedAndDisabledOnSubsequentViews() throws Exception {
+ public void selectionsAreImportedAndDisabledOnSubsequentImports() throws Exception {
// Clear out the instance so that it will have the most recent accounts when reloaded
AccountTypeManager.setInstanceForTest(null);
final AccountWithDataSet targetAccount = mAccountHelper.addTestAccount(
mAccountHelper.generateAccountName("SimImportActivity_target_"));
- mDao.addSim(someSimCard(),
- new SimContact(1, "Import One", "5550101"),
- new SimContact(2, "Skip Two", "5550102"),
- new SimContact(3, "Import Three", "5550103"),
- new SimContact(4, "Skip Four", "5550104"),
- new SimContact(5, "Skip Five", "5550105"),
- new SimContact(6, "Import Six", "5550106"));
+ final MockContentProvider iccProvider = new MockContentProvider();
+ iccProvider.expect(MockContentProvider.Query.forAnyUri())
+ .withDefaultProjection(new String[] {SimContactDaoImpl._ID, SimContactDaoImpl.NAME,
+ SimContactDaoImpl.NUMBER, SimContactDaoImpl.EMAILS })
+ .anyNumberOfTimes()
+ .returnRow(toCursorRow(new SimContact(1, "Import One", "5550101")))
+ .returnRow(toCursorRow(new SimContact(2, "Skip Two", "5550102")))
+ .returnRow(toCursorRow(new SimContact(3, "Import Three", "5550103")))
+ .returnRow(toCursorRow(new SimContact(4, "Skip Four", "5550104")))
+ .returnRow(toCursorRow(new SimContact(5, "Skip Five", "5550105")))
+ .returnRow(toCursorRow(new SimContact(6, "Import Six", "5550106")));
+ final MockContentResolver mockResolver = new MockContentResolver();
+ mockResolver.addProvider("icc", iccProvider);
+ final ContentProviderClient contactsProviderClient = mContext.getContentResolver()
+ .acquireContentProviderClient(ContactsContract.AUTHORITY);
+ mockResolver.addProvider(ContactsContract.AUTHORITY, new ForwardingContentProvider(
+ contactsProviderClient));
+
+ SimContactDao.setFactoryForTest(new Function<Context, SimContactDao>() {
+ @Override
+ public SimContactDao apply(Context input) {
+ final SimContactDaoImpl spy = spy(new SimContactDaoImpl(
+ mContext, mockResolver,
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)));
+ when(spy.canReadSimContacts()).thenReturn(true);
+ return spy;
+ }
+ });
mActivity = mInstrumentation.startActivitySync(
new Intent(mContext, SimImportActivity.class)
@@ -190,9 +253,11 @@ public class SimImportActivityTest {
mDevice.findObject(By.desc("Show more")).clickAndWait(Until.newWindow(), TIMEOUT);
mDevice.findObject(By.textStartsWith("SimImportActivity_target_")).click();
- mDevice.waitForIdle();
+
+ assertTrue(mDevice.wait(Until.hasObject(By.text("Skip Two")), TIMEOUT));
mDevice.findObject(By.text("Skip Two")).click();
+ mDevice.findObject(By.text("Skip Four")).click();
mDevice.findObject(By.text("Skip Five")).click();
mDevice.waitForIdle();
@@ -204,8 +269,12 @@ public class SimImportActivityTest {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
mDevice.wait(Until.hasObject(By.text("Import One")), TIMEOUT);
+ ListenableFuture<?> nextImportFuture = nextImportCompleteBroadcast();
+
mDevice.findObject(By.text("IMPORT").clickable(true)).click();
- mDevice.waitForIdle();
+
+ // Block until import completes
+ nextImportFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
final Cursor cursor = new StringableCursor(
mContext.getContentResolver().query(Data.CONTENT_URI, null,
@@ -237,37 +306,44 @@ public class SimImportActivityTest {
cursor.close();
- mInstrumentation.startActivitySync(
+ mActivity = mInstrumentation.startActivitySync(
new Intent(mContext, SimImportActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
assertTrue(mDevice.wait(Until.hasObject(By.text("Import One")), TIMEOUT));
- mDevice.findObject(By.descStartsWith("Saving to")).clickAndWait(Until.newWindow(), TIMEOUT);
+ mDevice.findObject(By.descStartsWith("Show more")).clickAndWait(Until.newWindow(), TIMEOUT);
mDevice.findObject(By.textContains(targetAccount.name)).click();
mDevice.waitForIdle();
- assertTrue(mDevice.hasObject(By.text("Import One").checked(false).enabled(false)));
+ assertTrue(mDevice.wait(Until.hasObject(By.text("Import One").checked(false).enabled(false)), TIMEOUT));
assertTrue(mDevice.hasObject(By.text("Import Three").checked(false).enabled(false)));
assertTrue(mDevice.hasObject(By.text("Import Six").checked(false).enabled(false)));
- }
- private SimCard someSimCard() {
- return new SimCard("id", 1, "Carrier", "SIM", "18005550101", "us");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ contactsProviderClient.close();
+ }
}
- private Matcher<SimContact> withContactId(final long id) {
- return new BaseMatcher<SimContact>() {
+ private ListenableFuture<Intent> nextImportCompleteBroadcast() {
+ final SettableFuture<Intent> result = SettableFuture.create();
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
- public boolean matches(Object o) {
- return (o instanceof SimContact) && ((SimContact) o).getId() == id;
+ public void onReceive(Context context, Intent intent) {
+ result.set(intent);
+ LocalBroadcastManager.getInstance(mContext).unregisterReceiver(this);
}
+ };
+ LocalBroadcastManager.getInstance(mContext).registerReceiver(receiver, new IntentFilter(
+ SimImportService.BROADCAST_SIM_IMPORT_COMPLETE));
+ return result;
+ }
+ private Object[] toCursorRow(SimContact contact) {
+ return new Object[] { contact.getId(), contact.getName(), contact.getPhone(), null };
+ }
- @Override
- public void describeTo(Description description) {
- description.appendText("Expected SimContact with id=" + id);
- }
- };
+ private SimCard someSimCard() {
+ return new SimCard("id", 1, "Carrier", "SIM", "18005550101", "us");
}
}
diff --git a/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java b/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java
new file mode 100644
index 000000000..b6ca983c9
--- /dev/null
+++ b/tests/src/com/android/contacts/test/mocks/ForwardingContentProvider.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 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.contacts.test.mocks;
+
+import android.content.ContentProviderClient;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentValues;
+import android.content.OperationApplicationException;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.support.annotation.Nullable;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * Forwards calls to a {@link ContentProviderClient}
+ *
+ * <p>This allows mixing use of the system content providers in a
+ * {@link android.test.mock.MockContentResolver}
+ * </p>
+ */
+public class ForwardingContentProvider extends android.test.mock.MockContentProvider {
+
+ private final ContentProviderClient mClient;
+
+ public ForwardingContentProvider(ContentProviderClient client) {
+ mClient = client;
+ }
+
+ @Override
+ public synchronized Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ try {
+ return mClient.query(url, projection, selection, selectionArgs, sortOrder);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public synchronized Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
+ try {
+ return mClient.query(url, projection, selection, selectionArgs, sortOrder,
+ cancellationSignal);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized String getType(Uri url) {
+ try {
+ return mClient.getType(url);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized String[] getStreamTypes(Uri url, String mimeTypeFilter) {
+ try {
+ return mClient.getStreamTypes(url, mimeTypeFilter);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized Uri insert(Uri url, ContentValues initialValues) {
+ try {
+ return mClient.insert(url, initialValues);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized int bulkInsert(Uri url, ContentValues[] initialValues) {
+ try {
+ return mClient.bulkInsert(url, initialValues);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized int delete(Uri url, String selection, String[] selectionArgs) {
+ try {
+ return mClient.delete(url, selection, selectionArgs);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized int update(Uri url, ContentValues values,
+ String selection, String[] selectionArgs) {
+ try {
+ return mClient.update(url, values, selection, selectionArgs);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public synchronized ParcelFileDescriptor openFile(Uri url, String mode) {
+ try {
+ return mClient.openFile(url, mode);
+ } catch (RemoteException|FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public synchronized ParcelFileDescriptor openFile(Uri url, String mode,
+ CancellationSignal signal) {
+ try {
+ return mClient.openFile(url, mode, signal);
+ } catch (RemoteException|FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public synchronized AssetFileDescriptor openAssetFile(Uri url, String mode) {
+ try {
+ return mClient.openAssetFile(url, mode);
+ } catch (RemoteException|FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public synchronized AssetFileDescriptor openAssetFile(Uri url, String mode,
+ CancellationSignal signal) {
+ try {
+ return mClient.openAssetFile(url, mode, signal);
+ } catch (RemoteException|FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, String mimeType,
+ Bundle opts) {
+ try {
+ return mClient.openTypedAssetFileDescriptor(uri, mimeType, opts);
+ } catch (RemoteException|FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, String mimeType,
+ Bundle opts, CancellationSignal signal) {
+ try {
+ return mClient.openTypedAssetFileDescriptor(uri, mimeType, opts, signal);
+ } catch (RemoteException|FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public synchronized ContentProviderResult[] applyBatch(
+ ArrayList<ContentProviderOperation> operations) {
+ try {
+ return mClient.applyBatch(operations);
+ } catch (RemoteException|OperationApplicationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Nullable
+ @Override
+ public synchronized Bundle call(String method, String arg, Bundle extras) {
+ try {
+ return mClient.call(method, arg, extras);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}