Add unit tests for slice purchase app
Test: atest CarrierDefaultAppUnitTests
Bug: 248533515
Change-Id: I1be5b66f10eb9394bfd19a943fc7ecf5735f6800
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.bp b/packages/CarrierDefaultApp/tests/unit/Android.bp
index 54c9016..cdf7957 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.bp
+++ b/packages/CarrierDefaultApp/tests/unit/Android.bp
@@ -27,11 +27,13 @@
libs: [
"android.test.runner",
"android.test.base",
+ "SlicePurchaseController",
],
static_libs: [
"androidx.test.rules",
- "mockito-target-minus-junit4",
+ "mockito-target-inline-minus-junit4",
],
+ jni_libs: ["libdexmakerjvmtiagent"],
// Include all test java files.
srcs: ["src/**/*.java"],
platform_apis: true,
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
new file mode 100644
index 0000000..cecc86d
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 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.carrierdefaultapp;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.test.ActivityUnitTestCase;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.phone.slice.SlicePurchaseController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchaseActivity> {
+ private static final String TAG = "SlicePurchaseActivityTest";
+ private static final String URL = "file:///android_asset/slice_purchase_test.html";
+ private static final int PHONE_ID = 0;
+
+ @Mock PendingIntent mPendingIntent;
+ @Mock PendingIntent mCanceledIntent;
+ @Mock CarrierConfigManager mCarrierConfigManager;
+ @Mock NotificationManager mNotificationManager;
+ @Mock PersistableBundle mPersistableBundle;
+
+ private SlicePurchaseActivity mSlicePurchaseActivity;
+ private Context mContext;
+
+ public SlicePurchaseActivityTest() {
+ super(SlicePurchaseActivity.class);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+
+ // setup context
+ mContext = spy(getInstrumentation().getTargetContext());
+ doReturn(mCarrierConfigManager).when(mContext)
+ .getSystemService(eq(CarrierConfigManager.class));
+ doReturn(URL).when(mPersistableBundle).getString(
+ CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING);
+ doReturn(mPersistableBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
+ doReturn(mNotificationManager).when(mContext)
+ .getSystemService(eq(NotificationManager.class));
+ doReturn(mContext).when(mContext).getApplicationContext();
+ setActivityContext(mContext);
+
+ // set up intent
+ Intent intent = new Intent();
+ intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
+ intent.putExtra(SlicePurchaseController.EXTRA_SUB_ID,
+ SubscriptionManager.getDefaultDataSubscriptionId());
+ intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
+ intent.putExtra(SlicePurchaseController.EXTRA_REQUESTING_APP_NAME, TAG);
+ Intent spiedIntent = spy(intent);
+
+ // set up pending intents
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mPendingIntent).getCreatorPackage();
+ doReturn(true).when(mPendingIntent).isBroadcast();
+ doReturn(mPendingIntent).when(spiedIntent).getParcelableExtra(
+ anyString(), eq(PendingIntent.class));
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mCanceledIntent).getCreatorPackage();
+ doReturn(true).when(mCanceledIntent).isBroadcast();
+ doReturn(mCanceledIntent).when(spiedIntent).getParcelableExtra(
+ eq(SlicePurchaseController.EXTRA_INTENT_CANCELED), eq(PendingIntent.class));
+
+ mSlicePurchaseActivity = startActivity(spiedIntent, null, null);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mSlicePurchaseActivity.onDestroy();
+ super.tearDown();
+ }
+
+ @Test
+ public void testOnPurchaseSuccessful() throws Exception {
+ int duration = 5 * 60 * 1000; // 5 minutes
+ int invalidDuration = -1;
+ mSlicePurchaseActivity.onPurchaseSuccessful(duration);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPendingIntent).send(eq(mContext), eq(0), intentCaptor.capture());
+ Intent intent = intentCaptor.getValue();
+ assertEquals(duration, intent.getLongExtra(
+ SlicePurchaseController.EXTRA_PURCHASE_DURATION, invalidDuration));
+ }
+
+ @Test
+ public void testOnPurchaseFailed() throws Exception {
+ int failureCode = SlicePurchaseController.FAILURE_CODE_SERVER_UNREACHABLE;
+ String failureReason = "Server unreachable";
+ mSlicePurchaseActivity.onPurchaseFailed(failureCode, failureReason);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPendingIntent).send(eq(mContext), eq(0), intentCaptor.capture());
+ Intent intent = intentCaptor.getValue();
+ assertEquals(failureCode, intent.getIntExtra(
+ SlicePurchaseController.EXTRA_FAILURE_CODE, failureCode));
+ assertEquals(failureReason, intent.getStringExtra(
+ SlicePurchaseController.EXTRA_FAILURE_REASON));
+ }
+
+ @Test
+ public void testOnUserCanceled() throws Exception {
+ mSlicePurchaseActivity.onDestroy();
+ verify(mCanceledIntent).send();
+ }
+}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
new file mode 100644
index 0000000..5765e5b
--- /dev/null
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2022 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.carrierdefaultapp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.DisplayMetrics;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.phone.slice.SlicePurchaseController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class SlicePurchaseBroadcastReceiverTest {
+ private static final int PHONE_ID = 0;
+ private static final String TAG = "SlicePurchaseBroadcastReceiverTest";
+ private static final String EXTRA = "EXTRA";
+
+ @Mock Intent mIntent;
+ @Mock Intent mDataIntent;
+ @Mock PendingIntent mPendingIntent;
+ @Mock PendingIntent mCanceledIntent;
+ @Mock PendingIntent mContentIntent1;
+ @Mock PendingIntent mContentIntent2;
+ @Mock Context mContext;
+ @Mock Resources mResources;
+ @Mock NotificationManager mNotificationManager;
+ @Mock ApplicationInfo mApplicationInfo;
+ @Mock PackageManager mPackageManager;
+ @Mock DisplayMetrics mDisplayMetrics;
+ @Mock SlicePurchaseActivity mSlicePurchaseActivity;
+
+ private SlicePurchaseBroadcastReceiver mSlicePurchaseBroadcastReceiver;
+ private ArgumentCaptor<Intent> mIntentCaptor;
+ private ArgumentCaptor<Notification> mNotificationCaptor;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mNotificationManager).when(mContext)
+ .getSystemService(eq(NotificationManager.class));
+
+ mIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ mNotificationCaptor = ArgumentCaptor.forClass(Notification.class);
+ mSlicePurchaseBroadcastReceiver = spy(new SlicePurchaseBroadcastReceiver());
+ }
+
+ @Test
+ public void testSendSlicePurchaseAppResponse() throws Exception {
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(mIntent, EXTRA);
+ verify(mPendingIntent, never()).send();
+
+ doReturn(mPendingIntent).when(mIntent).getParcelableExtra(
+ eq(EXTRA), eq(PendingIntent.class));
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(mIntent, EXTRA);
+ verify(mPendingIntent).send();
+ }
+
+ @Test
+ public void testSendSlicePurchaseAppResponseWithData() throws Exception {
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponseWithData(
+ mContext, mIntent, EXTRA, mDataIntent);
+ verify(mPendingIntent, never()).send(eq(mContext), eq(0), any(Intent.class));
+
+ doReturn(mPendingIntent).when(mIntent).getParcelableExtra(
+ eq(EXTRA), eq(PendingIntent.class));
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponseWithData(
+ mContext, mIntent, EXTRA, mDataIntent);
+ verify(mPendingIntent).send(eq(mContext), eq(0), mIntentCaptor.capture());
+ assertEquals(mDataIntent, mIntentCaptor.getValue());
+ }
+
+ @Test
+ public void testIsIntentValid() {
+ assertFalse(SlicePurchaseBroadcastReceiver.isIntentValid(mIntent));
+
+ // set up intent
+ doReturn(PHONE_ID).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PHONE_ID), anyInt());
+ doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_SUB_ID), anyInt());
+ doReturn(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY), anyInt());
+ doReturn(TAG).when(mIntent).getStringExtra(
+ eq(SlicePurchaseController.EXTRA_REQUESTING_APP_NAME));
+ assertFalse(SlicePurchaseBroadcastReceiver.isIntentValid(mIntent));
+
+ // set up pending intent
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mPendingIntent).getCreatorPackage();
+ doReturn(true).when(mPendingIntent).isBroadcast();
+ doReturn(mPendingIntent).when(mIntent).getParcelableExtra(
+ anyString(), eq(PendingIntent.class));
+ assertTrue(SlicePurchaseBroadcastReceiver.isIntentValid(mIntent));
+ }
+
+ @Test
+ public void testDisplayBoosterNotification() {
+ // set up intent
+ doReturn(SlicePurchaseController.ACTION_START_SLICE_PURCHASE_APP).when(mIntent).getAction();
+ doReturn(PHONE_ID).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PHONE_ID), anyInt());
+ doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_SUB_ID), anyInt());
+ doReturn(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY), anyInt());
+ doReturn(TAG).when(mIntent).getStringExtra(
+ eq(SlicePurchaseController.EXTRA_REQUESTING_APP_NAME));
+
+ // set up pending intent
+ doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mPendingIntent).getCreatorPackage();
+ doReturn(true).when(mPendingIntent).isBroadcast();
+ doReturn(mPendingIntent).when(mIntent).getParcelableExtra(
+ anyString(), eq(PendingIntent.class));
+
+ // set up notification
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(mDisplayMetrics).when(mResources).getDisplayMetrics();
+ doReturn("").when(mResources).getString(anyInt());
+ doReturn(mApplicationInfo).when(mContext).getApplicationInfo();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+
+ // set up intents created by broadcast receiver
+ doReturn(mContentIntent1).when(mSlicePurchaseBroadcastReceiver).createContentIntent(
+ eq(mContext), eq(mIntent), eq(1));
+ doReturn(mContentIntent2).when(mSlicePurchaseBroadcastReceiver).createContentIntent(
+ eq(mContext), eq(mIntent), eq(2));
+ doReturn(mCanceledIntent).when(mSlicePurchaseBroadcastReceiver).createCanceledIntent(
+ eq(mContext), eq(mIntent));
+
+ // send ACTION_START_SLICE_PURCHASE_APP
+ mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent);
+
+ // verify network boost notification was shown
+ verify(mNotificationManager).notifyAsUser(
+ eq(SlicePurchaseBroadcastReceiver.NETWORK_BOOST_NOTIFICATION_TAG),
+ eq(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY),
+ mNotificationCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ Notification notification = mNotificationCaptor.getValue();
+ assertEquals(mContentIntent1, notification.contentIntent);
+ assertEquals(mPendingIntent, notification.deleteIntent);
+ assertEquals(2, notification.actions.length);
+ assertEquals(mCanceledIntent, notification.actions[0].actionIntent);
+ assertEquals(mContentIntent2, notification.actions[1].actionIntent);
+ }
+
+
+ @Test
+ public void testNotificationCanceled() {
+ // set up intent
+ doReturn("com.android.phone.slice.action.NOTIFICATION_CANCELED").when(mIntent).getAction();
+ doReturn(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY), anyInt());
+
+ // send ACTION_NOTIFICATION_CANCELED
+ mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent);
+
+ // verify notification was canceled
+ verify(mNotificationManager).cancelAsUser(
+ eq(SlicePurchaseBroadcastReceiver.NETWORK_BOOST_NOTIFICATION_TAG),
+ eq(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY),
+ eq(UserHandle.ALL));
+ }
+
+ @Test
+ public void testNotificationTimeout() {
+ // set up intent
+ doReturn(SlicePurchaseController.ACTION_SLICE_PURCHASE_APP_RESPONSE_TIMEOUT).when(mIntent)
+ .getAction();
+ doReturn(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY), anyInt());
+
+ // send ACTION_SLICE_PURCHASE_APP_RESPONSE_TIMEOUT
+ mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent);
+
+ // verify notification was canceled
+ verify(mNotificationManager).cancelAsUser(
+ eq(SlicePurchaseBroadcastReceiver.NETWORK_BOOST_NOTIFICATION_TAG),
+ eq(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY),
+ eq(UserHandle.ALL));
+ }
+
+ @Test
+ // TODO: WebView/Activity should not close on timeout.
+ // This test should be removed once implementation is fixed.
+ public void testActivityTimeout() {
+ // create and track activity
+ SlicePurchaseBroadcastReceiver.updateSlicePurchaseActivity(
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mSlicePurchaseActivity);
+
+ // set up intent
+ doReturn(SlicePurchaseController.ACTION_SLICE_PURCHASE_APP_RESPONSE_TIMEOUT).when(mIntent)
+ .getAction();
+ doReturn(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY).when(mIntent).getIntExtra(
+ eq(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY), anyInt());
+
+ // send ACTION_SLICE_PURCHASE_APP_RESPONSE_TIMEOUT
+ mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent);
+
+ // verify activity was canceled
+ verify(mSlicePurchaseActivity).finishAndRemoveTask();
+
+ // untrack activity
+ SlicePurchaseBroadcastReceiver.removeSlicePurchaseActivity(
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
+ }
+}