Add unit test for migration broadcast sending logic.
Bug: 267830390
Test: atest MigrationBroadcastSendingTest
Change-Id: If60fe5f2235443530c2026a56d566fadf216eb9c
diff --git a/tests/unittests/src/com/android/server/healthconnect/migration/MigrationBroadcastSendingTest.java b/tests/unittests/src/com/android/server/healthconnect/migration/MigrationBroadcastSendingTest.java
new file mode 100644
index 0000000..3b77b5d
--- /dev/null
+++ b/tests/unittests/src/com/android/server/healthconnect/migration/MigrationBroadcastSendingTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2023 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.server.healthconnect.migration;
+
+import static junit.framework.Assert.fail;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.health.connect.HealthConnectManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.verification.VerificationMode;
+
+import java.util.ArrayList;
+
+/** Unit tests for broadcast sending logic in {@link MigrationBroadcast} */
+@RunWith(AndroidJUnit4.class)
+public class MigrationBroadcastSendingTest {
+ private static final String[] PERMISSIONS_TO_CHECK =
+ new String[] {Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA};
+ private static final String MOCK_CONFIGURED_PACKAGE = "com.configured.app";
+ private static final String MOCK_UNCONFIGURED_PACKAGE_ONE = "com.unconfigured.app";
+ private static final String MOCK_UNCONFIGURED_PACKAGE_TWO = "com.unconfigured.apptwo";
+
+ @Mock private Context mContext;
+ @Mock private Context mUserContext;
+ @Mock private PackageManager mPackageManager;
+ @Mock private PackageManager mUserContextPackageManager;
+ @Mock private Resources mResources;
+ @Mock private UserHandle mUser;
+ @Mock private UserManager mUserManager;
+
+ private MigrationBroadcast mMigrationBroadcast;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getIdentifier(
+ eq("config_healthConnectMigratorPackageName"), eq("string"), eq("android")))
+ .thenReturn(1);
+ when(mContext.getString(anyInt())).thenReturn(MOCK_CONFIGURED_PACKAGE);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+
+ when(mContext.createContextAsUser(eq(mUser), eq(0))).thenReturn(mUserContext);
+ when(mUserContext.getPackageManager()).thenReturn(mUserContextPackageManager);
+
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+
+ mMigrationBroadcast = new MigrationBroadcast(mContext, mUser);
+ }
+
+ @Test
+ public void testSendInvocationBroadcast_noPermissionMatchingApps_noBroadcastSent()
+ throws Exception {
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(new ArrayList<PackageInfo>());
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(never());
+ }
+
+ @Test
+ public void testSendInvocationBroadcast_noIntentMatchingApps_noBroadcastSent()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray = createPackageInfoArray(MOCK_CONFIGURED_PACKAGE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(null);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(never());
+ }
+
+ @Test
+ public void
+ testSendInvocationBroadcast_oneMigrationAwareConfiguredAppInstalledUserRunning_broadcastSentToConfiguredApp()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray = createPackageInfoArray(MOCK_CONFIGURED_PACKAGE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+ when(mUserContextPackageManager.getPackageInfo(
+ anyString(), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(new PackageInfo());
+ when(mUserManager.isUserRunning(eq(mUser))).thenReturn(true);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(times(1));
+ }
+
+ @Test
+ public void
+ testSendInvocationBroadcast_oneMigrationAwareConfiguredAppInstalledUserNotRunning_noBroadcastSent()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray = createPackageInfoArray(MOCK_CONFIGURED_PACKAGE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+ when(mUserContextPackageManager.getPackageInfo(
+ anyString(), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(new PackageInfo());
+ when(mUserManager.isUserRunning(eq(mUser))).thenReturn(false);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(never());
+ }
+
+ @Test
+ public void
+ testSendInvocationBroadcast_oneMigrationAwareConfiguredAppNotInstalledOnUser_noBroadcastSent()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray = createPackageInfoArray(MOCK_CONFIGURED_PACKAGE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+ when(mUserContextPackageManager.getPackageInfo(
+ anyString(), argThat(flag -> (flag.getValue() == 0))))
+ .thenThrow(PackageManager.NameNotFoundException.class);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(never());
+ }
+
+ @Test(expected = Exception.class)
+ public void testSendInvocationBroadcast_oneMigrationAwareNotConfiguredApp_exceptionThrown()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray =
+ createPackageInfoArray(MOCK_UNCONFIGURED_PACKAGE_ONE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+
+ try {
+ mMigrationBroadcast.sendInvocationBroadcast();
+ fail("Expected Exception");
+ } finally {
+ verifyInvocations(never());
+ }
+ }
+
+ @Test
+ public void
+ testSendInvocationBroadcast_multipleAppsIncludingConfiguredAppInstalledUserRunning_broadcastSentToConfiguredApp()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray =
+ createPackageInfoArray(MOCK_CONFIGURED_PACKAGE, MOCK_UNCONFIGURED_PACKAGE_ONE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+ when(mUserContextPackageManager.getPackageInfo(
+ anyString(), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(new PackageInfo());
+ when(mUserManager.isUserRunning(eq(mUser))).thenReturn(true);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(times(1));
+ }
+
+ @Test
+ public void
+ testSendInvocationBroadcast_multipleAppsIncludingConfiguredAppInstalledUserNotRunning_noBroadcastSent()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray =
+ createPackageInfoArray(MOCK_CONFIGURED_PACKAGE, MOCK_UNCONFIGURED_PACKAGE_ONE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+ when(mUserContextPackageManager.getPackageInfo(
+ anyString(), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(new PackageInfo());
+ when(mUserManager.isUserRunning(eq(mUser))).thenReturn(false);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(never());
+ }
+
+ @Test
+ public void
+ testSendInvocationBroadcast_multipleAppsIncludingConfiguredAppNotInstalledOnUser_noBroadcastSent()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray =
+ createPackageInfoArray(MOCK_CONFIGURED_PACKAGE, MOCK_UNCONFIGURED_PACKAGE_ONE);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+ when(mUserContextPackageManager.getPackageInfo(
+ anyString(), argThat(flag -> (flag.getValue() == 0))))
+ .thenThrow(PackageManager.NameNotFoundException.class);
+
+ mMigrationBroadcast.sendInvocationBroadcast();
+
+ verifyInvocations(never());
+ }
+
+ @Test(expected = Exception.class)
+ public void testSendInvocationBroadcast_multipleAppsExcludingConfiguredApp_exceptionThrown()
+ throws Exception {
+ ArrayList<PackageInfo> packageInfoArray =
+ createPackageInfoArray(
+ MOCK_UNCONFIGURED_PACKAGE_ONE, MOCK_UNCONFIGURED_PACKAGE_TWO);
+ when(mPackageManager.getPackagesHoldingPermissions(
+ eq(PERMISSIONS_TO_CHECK), argThat(flag -> (flag.getValue() == 0))))
+ .thenReturn(packageInfoArray);
+ getResolveActivityResult(new ResolveInfo());
+
+ try {
+ mMigrationBroadcast.sendInvocationBroadcast();
+ fail("Expected Exception");
+ } finally {
+ verifyInvocations(never());
+ }
+ }
+
+ private ArrayList<PackageInfo> createPackageInfoArray(String... packageNames) {
+ ArrayList<PackageInfo> packageInfoArray = new ArrayList<PackageInfo>();
+ for (String packageName : packageNames) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfoArray.add(packageInfo);
+ }
+ return packageInfoArray;
+ }
+
+ private void getResolveActivityResult(ResolveInfo result) {
+ when(mPackageManager.resolveActivity(
+ argThat(
+ intent ->
+ (HealthConnectManager.ACTION_SHOW_MIGRATION_INFO.equals(
+ intent.getAction()))),
+ argThat(flag -> (flag.getValue() == PackageManager.MATCH_ALL))))
+ .thenReturn(result);
+ }
+
+ private void verifyInvocations(VerificationMode verificationMode) {
+ verify(mContext, verificationMode)
+ .sendBroadcastAsUser(
+ argThat(
+ intent ->
+ (HealthConnectManager.ACTION_HEALTH_CONNECT_MIGRATION_READY
+ .equals(intent.getAction())
+ && (MOCK_CONFIGURED_PACKAGE.equals(
+ intent.getPackage())))),
+ eq(mUser));
+ }
+}