1 /*
2  * Copyright (C) 2020 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 package android.car.test.mocks;
17 
18 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
19 
20 import static org.mockito.ArgumentMatchers.anyBoolean;
21 import static org.mockito.Matchers.anyString;
22 import static org.mockito.Mockito.when;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.UserIdInt;
27 import android.app.ActivityManager;
28 import android.car.test.util.UserTestingHelper;
29 import android.car.test.util.UserTestingHelper.UserInfoBuilder;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.content.pm.UserInfo;
33 import android.content.pm.UserInfo.UserInfoFlag;
34 import android.os.IBinder;
35 import android.os.IInterface;
36 import android.os.ServiceManager;
37 import android.os.UserHandle;
38 import android.os.UserManager;
39 
40 import com.android.internal.infra.AndroidFuture;
41 
42 import java.util.Arrays;
43 import java.util.List;
44 import java.util.Objects;
45 import java.util.concurrent.ExecutionException;
46 import java.util.concurrent.TimeUnit;
47 import java.util.concurrent.TimeoutException;
48 import java.util.stream.Collectors;
49 
50 /**
51  * Provides common Mockito calls for core Android classes.
52  */
53 public final class AndroidMockitoHelper {
54 
55     private static final long ASYNC_TIMEOUT_MS = 500;
56 
57     /**
58      * Mocks a call to {@link ActivityManager#getCurrentUser()}.
59      *
60      * <p><b>Note: </b>it must be made inside a
61      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
62      * {@code spyStatic(ActivityManager.class)}.
63      *
64      * @param userId result of such call
65      */
mockAmGetCurrentUser(@serIdInt int userId)66     public static void mockAmGetCurrentUser(@UserIdInt int userId) {
67         doReturn(userId).when(() -> ActivityManager.getCurrentUser());
68     }
69 
70     /**
71      * Mocks a call to {@link UserManager#isHeadlessSystemUserMode()}.
72      *
73      * <p><b>Note: </b>it must be made inside a
74      * {@linkcom.android.dx.mockito.inline.extended.StaticMockitoSession} built with
75      * {@code spyStatic(UserManager.class)}.
76      *
77      * @param mode result of such call
78      */
mockUmIsHeadlessSystemUserMode(boolean mode)79     public static void mockUmIsHeadlessSystemUserMode(boolean mode) {
80         doReturn(mode).when(() -> UserManager.isHeadlessSystemUserMode());
81     }
82 
83     /**
84      * Mocks {@code UserManager#getUserInfo(userId)} to return a {@link UserInfo} with the given
85      * {@code flags}.
86      */
87     @NonNull
mockUmGetUserInfo(@onNull UserManager um, @UserIdInt int userId, @UserInfoFlag int flags)88     public static UserInfo mockUmGetUserInfo(@NonNull UserManager um, @UserIdInt int userId,
89             @UserInfoFlag int flags) {
90         Objects.requireNonNull(um);
91         UserInfo user = new UserTestingHelper.UserInfoBuilder(userId).setFlags(flags).build();
92         mockUmGetUserInfo(um, user);
93         return user;
94     }
95 
96     /**
97      * Mocks {@code UserManager.getUserInfo(userId)} to return the given {@link UserInfo}.
98      */
99     @NonNull
mockUmGetUserInfo(@onNull UserManager um, @NonNull UserInfo user)100     public static void mockUmGetUserInfo(@NonNull UserManager um, @NonNull UserInfo user) {
101         when(um.getUserInfo(user.id)).thenReturn(user);
102     }
103 
104     /**
105      * Mocks {@code UserManager#getUserInfo(userId)} when the {@code userId} is the system user's.
106      */
107     @NonNull
mockUmGetSystemUser(@onNull UserManager um)108     public static void mockUmGetSystemUser(@NonNull UserManager um) {
109         UserInfo user = new UserTestingHelper.UserInfoBuilder(UserHandle.USER_SYSTEM)
110                 .setFlags(UserInfo.FLAG_SYSTEM).build();
111         when(um.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(user);
112     }
113 
114     /**
115      * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
116      * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return the given
117      * users.
118      */
mockUmGetUsers(@onNull UserManager um, @NonNull UserInfo... users)119     public static void mockUmGetUsers(@NonNull UserManager um, @NonNull UserInfo... users) {
120         Objects.requireNonNull(um);
121         List<UserInfo> testUsers = Arrays.stream(users).collect(Collectors.toList());
122         when(um.getUsers()).thenReturn(testUsers);
123         when(um.getUsers(anyBoolean())).thenReturn(testUsers);
124         when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(testUsers);
125     }
126 
127     /**
128      * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
129      * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return simple
130      * users with the given ids.
131      */
mockUmGetUsers(@onNull UserManager um, @NonNull @UserIdInt int... userIds)132     public static void mockUmGetUsers(@NonNull UserManager um, @NonNull @UserIdInt int... userIds) {
133         List<UserInfo> users = UserTestingHelper.newUsers(userIds);
134         when(um.getUsers()).thenReturn(users);
135         when(um.getUsers(anyBoolean())).thenReturn(users);
136         when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(users);
137     }
138 
139     /**
140      * Mocks a call to {@code UserManager#getUsers()}, which includes dying users.
141      */
mockUmGetAllUsers(@onNull UserManager um, @NonNull List<UserInfo> userInfos)142     public static void mockUmGetAllUsers(@NonNull UserManager um,
143             @NonNull List<UserInfo> userInfos) {
144         when(um.getUsers()).thenReturn(userInfos);
145     }
146 
147     /**
148      * Mocks {@code UserManager#getUsers()}, {@code UserManager#getUsers(excludeDying)}, and
149      * {@code UserManager#getUsers(excludePartial, excludeDying, excludeDying)} to return given
150      * userInfos.
151      */
mockUmGetUsers(@onNull UserManager um, @NonNull List<UserInfo> userInfos)152     public static void mockUmGetUsers(@NonNull UserManager um, @NonNull List<UserInfo> userInfos) {
153         when(um.getUsers()).thenReturn(userInfos);
154         when(um.getUsers(anyBoolean())).thenReturn(userInfos);
155         when(um.getUsers(anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(userInfos);
156     }
157 
158     /**
159      * Mocks a call to {@code UserManager#isUserRunning(userId)}.
160      */
mockUmIsUserRunning(@onNull UserManager um, @UserIdInt int userId, boolean isRunning)161     public static void mockUmIsUserRunning(@NonNull UserManager um, @UserIdInt int userId,
162             boolean isRunning) {
163         when(um.isUserRunning(userId)).thenReturn(isRunning);
164     }
165 
166     /**
167      * Mocks a successful call to {@code UserManager#createUser(String, String, int)}, returning
168      * a user with the passed arguments.
169      */
170     @NonNull
mockUmCreateUser(@onNull UserManager um, @Nullable String name, @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId)171     public static UserInfo mockUmCreateUser(@NonNull UserManager um, @Nullable String name,
172             @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId) {
173         UserInfo userInfo = new UserInfoBuilder(userId)
174                         .setName(name)
175                         .setType(userType)
176                         .setFlags(flags)
177                         .build();
178         when(um.createUser(name, userType, flags)).thenReturn(userInfo);
179         return userInfo;
180     }
181 
182     /**
183      * Mocks a call to {@code UserManager#createUser(String, String, int)} that throws the given
184      * runtime exception.
185      */
186     @NonNull
mockUmCreateUser(@onNull UserManager um, @Nullable String name, @NonNull String userType, @UserInfoFlag int flags, @NonNull RuntimeException e)187     public static void mockUmCreateUser(@NonNull UserManager um, @Nullable String name,
188             @NonNull String userType, @UserInfoFlag int flags, @NonNull RuntimeException e) {
189         when(um.createUser(name, userType, flags)).thenThrow(e);
190     }
191 
192     /**
193      * Mocks a call to {@link ServiceManager#getService(name)}.
194      *
195      * <p><b>Note: </b>it must be made inside a
196      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
197      * {@code spyStatic(ServiceManager.class)}.
198      *
199      * @param name interface name of the service
200      * @param binder result of such call
201      */
mockSmGetService(@onNull String name, @NonNull IBinder binder)202     public static void mockSmGetService(@NonNull String name, @NonNull IBinder binder) {
203         doReturn(binder).when(() -> ServiceManager.getService(name));
204     }
205 
206     /**
207      * Returns mocked binder implementation from the given interface name.
208      *
209      * <p><b>Note: </b>it must be made inside a
210      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
211      * {@code spyStatic(ServiceManager.class)}.
212      *
213      * @param name interface name of the service
214      * @param binder mocked return of ServiceManager.getService
215      * @param service binder implementation
216      */
mockQueryService(@onNull String name, @NonNull IBinder binder, @NonNull T service)217     public static <T extends IInterface> void mockQueryService(@NonNull String name,
218             @NonNull IBinder binder, @NonNull T service) {
219         doReturn(binder).when(() -> ServiceManager.getService(name));
220         when(binder.queryLocalInterface(anyString())).thenReturn(service);
221     }
222 
223     /**
224      * Mocks a call to {@link Context#getSystemService(Class)}.
225      */
mockContextGetService(@onNull Context context, @NonNull Class<T> serviceClass, @NonNull T service)226     public static <T> void mockContextGetService(@NonNull Context context,
227             @NonNull Class<T> serviceClass, @NonNull T service) {
228         when(context.getSystemService(serviceClass)).thenReturn(service);
229         if (serviceClass.equals(PackageManager.class)) {
230             when(context.getPackageManager()).thenReturn(PackageManager.class.cast(service));
231         }
232     }
233 
234     /**
235      * Gets the result of a future, or throw a {@link IllegalStateException} if it times out after
236      * {@value #ASYNC_TIMEOUT_MS} ms.
237      */
238     @NonNull
getResult(@onNull AndroidFuture<T> future)239     public static <T> T getResult(@NonNull AndroidFuture<T> future)
240             throws InterruptedException, ExecutionException {
241         return getResult(future, ASYNC_TIMEOUT_MS);
242     }
243 
244     /**
245      * Gets the result of a future, or throw a {@link IllegalStateException} if it times out.
246      */
247     @NonNull
getResult(@onNull AndroidFuture<T> future, long timeoutMs)248     public static <T> T getResult(@NonNull AndroidFuture<T> future, long timeoutMs)
249             throws InterruptedException, ExecutionException {
250         try {
251             return future.get(timeoutMs, TimeUnit.MILLISECONDS);
252         } catch (TimeoutException e) {
253             throw new IllegalStateException("not called in " + ASYNC_TIMEOUT_MS + "ms", e);
254         }
255     }
256 
AndroidMockitoHelper()257     private AndroidMockitoHelper() {
258         throw new UnsupportedOperationException("contains only static methods");
259     }
260 }
261