• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.Mockito.when;
22 
23 import android.app.ActivityManager;
24 import android.content.Context;
25 import android.os.Process;
26 
27 import androidx.test.ext.junit.runners.AndroidJUnit4;
28 import androidx.test.platform.app.InstrumentationRegistry;
29 
30 import com.android.server.healthconnect.testing.TestUtils;
31 
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.mockito.Mock;
36 import org.mockito.MockitoAnnotations;
37 
38 import java.util.List;
39 import java.util.concurrent.Future;
40 import java.util.concurrent.ThreadPoolExecutor;
41 
42 @RunWith(AndroidJUnit4.class)
43 public class HealthConnectThreadSchedulerTest {
44     private ThreadPoolExecutor mInternalTaskScheduler;
45     private ThreadPoolExecutor mControllerTaskScheduler;
46     private ThreadPoolExecutor mForegroundTaskScheduler;
47     private ThreadPoolExecutor mBackgroundTaskScheduler;
48     private long mInternalTaskSchedulerCompletedJobs;
49     private long mControllerTaskSchedulerCompletedJobs;
50     private long mForegroundTaskSchedulerCompletedJobs;
51     private long mBackgroundTaskSchedulerCompletedJobs;
52     private Context mContext;
53     private HealthConnectThreadScheduler mHealthConnectThreadScheduler;
54 
55     @Mock private Context mMockContext;
56     @Mock private ActivityManager mActivityManager;
57 
58     @Before
setUp()59     public void setUp() {
60         mHealthConnectThreadScheduler = new HealthConnectThreadScheduler();
61         MockitoAnnotations.initMocks(this);
62 
63         mHealthConnectThreadScheduler.resetThreadPools();
64 
65         mInternalTaskScheduler = mHealthConnectThreadScheduler.mInternalBackgroundExecutor;
66         mInternalTaskSchedulerCompletedJobs = mInternalTaskScheduler.getCompletedTaskCount();
67         mControllerTaskScheduler = mHealthConnectThreadScheduler.mControllerExecutor;
68         mControllerTaskSchedulerCompletedJobs = mControllerTaskScheduler.getCompletedTaskCount();
69         mForegroundTaskScheduler = mHealthConnectThreadScheduler.mForegroundExecutor;
70         mForegroundTaskSchedulerCompletedJobs = mForegroundTaskScheduler.getCompletedTaskCount();
71         mBackgroundTaskScheduler = mHealthConnectThreadScheduler.mBackgroundThreadExecutor;
72         mBackgroundTaskSchedulerCompletedJobs = mBackgroundTaskScheduler.getCompletedTaskCount();
73         mContext = InstrumentationRegistry.getInstrumentation().getContext();
74     }
75 
76     @Test
testSchedulerScheduleInternal()77     public void testSchedulerScheduleInternal() throws Exception {
78         mHealthConnectThreadScheduler.scheduleInternalTask(() -> {});
79         TestUtils.waitForTaskToFinishSuccessfully(
80                 () -> {
81                     if (mInternalTaskScheduler.getCompletedTaskCount()
82                             != mInternalTaskSchedulerCompletedJobs + 1) {
83                         throw new RuntimeException();
84                     }
85                 });
86     }
87 
88     @Test
testScheduleControllerTask()89     public void testScheduleControllerTask() throws Exception {
90         mHealthConnectThreadScheduler.scheduleControllerTask(() -> {});
91         TestUtils.waitForTaskToFinishSuccessfully(
92                 () -> {
93                     if (mControllerTaskScheduler.getCompletedTaskCount()
94                             != mControllerTaskSchedulerCompletedJobs + 1) {
95                         throw new RuntimeException();
96                     }
97                 });
98     }
99 
100     @Test
testScheduleBackgroundTask()101     public void testScheduleBackgroundTask() throws Exception {
102         mockCurrentProcessImportance(ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED);
103 
104         mHealthConnectThreadScheduler.schedule(mMockContext, () -> {}, Process.myUid(), false);
105         TestUtils.waitForTaskToFinishSuccessfully(
106                 () -> {
107                     if (mBackgroundTaskScheduler.getCompletedTaskCount()
108                             != mBackgroundTaskSchedulerCompletedJobs + 1) {
109                         throw new RuntimeException();
110                     }
111                 });
112     }
113 
114     @Test
testScheduleForegroundTask()115     public void testScheduleForegroundTask() throws Exception {
116         mockCurrentProcessImportance(ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
117 
118         mHealthConnectThreadScheduler.schedule(mMockContext, () -> {}, Process.myUid(), false);
119         TestUtils.waitForTaskToFinishSuccessfully(
120                 () -> {
121                     if (mForegroundTaskScheduler.getCompletedTaskCount()
122                             != mForegroundTaskSchedulerCompletedJobs + 1) {
123                         throw new RuntimeException();
124                     }
125                 });
126     }
127 
128     @Test
testHealthConnectScheduler_runningAppProcessNull()129     public void testHealthConnectScheduler_runningAppProcessNull() throws Exception {
130         when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
131         when(mActivityManager.getRunningAppProcesses()).thenReturn(null);
132 
133         mHealthConnectThreadScheduler.scheduleInternalTask(() -> {});
134         TestUtils.waitForTaskToFinishSuccessfully(
135                 () -> {
136                     if (mInternalTaskScheduler.getCompletedTaskCount()
137                             != mInternalTaskSchedulerCompletedJobs + 1) {
138                         throw new RuntimeException();
139                     }
140                 });
141     }
142 
143     @Test
testHealthConnectSchedulerClear()144     public void testHealthConnectSchedulerClear() {
145         assertThat(mInternalTaskSchedulerCompletedJobs).isEqualTo(0);
146         assertThat(mControllerTaskSchedulerCompletedJobs).isEqualTo(0);
147         assertThat(mForegroundTaskSchedulerCompletedJobs).isEqualTo(0);
148         assertThat(mBackgroundTaskSchedulerCompletedJobs).isEqualTo(0);
149     }
150 
151     @Test
testScheduleAfterTheSchedulersAreShutdown_expectNoException()152     public void testScheduleAfterTheSchedulersAreShutdown_expectNoException() {
153         mHealthConnectThreadScheduler.shutdownThreadPools();
154 
155         mHealthConnectThreadScheduler.schedule(mContext, () -> {}, Process.myUid(), false);
156         mHealthConnectThreadScheduler.schedule(mContext, () -> {}, Process.myUid(), true);
157         mHealthConnectThreadScheduler.scheduleInternalTask(() -> {});
158         mHealthConnectThreadScheduler.scheduleControllerTask(() -> {});
159     }
160 
161     @Test
testInternalSchedulerThreadName()162     public void testInternalSchedulerThreadName() throws Exception {
163         Future<String> name = mInternalTaskScheduler.submit(() -> Thread.currentThread().getName());
164         assertThat(name.get()).isEqualTo("hc-int-bg-0");
165     }
166 
167     @Test
testControllerSchedulerThreadName()168     public void testControllerSchedulerThreadName() throws Exception {
169         Future<String> name =
170                 mControllerTaskScheduler.submit(() -> Thread.currentThread().getName());
171         assertThat(name.get()).startsWith("hc-ctrl-");
172     }
173 
174     @Test
testForegroundSchedulerThreadName()175     public void testForegroundSchedulerThreadName() throws Exception {
176         Future<String> name =
177                 mForegroundTaskScheduler.submit(() -> Thread.currentThread().getName());
178         assertThat(name.get()).startsWith("hc-fg-0");
179     }
180 
181     @Test
testBackgroundSchedulerThreadName()182     public void testBackgroundSchedulerThreadName() throws Exception {
183         Future<String> name =
184                 mBackgroundTaskScheduler.submit(() -> Thread.currentThread().getName());
185         assertThat(name.get()).isEqualTo("hc-bg-0");
186     }
187 
mockCurrentProcessImportance(int importance)188     private void mockCurrentProcessImportance(int importance) {
189         when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
190         ActivityManager.RunningAppProcessInfo runningAppProcessInfo =
191                 new ActivityManager.RunningAppProcessInfo();
192         runningAppProcessInfo.uid = Process.myUid();
193         runningAppProcessInfo.importance = importance;
194         when(mActivityManager.getRunningAppProcesses()).thenReturn(List.of(runningAppProcessInfo));
195     }
196 }
197