| /* |
| * Copyright (C) 2021 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.bedstead.testapp; |
| |
| import static android.app.AppOpsManager.OPSTR_START_FOREGROUND; |
| import static android.app.admin.DevicePolicyManager.OPERATION_SAFETY_REASON_DRIVING_DISTRACTION; |
| import static android.content.PermissionChecker.PERMISSION_GRANTED; |
| import static android.os.Build.VERSION_CODES.Q; |
| import static android.os.Build.VERSION_CODES.S; |
| |
| import static com.android.bedstead.nene.appops.AppOpsMode.ALLOWED; |
| import static com.android.bedstead.nene.permissions.CommonPermissions.BLUETOOTH_CONNECT; |
| import static com.android.bedstead.nene.permissions.CommonPermissions.READ_CONTACTS; |
| import static com.android.eventlib.truth.EventLogsSubject.assertThat; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.testng.Assert.assertThrows; |
| |
| import android.app.admin.DevicePolicyManager; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| |
| import com.android.bedstead.harrier.BedsteadJUnit4; |
| import com.android.bedstead.harrier.DeviceState; |
| import com.android.bedstead.harrier.annotations.RequireSdkVersion; |
| import com.android.bedstead.nene.TestApis; |
| import com.android.bedstead.nene.permissions.PermissionContext; |
| import com.android.bedstead.nene.users.UserReference; |
| import com.android.bedstead.nene.utils.Poll; |
| import com.android.eventlib.EventLogs; |
| import com.android.eventlib.events.broadcastreceivers.BroadcastReceivedEvent; |
| |
| import org.junit.ClassRule; |
| import org.junit.Ignore; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.time.Duration; |
| |
| @RunWith(BedsteadJUnit4.class) |
| public class TestAppInstanceTest { |
| |
| @ClassRule |
| @Rule |
| public static final DeviceState sDeviceState = new DeviceState(); |
| |
| private static final Context sContext = TestApis.context().instrumentedContext(); |
| private static final UserReference sUser = TestApis.users().instrumented(); |
| |
| private static final TestApp sTestApp = sDeviceState.testApps().query() |
| .whereActivities().isNotEmpty() |
| .get(); |
| private static final TestApp sTestApp2 = sDeviceState.testApps().any(); |
| |
| private static final String INTENT_ACTION = "com.android.bedstead.testapp.test_action"; |
| private static final IntentFilter INTENT_FILTER = new IntentFilter(INTENT_ACTION); |
| private static final Intent INTENT = new Intent(INTENT_ACTION); |
| private static final String INTENT_ACTION_2 = "com.android.bedstead.testapp.test_action2"; |
| private static final IntentFilter INTENT_FILTER_2 = new IntentFilter(INTENT_ACTION_2); |
| private static final Intent INTENT_2 = new Intent(INTENT_ACTION_2); |
| private static final Duration SHORT_TIMEOUT = Duration.ofSeconds(5); |
| |
| @Test |
| public void user_returnsUserReference() { |
| TestAppInstance testAppInstance = sTestApp.instance(sUser); |
| |
| assertThat(testAppInstance.user()).isEqualTo(sUser); |
| } |
| |
| @Test |
| public void testApp_returnsTestApp() { |
| TestAppInstance testAppInstance = sTestApp.instance(sUser); |
| |
| assertThat(testAppInstance.testApp()).isEqualTo(sTestApp); |
| } |
| |
| @Test |
| public void activities_any_returnsActivity() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.activities().any()).isNotNull(); |
| } |
| } |
| |
| @Test |
| public void uninstall_uninstalls() { |
| TestAppInstance testAppInstance = sTestApp.install(); |
| |
| testAppInstance.uninstall(); |
| |
| assertThat(TestApis.packages().find(sTestApp.packageName()) |
| .installedOnUser(sUser)).isFalse(); |
| } |
| |
| @Test |
| public void autoclose_uninstalls() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Intentionally empty |
| } |
| |
| assertThat(TestApis.packages().find(sTestApp.packageName()) |
| .installedOnUser(sUser)).isFalse(); |
| } |
| |
| @Test |
| public void keepAlive_notInstalled_throwsException() { |
| TestAppInstance testAppInstance = sTestApp.instance(sUser); |
| |
| assertThrows(IllegalStateException.class, testAppInstance::keepAlive); |
| } |
| |
| @Test |
| @Ignore("b/203758521 Need to re-add support for killing processes") |
| public void killProcess_keepAlive_processIsRunningAgain() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.keepAlive(); |
| |
| // testAppInstance.process().kill(); |
| |
| Poll.forValue("running process", () -> sTestApp.pkg().runningProcess(sUser)) |
| .toNotBeNull() |
| .errorOnFail() |
| .await(); |
| } |
| } |
| |
| // We cannot test that after stopKeepAlive it does not restart, as we'd have to wait an |
| // unbounded amount of time |
| |
| @Test |
| public void stop_processIsNotRunning() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.activities().any().start(); |
| |
| testAppInstance.stop(); |
| |
| assertThat(sTestApp.pkg().runningProcesses()).isEmpty(); |
| } |
| } |
| |
| @Test |
| public void stop_previouslyCalledKeepAlive_processDoesNotRestart() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.activities().any().start(); |
| testAppInstance.keepAlive(); |
| |
| testAppInstance.stop(); |
| |
| assertThat(sTestApp.pkg().runningProcesses()).isEmpty(); |
| } |
| } |
| |
| @Test |
| public void process_isNotRunning_returnsNull() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.process()).isNull(); |
| } |
| } |
| |
| @Test |
| public void process_isRunning_isNotNull() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.activities().any().start(); |
| |
| Poll.forValue("TestApp process", testAppInstance::process) |
| .toNotBeNull() |
| .errorOnFail() |
| .await(); |
| } |
| } |
| |
| @Test |
| public void registerReceiver_receivesBroadcast() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| |
| sContext.sendBroadcast(INTENT); |
| |
| assertThat(testAppInstance.events().broadcastReceived() |
| .whereIntent().action().isEqualTo(INTENT_ACTION)) |
| .eventOccurred(); |
| } |
| } |
| |
| @Test |
| public void registerReceiver_multipleIntentFilters_receivesAllMatchingBroadcasts() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| testAppInstance.registerReceiver(INTENT_FILTER_2); |
| |
| sContext.sendBroadcast(INTENT); |
| sContext.sendBroadcast(INTENT_2); |
| |
| assertThat(testAppInstance.events().broadcastReceived() |
| .whereIntent().action().isEqualTo(INTENT_ACTION)) |
| .eventOccurred(); |
| assertThat(testAppInstance.events().broadcastReceived() |
| .whereIntent().action().isEqualTo(INTENT_ACTION_2)) |
| .eventOccurred(); |
| } |
| } |
| |
| @Test |
| public void registerReceiver_processIsRunning() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| |
| assertThat(sTestApp.pkg().runningProcess(sUser)).isNotNull(); |
| } |
| } |
| |
| @Test |
| @Ignore("b/203758521 need to re-add support for killing processes") |
| public void stop_registeredReceiver_doesNotReceiveBroadcast() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| |
| // testAppInstance.stop(); |
| sContext.sendBroadcast(INTENT); |
| |
| EventLogs<BroadcastReceivedEvent> logs = |
| BroadcastReceivedEvent.queryPackage(sTestApp.packageName()) |
| .whereIntent().action().isEqualTo(INTENT_ACTION); |
| assertThat(logs.poll(SHORT_TIMEOUT)).isNull(); |
| } |
| } |
| |
| @Test |
| public void unregisterReceiver_registeredReceiver_doesNotReceiveBroadcast() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| |
| testAppInstance.unregisterReceiver(INTENT_FILTER); |
| sContext.sendBroadcast(INTENT); |
| |
| EventLogs<BroadcastReceivedEvent> logs = |
| BroadcastReceivedEvent.queryPackage(sTestApp.packageName()) |
| .whereIntent().action().isEqualTo(INTENT_ACTION); |
| assertThat(logs.poll(SHORT_TIMEOUT)).isNull(); |
| } |
| } |
| |
| @Test |
| public void unregisterReceiver_doesNotUnregisterOtherReceivers() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| testAppInstance.registerReceiver(INTENT_FILTER_2); |
| |
| testAppInstance.unregisterReceiver(INTENT_FILTER); |
| sContext.sendBroadcast(INTENT); |
| sContext.sendBroadcast(INTENT_2); |
| |
| EventLogs<BroadcastReceivedEvent> logs = |
| BroadcastReceivedEvent.queryPackage(sTestApp.packageName()) |
| .whereIntent().action().isEqualTo(INTENT_ACTION); |
| EventLogs<BroadcastReceivedEvent> logs2 = |
| BroadcastReceivedEvent.queryPackage(sTestApp.packageName()) |
| .whereIntent().action().isEqualTo(INTENT_ACTION_2); |
| assertThat(logs.poll(SHORT_TIMEOUT)).isNull(); |
| assertThat(logs2.poll()).isNotNull(); |
| } |
| } |
| |
| @Test |
| public void keepAlive_processIsRunning() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| |
| testAppInstance.keepAlive(); |
| |
| assertThat(sTestApp.pkg().runningProcess(sUser)).isNotNull(); |
| } |
| } |
| |
| @Test |
| @Ignore("b/203758521 need to re-add support for killing processes") |
| public void registerReceiver_appIsKilled_stillReceivesBroadcast() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| testAppInstance.registerReceiver(INTENT_FILTER); |
| // testApp.pkg().runningProcess(sUser).kill(); |
| Poll.forValue("running process", () -> sTestApp.pkg().runningProcess(sUser)) |
| .toNotBeNull() |
| .errorOnFail() |
| .await(); |
| |
| sContext.sendBroadcast(INTENT); |
| |
| EventLogs<BroadcastReceivedEvent> logs = |
| BroadcastReceivedEvent.queryPackage(sTestApp.packageName()) |
| .whereIntent().action().isEqualTo(INTENT_ACTION); |
| assertThat(logs.poll()).isNotNull(); |
| } |
| } |
| |
| @Test |
| @RequireSdkVersion(min = S, reason = "isSafeOperation only available on S+") |
| public void devicePolicyManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Arbitrary call which does not require specific permissions to confirm no crash |
| testAppInstance.devicePolicyManager() |
| .isSafeOperation(OPERATION_SAFETY_REASON_DRIVING_DISTRACTION); |
| } |
| } |
| |
| @Test |
| public void userManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Arbitrary call which does not require specific permissions to confirm no crash |
| testAppInstance.userManager().getUserProfiles(); |
| } |
| } |
| |
| @Test |
| @RequireSdkVersion(min = Q, reason = "Wifimanager API only available on Q+") |
| public void wifiManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Arbitrary call which does not require specific permissions to confirm no crash |
| testAppInstance.wifiManager().getMaxNumberOfNetworkSuggestionsPerApp(); |
| } |
| } |
| |
| @Test |
| public void hardwarePropertiesManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Arbitrary call - there are no methods on this service which don't require permissions |
| assertThrows(SecurityException.class, () -> { |
| testAppInstance.hardwarePropertiesManager().getCpuUsages(); |
| }); |
| } |
| } |
| |
| @Test |
| public void packageManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.packageManager().hasSystemFeature("")).isFalse(); |
| } |
| } |
| |
| @Test |
| public void crossProfileApps_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.crossProfileApps().getTargetUserProfiles()).isEmpty(); |
| } |
| } |
| |
| @Test |
| public void launcherApps_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.launcherApps().hasShortcutHostPermission()).isFalse(); |
| } |
| } |
| |
| @Test |
| public void accountManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Arbitrary call which does not require specific permissions to confirm no crash |
| assertThat(testAppInstance.accountManager().getAccounts()).isNotNull(); |
| } |
| } |
| |
| @Test |
| public void context_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.context().getSystemServiceName(DevicePolicyManager.class)) |
| .isEqualTo(Context.DEVICE_POLICY_SERVICE); |
| } |
| } |
| |
| @Test |
| public void context_getContentResolver_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // Arbitrary call which does not require specific permissions to confirm no crash |
| assertThat(testAppInstance.context().getContentResolver().getPersistedUriPermissions()) |
| .isNotNull(); |
| } |
| } |
| |
| @Test |
| public void keyChain_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| assertThat(testAppInstance.keyChain().isKeyAlgorithmSupported("A")).isFalse(); |
| } |
| } |
| |
| @Test |
| public void bluetoothManager_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install(); |
| PermissionContext p = testAppInstance.permissions().withPermission(BLUETOOTH_CONNECT)) { |
| assertThat(testAppInstance.bluetoothManager().getConnectedDevices(/* profile= */ 7)) |
| .isEmpty(); |
| } |
| } |
| |
| @Test |
| public void bluetoothManager_getAdapter_returnsUsableInstance() { |
| try (TestAppInstance testAppInstance = sTestApp.install()) { |
| // No exception |
| testAppInstance.bluetoothManager().getAdapter().isEnabled(); |
| } |
| } |
| |
| @Test |
| public void permissions_withPermission_permissionStateAppliesToCallsToTestApp() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| PermissionContext p = testApp.permissions().withPermission(READ_CONTACTS)) { |
| assertThat(testApp.context().checkSelfPermission( |
| READ_CONTACTS)).isEqualTo(PERMISSION_GRANTED); |
| } |
| } |
| |
| @Test |
| public void permissions_withPermission_permissionStateDoesNotApplyToOtherTestApps() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| TestAppInstance testApp2 = sTestApp2.install(); |
| PermissionContext p = testApp.permissions().withPermission(READ_CONTACTS)) { |
| assertThat(testApp2.context().checkSelfPermission( |
| READ_CONTACTS)).isNotEqualTo(PERMISSION_GRANTED); |
| } |
| } |
| |
| @Test |
| public void permissions_withPermission_permissionStateDoesNotApplyToInstrumentedApp() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| PermissionContext p = testApp.permissions().withPermission(READ_CONTACTS)) { |
| assertThat(sContext.checkSelfPermission( |
| READ_CONTACTS)).isNotEqualTo(PERMISSION_GRANTED); |
| } |
| } |
| |
| @Test |
| public void permissions_withPermission_permissionStateDoesNotApplyToInstrumentedAppAfterCall() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| PermissionContext p = testApp.permissions().withPermission(READ_CONTACTS)) { |
| testApp.context().checkSelfPermission(READ_CONTACTS); |
| |
| assertThat(sContext.checkSelfPermission( |
| READ_CONTACTS)).isNotEqualTo(PERMISSION_GRANTED); |
| } |
| } |
| |
| @Test |
| public void permissions_withPermission_instrumentedPermissionStateDoesNotAffectTestApp() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| PermissionContext p = TestApis.permissions().withoutPermission(READ_CONTACTS); |
| PermissionContext p2 = testApp.permissions().withPermission(READ_CONTACTS)) { |
| assertThat(sContext.checkSelfPermission( |
| READ_CONTACTS)).isNotEqualTo(PERMISSION_GRANTED); |
| assertThat(testApp.context().checkSelfPermission( |
| READ_CONTACTS)).isEqualTo(PERMISSION_GRANTED); |
| } |
| } |
| |
| @Test |
| public void permissions_withAppOp_appOpIsAllowedForTestApp() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| PermissionContext p = testApp.permissions().withAppOp(OPSTR_START_FOREGROUND)) { |
| |
| assertThat(sTestApp.pkg().appOps().get(OPSTR_START_FOREGROUND)).isEqualTo(ALLOWED); |
| } |
| } |
| |
| @Test |
| public void permissions_withoutAppOp_appOpIsNotAllowedForTestApp() { |
| try (TestAppInstance testApp = sTestApp.install(); |
| PermissionContext p = testApp.permissions().withAppOp(OPSTR_START_FOREGROUND); |
| PermissionContext p2 = testApp.permissions().withoutAppOp(OPSTR_START_FOREGROUND)) { |
| assertThat(sTestApp.pkg().appOps().get(OPSTR_START_FOREGROUND)).isNotEqualTo(ALLOWED); |
| } |
| } |
| } |