1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.healthconnect; 18 19 import static org.mockito.Mockito.when; 20 21 import android.app.ActivityManager; 22 import android.content.Context; 23 import android.os.Process; 24 25 import androidx.test.platform.app.InstrumentationRegistry; 26 import androidx.test.runner.AndroidJUnit4; 27 28 import com.google.common.truth.Truth; 29 30 import org.junit.Before; 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 import org.mockito.Mock; 34 import org.mockito.MockitoAnnotations; 35 36 import java.util.List; 37 import java.util.concurrent.ThreadPoolExecutor; 38 39 @RunWith(AndroidJUnit4.class) 40 public class HealthConnectThreadSchedulerTest { 41 private ThreadPoolExecutor mInternalTaskScheduler; 42 private ThreadPoolExecutor mControllerTaskScheduler; 43 private ThreadPoolExecutor mForegroundTaskScheduler; 44 private ThreadPoolExecutor mBackgroundTaskScheduler; 45 private long mInternalTaskSchedulerCompletedJobs; 46 private long mControllerTaskSchedulerCompletedJobs; 47 private long mForegroundTaskSchedulerCompletedJobs; 48 private long mBackgroundTaskSchedulerCompletedJobs; 49 private Context mContext; 50 51 @Mock private Context mMockContext; 52 @Mock private ActivityManager mActivityManager; 53 54 @Before setUp()55 public void setUp() { 56 MockitoAnnotations.initMocks(this); 57 58 HealthConnectThreadScheduler.resetThreadPools(); 59 60 mInternalTaskScheduler = HealthConnectThreadScheduler.sInternalBackgroundExecutor; 61 mInternalTaskSchedulerCompletedJobs = mInternalTaskScheduler.getCompletedTaskCount(); 62 mControllerTaskScheduler = HealthConnectThreadScheduler.sControllerExecutor; 63 mControllerTaskSchedulerCompletedJobs = mControllerTaskScheduler.getCompletedTaskCount(); 64 mForegroundTaskScheduler = HealthConnectThreadScheduler.sForegroundExecutor; 65 mForegroundTaskSchedulerCompletedJobs = mForegroundTaskScheduler.getCompletedTaskCount(); 66 mBackgroundTaskScheduler = HealthConnectThreadScheduler.sBackgroundThreadExecutor; 67 mBackgroundTaskSchedulerCompletedJobs = mBackgroundTaskScheduler.getCompletedTaskCount(); 68 mContext = InstrumentationRegistry.getInstrumentation().getContext(); 69 } 70 71 @Test testHealthConnectSchedulerScheduleInternal()72 public void testHealthConnectSchedulerScheduleInternal() throws Exception { 73 HealthConnectThreadScheduler.scheduleInternalTask(() -> {}); 74 TestUtils.waitForTaskToFinishSuccessfully( 75 () -> { 76 if (mInternalTaskScheduler.getCompletedTaskCount() 77 != mInternalTaskSchedulerCompletedJobs + 1) { 78 throw new RuntimeException(); 79 } 80 }); 81 HealthConnectThreadScheduler.scheduleControllerTask(() -> {}); 82 TestUtils.waitForTaskToFinishSuccessfully( 83 () -> { 84 if (mControllerTaskScheduler.getCompletedTaskCount() 85 != mControllerTaskSchedulerCompletedJobs + 1) { 86 throw new RuntimeException(); 87 } 88 }); 89 HealthConnectThreadScheduler.schedule(mContext, () -> {}, Process.myUid(), false); 90 TestUtils.waitForTaskToFinishSuccessfully( 91 () -> { 92 if (mBackgroundTaskScheduler.getCompletedTaskCount() 93 != mBackgroundTaskSchedulerCompletedJobs + 1) { 94 throw new RuntimeException(); 95 } 96 }); 97 98 when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); 99 ActivityManager.RunningAppProcessInfo runningAppProcessInfo = 100 new ActivityManager.RunningAppProcessInfo(); 101 runningAppProcessInfo.uid = Process.myUid(); 102 runningAppProcessInfo.importance = 103 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 104 when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(runningAppProcessInfo)); 105 106 HealthConnectThreadScheduler.schedule(mMockContext, () -> {}, Process.myUid(), false); 107 TestUtils.waitForTaskToFinishSuccessfully( 108 () -> { 109 if (mForegroundTaskScheduler.getCompletedTaskCount() 110 != mForegroundTaskSchedulerCompletedJobs + 1) { 111 throw new RuntimeException(); 112 } 113 }); 114 } 115 116 @Test testHealthConnectScheduler_runningAppProcessNull()117 public void testHealthConnectScheduler_runningAppProcessNull() throws Exception { 118 when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); 119 when(mActivityManager.getRunningAppProcesses()).thenReturn(null); 120 121 HealthConnectThreadScheduler.scheduleInternalTask(() -> {}); 122 TestUtils.waitForTaskToFinishSuccessfully( 123 () -> { 124 if (mInternalTaskScheduler.getCompletedTaskCount() 125 != mInternalTaskSchedulerCompletedJobs + 1) { 126 throw new RuntimeException(); 127 } 128 }); 129 } 130 131 @Test testHealthConnectSchedulerClear()132 public void testHealthConnectSchedulerClear() { 133 Truth.assertThat(mInternalTaskSchedulerCompletedJobs).isEqualTo(0); 134 Truth.assertThat(mControllerTaskSchedulerCompletedJobs).isEqualTo(0); 135 Truth.assertThat(mForegroundTaskSchedulerCompletedJobs).isEqualTo(0); 136 Truth.assertThat(mBackgroundTaskSchedulerCompletedJobs).isEqualTo(0); 137 } 138 139 @Test testScheduleAfterTheSchedulersAreShutdown_expectNoException()140 public void testScheduleAfterTheSchedulersAreShutdown_expectNoException() { 141 HealthConnectThreadScheduler.shutdownThreadPools(); 142 143 HealthConnectThreadScheduler.schedule(mContext, () -> {}, Process.myUid(), false); 144 HealthConnectThreadScheduler.schedule(mContext, () -> {}, Process.myUid(), true); 145 HealthConnectThreadScheduler.scheduleInternalTask(() -> {}); 146 HealthConnectThreadScheduler.scheduleControllerTask(() -> {}); 147 } 148 } 149