• 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 android.credentials;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertThrows;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.ArgumentMatchers.same;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.app.Activity;
31 import android.app.slice.Slice;
32 import android.content.Context;
33 import android.content.pm.ServiceInfo;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.CancellationSignal;
37 import android.os.ICancellationSignal;
38 import android.os.OutcomeReceiver;
39 import android.os.RemoteException;
40 import android.service.credentials.CredentialEntry;
41 
42 import androidx.test.platform.app.InstrumentationRegistry;
43 
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.ArgumentCaptor;
48 import org.mockito.Mock;
49 import org.mockito.junit.MockitoJUnitRunner;
50 
51 import java.util.Arrays;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Objects;
55 import java.util.concurrent.Executor;
56 
57 @RunWith(MockitoJUnitRunner.class)
58 public class CredentialManagerTest {
59     @Mock private ICredentialManager mMockCredentialManagerService;
60 
61     @Mock private Activity mMockActivity;
62 
63     private static final int TEST_USER_ID = 1;
64     private static final CredentialProviderInfo TEST_CREDENTIAL_PROVIDER_INFO =
65             new CredentialProviderInfo.Builder(new ServiceInfo())
66                     .setSystemProvider(true)
67                     .setOverrideLabel("test")
68                     .addCapabilities(Arrays.asList("passkey"))
69                     .setEnabled(true)
70                     .build();
71     private static final List<CredentialProviderInfo> TEST_CREDENTIAL_PROVIDER_INFO_LIST =
72             Arrays.asList(TEST_CREDENTIAL_PROVIDER_INFO);
73 
74     private GetCredentialRequest mGetRequest;
75     private CreateCredentialRequest mCreateRequest;
76 
77     private ClearCredentialStateRequest mClearRequest;
78     private RegisterCredentialDescriptionRequest mRegisterRequest;
79     private UnregisterCredentialDescriptionRequest mUnregisterRequest;
80 
81     private CredentialManager mCredentialManager;
82     private Executor mExecutor;
83     private String mPackageName;
84 
bundleEquals(Bundle a, Bundle b)85     private static boolean bundleEquals(Bundle a, Bundle b) {
86         if (a == null && b == null) {
87             return true;
88         }
89         if (a == null || b == null) {
90             return false;
91         }
92         for (String aKey : a.keySet()) {
93             if (!Objects.equals(a.get(aKey), b.get(aKey))) {
94                 return false;
95             }
96         }
97 
98         for (String bKey : b.keySet()) {
99             if (!Objects.equals(b.get(bKey), a.get(bKey))) {
100                 return false;
101             }
102         }
103 
104         return true;
105     }
106 
assertBundleEquals(Bundle a, Bundle b)107     private static void assertBundleEquals(Bundle a, Bundle b) {
108         assertThat(bundleEquals(a, b)).isTrue();
109     }
110 
111     @Before
setup()112     public void setup() {
113         mGetRequest =
114                 new GetCredentialRequest.Builder(Bundle.EMPTY)
115                         .addCredentialOption(
116                                 new CredentialOption(
117                                         Credential.TYPE_PASSWORD_CREDENTIAL,
118                                         Bundle.EMPTY,
119                                         Bundle.EMPTY,
120                                         false))
121                         .build();
122         mCreateRequest =
123                 new CreateCredentialRequest.Builder(
124                                 Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY, Bundle.EMPTY)
125                         .setIsSystemProviderRequired(false)
126                         .setAlwaysSendAppInfoToProvider(false)
127                         .build();
128         mClearRequest = new ClearCredentialStateRequest(Bundle.EMPTY);
129 
130         final Slice slice =
131                 new Slice.Builder(Uri.parse("foo://bar"), null)
132                         .addText("some text", null, List.of(Slice.HINT_TITLE))
133                         .build();
134         mRegisterRequest =
135                 new RegisterCredentialDescriptionRequest(
136                         new CredentialDescription(
137                                 Credential.TYPE_PASSWORD_CREDENTIAL,
138                                 new HashSet<>(List.of("{ \"foo\": \"bar\" }")),
139                                 List.of(
140                                         new CredentialEntry(
141                                                 Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
142         mUnregisterRequest =
143                 new UnregisterCredentialDescriptionRequest(
144                         new CredentialDescription(
145                                 Credential.TYPE_PASSWORD_CREDENTIAL,
146                                 new HashSet<>(List.of("{ \"foo\": \"bar\" }")),
147                                 List.of(
148                                         new CredentialEntry(
149                                                 Credential.TYPE_PASSWORD_CREDENTIAL, slice))));
150 
151         final Context context = InstrumentationRegistry.getInstrumentation().getContext();
152         mCredentialManager = new CredentialManager(context, mMockCredentialManagerService);
153         mExecutor = Runnable::run;
154         mPackageName = context.getOpPackageName();
155     }
156 
157     @Test
testGetCredential_nullRequest()158     public void testGetCredential_nullRequest() {
159         GetCredentialRequest nullRequest = null;
160         assertThrows(
161                 NullPointerException.class,
162                 () ->
163                         mCredentialManager.getCredential(
164                                 mMockActivity, nullRequest, null, mExecutor, result -> {}));
165     }
166 
167     @Test
testGetCredential_nullActivity()168     public void testGetCredential_nullActivity() {
169         assertThrows(
170                 NullPointerException.class,
171                 () ->
172                         mCredentialManager.getCredential(
173                                 null, mGetRequest, null, mExecutor, result -> {}));
174     }
175 
176     @Test
testGetCredential_nullExecutor()177     public void testGetCredential_nullExecutor() {
178         assertThrows(
179                 NullPointerException.class,
180                 () ->
181                         mCredentialManager.getCredential(
182                                 mMockActivity, mGetRequest, null, null, result -> {}));
183     }
184 
185     @Test
testGetCredential_nullCallback()186     public void testGetCredential_nullCallback() {
187         assertThrows(
188                 NullPointerException.class,
189                 () ->
190                         mCredentialManager.getCredential(
191                                 mMockActivity, mGetRequest, null, null, null));
192     }
193 
194     @Test
testGetCredential_noCredential()195     public void testGetCredential_noCredential() throws RemoteException {
196         ArgumentCaptor<IGetCredentialCallback> callbackCaptor =
197                 ArgumentCaptor.forClass(IGetCredentialCallback.class);
198         ArgumentCaptor<GetCredentialException> errorCaptor =
199                 ArgumentCaptor.forClass(GetCredentialException.class);
200 
201         OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback =
202                 mock(OutcomeReceiver.class);
203 
204         when(mMockCredentialManagerService.executeGetCredential(
205                         any(), callbackCaptor.capture(), any()))
206                 .thenReturn(mock(ICancellationSignal.class));
207         mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback);
208         verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
209 
210         callbackCaptor
211                 .getValue()
212                 .onError(GetCredentialException.TYPE_NO_CREDENTIAL, "no credential found");
213         verify(callback).onError(errorCaptor.capture());
214 
215         assertThat(errorCaptor.getValue().getType())
216                 .isEqualTo(GetCredentialException.TYPE_NO_CREDENTIAL);
217     }
218 
219     @Test
testGetCredential_alreadyCancelled()220     public void testGetCredential_alreadyCancelled() throws RemoteException {
221         final CancellationSignal cancellation = new CancellationSignal();
222         cancellation.cancel();
223 
224         mCredentialManager.getCredential(
225                 mMockActivity, mGetRequest, cancellation, mExecutor, result -> {});
226 
227         verify(mMockCredentialManagerService, never()).executeGetCredential(any(), any(), any());
228     }
229 
230     @Test
testGetCredential_cancel()231     public void testGetCredential_cancel() throws RemoteException {
232         final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
233         final CancellationSignal cancellation = new CancellationSignal();
234 
235         OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback =
236                 mock(OutcomeReceiver.class);
237 
238         when(mMockCredentialManagerService.executeGetCredential(any(), any(), any()))
239                 .thenReturn(serviceSignal);
240 
241         mCredentialManager.getCredential(
242                 mMockActivity, mGetRequest, cancellation, mExecutor, callback);
243 
244         verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
245 
246         cancellation.cancel();
247         verify(serviceSignal).cancel();
248     }
249 
250     @Test
testGetCredential_success()251     public void testGetCredential_success() throws RemoteException {
252         final Credential cred = new Credential(Credential.TYPE_PASSWORD_CREDENTIAL, Bundle.EMPTY);
253 
254         ArgumentCaptor<IGetCredentialCallback> callbackCaptor =
255                 ArgumentCaptor.forClass(IGetCredentialCallback.class);
256         ArgumentCaptor<GetCredentialResponse> responseCaptor =
257                 ArgumentCaptor.forClass(GetCredentialResponse.class);
258 
259         OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback =
260                 mock(OutcomeReceiver.class);
261 
262         when(mMockCredentialManagerService.executeGetCredential(
263                         any(), callbackCaptor.capture(), any()))
264                 .thenReturn(mock(ICancellationSignal.class));
265         mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback);
266         verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName));
267 
268         callbackCaptor.getValue().onResponse(new GetCredentialResponse(cred));
269         verify(callback).onResult(responseCaptor.capture());
270 
271         assertThat(responseCaptor.getValue().getCredential().getType()).isEqualTo(cred.getType());
272     }
273 
274     @Test
testCreateCredential_nullRequest()275     public void testCreateCredential_nullRequest() {
276         assertThrows(
277                 NullPointerException.class,
278                 () ->
279                         mCredentialManager.createCredential(
280                                 mMockActivity, null, null, mExecutor, result -> {}));
281     }
282 
283     @Test
testCreateCredential_nullActivity()284     public void testCreateCredential_nullActivity() {
285         assertThrows(
286                 NullPointerException.class,
287                 () ->
288                         mCredentialManager.createCredential(
289                                 null, mCreateRequest, null, mExecutor, result -> {}));
290     }
291 
292     @Test
testCreateCredential_nullExecutor()293     public void testCreateCredential_nullExecutor() {
294         assertThrows(
295                 NullPointerException.class,
296                 () ->
297                         mCredentialManager.createCredential(
298                                 mMockActivity, mCreateRequest, null, null, result -> {}));
299     }
300 
301     @Test
testCreateCredential_nullCallback()302     public void testCreateCredential_nullCallback() {
303         assertThrows(
304                 NullPointerException.class,
305                 () ->
306                         mCredentialManager.createCredential(
307                                 mMockActivity, mCreateRequest, null, mExecutor, null));
308     }
309 
310     @Test
testCreateCredential_alreadyCancelled()311     public void testCreateCredential_alreadyCancelled() throws RemoteException {
312         final CancellationSignal cancellation = new CancellationSignal();
313         cancellation.cancel();
314 
315         mCredentialManager.createCredential(
316                 mMockActivity, mCreateRequest, cancellation, mExecutor, result -> {});
317 
318         verify(mMockCredentialManagerService, never()).executeCreateCredential(any(), any(), any());
319     }
320 
321     @Test
testCreateCredential_cancel()322     public void testCreateCredential_cancel() throws RemoteException {
323         final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
324         final CancellationSignal cancellation = new CancellationSignal();
325 
326         OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback =
327                 mock(OutcomeReceiver.class);
328 
329         when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any()))
330                 .thenReturn(serviceSignal);
331 
332         mCredentialManager.createCredential(
333                 mMockActivity, mCreateRequest, cancellation, mExecutor, callback);
334 
335         verify(mMockCredentialManagerService)
336                 .executeCreateCredential(any(), any(), eq(mPackageName));
337 
338         cancellation.cancel();
339         verify(serviceSignal).cancel();
340     }
341 
342     @Test
testCreateCredential_failed()343     public void testCreateCredential_failed() throws RemoteException {
344         ArgumentCaptor<ICreateCredentialCallback> callbackCaptor =
345                 ArgumentCaptor.forClass(ICreateCredentialCallback.class);
346         ArgumentCaptor<CreateCredentialException> errorCaptor =
347                 ArgumentCaptor.forClass(CreateCredentialException.class);
348 
349         OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback =
350                 mock(OutcomeReceiver.class);
351 
352         when(mMockCredentialManagerService.executeCreateCredential(
353                         any(), callbackCaptor.capture(), any()))
354                 .thenReturn(mock(ICancellationSignal.class));
355         mCredentialManager.createCredential(
356                 mMockActivity, mCreateRequest, null, mExecutor, callback);
357         verify(mMockCredentialManagerService)
358                 .executeCreateCredential(any(), any(), eq(mPackageName));
359 
360         callbackCaptor.getValue().onError(CreateCredentialException.TYPE_UNKNOWN, "unknown error");
361         verify(callback).onError(errorCaptor.capture());
362 
363         assertThat(errorCaptor.getValue().getType())
364                 .isEqualTo(CreateCredentialException.TYPE_UNKNOWN);
365     }
366 
367     @Test
testCreateCredential_success()368     public void testCreateCredential_success() throws RemoteException {
369         final Bundle responseData = new Bundle();
370         responseData.putString("foo", "bar");
371 
372         ArgumentCaptor<ICreateCredentialCallback> callbackCaptor =
373                 ArgumentCaptor.forClass(ICreateCredentialCallback.class);
374         ArgumentCaptor<CreateCredentialResponse> responseCaptor =
375                 ArgumentCaptor.forClass(CreateCredentialResponse.class);
376 
377         OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback =
378                 mock(OutcomeReceiver.class);
379 
380         when(mMockCredentialManagerService.executeCreateCredential(
381                         any(), callbackCaptor.capture(), any()))
382                 .thenReturn(mock(ICancellationSignal.class));
383         mCredentialManager.createCredential(
384                 mMockActivity, mCreateRequest, null, mExecutor, callback);
385         verify(mMockCredentialManagerService)
386                 .executeCreateCredential(any(), any(), eq(mPackageName));
387 
388         callbackCaptor.getValue().onResponse(new CreateCredentialResponse(responseData));
389         verify(callback).onResult(responseCaptor.capture());
390 
391         assertBundleEquals(responseCaptor.getValue().getData(), responseData);
392     }
393 
394     @Test
testClearCredentialState_nullRequest()395     public void testClearCredentialState_nullRequest() {
396         assertThrows(
397                 NullPointerException.class,
398                 () -> mCredentialManager.clearCredentialState(null, null, mExecutor, result -> {}));
399     }
400 
401     @Test
testClearCredentialState_nullExecutor()402     public void testClearCredentialState_nullExecutor() {
403         assertThrows(
404                 NullPointerException.class,
405                 () ->
406                         mCredentialManager.clearCredentialState(
407                                 mClearRequest, null, null, result -> {}));
408     }
409 
410     @Test
testClearCredentialState_nullCallback()411     public void testClearCredentialState_nullCallback() {
412         assertThrows(
413                 NullPointerException.class,
414                 () ->
415                         mCredentialManager.clearCredentialState(
416                                 mClearRequest, null, mExecutor, null));
417     }
418 
419     @Test
testClearCredential_alreadyCancelled()420     public void testClearCredential_alreadyCancelled() throws RemoteException {
421         final CancellationSignal cancellation = new CancellationSignal();
422         cancellation.cancel();
423 
424         mCredentialManager.clearCredentialState(
425                 mClearRequest, cancellation, mExecutor, result -> {});
426 
427         verify(mMockCredentialManagerService, never()).clearCredentialState(any(), any(), any());
428     }
429 
430     @Test
testClearCredential_cancel()431     public void testClearCredential_cancel() throws RemoteException {
432         final ICancellationSignal serviceSignal = mock(ICancellationSignal.class);
433         final CancellationSignal cancellation = new CancellationSignal();
434 
435         OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
436 
437         when(mMockCredentialManagerService.clearCredentialState(any(), any(), any()))
438                 .thenReturn(serviceSignal);
439 
440         mCredentialManager.clearCredentialState(mClearRequest, cancellation, mExecutor, callback);
441 
442         verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
443 
444         cancellation.cancel();
445         verify(serviceSignal).cancel();
446     }
447 
448     @Test
testClearCredential_failed()449     public void testClearCredential_failed() throws RemoteException {
450         ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor =
451                 ArgumentCaptor.forClass(IClearCredentialStateCallback.class);
452         ArgumentCaptor<ClearCredentialStateException> errorCaptor =
453                 ArgumentCaptor.forClass(ClearCredentialStateException.class);
454 
455         OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
456 
457         when(mMockCredentialManagerService.clearCredentialState(
458                         any(), callbackCaptor.capture(), any()))
459                 .thenReturn(mock(ICancellationSignal.class));
460         mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
461         verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
462 
463         callbackCaptor
464                 .getValue()
465                 .onError(ClearCredentialStateException.TYPE_UNKNOWN, "unknown error");
466         verify(callback).onError(errorCaptor.capture());
467 
468         assertThat(errorCaptor.getValue().getType())
469                 .isEqualTo(ClearCredentialStateException.TYPE_UNKNOWN);
470     }
471 
472     @Test
testClearCredential_success()473     public void testClearCredential_success() throws RemoteException {
474         ArgumentCaptor<IClearCredentialStateCallback> callbackCaptor =
475                 ArgumentCaptor.forClass(IClearCredentialStateCallback.class);
476 
477         OutcomeReceiver<Void, ClearCredentialStateException> callback = mock(OutcomeReceiver.class);
478 
479         when(mMockCredentialManagerService.clearCredentialState(
480                         any(), callbackCaptor.capture(), any()))
481                 .thenReturn(mock(ICancellationSignal.class));
482         mCredentialManager.clearCredentialState(mClearRequest, null, mExecutor, callback);
483         verify(mMockCredentialManagerService).clearCredentialState(any(), any(), eq(mPackageName));
484 
485         callbackCaptor.getValue().onSuccess();
486         verify(callback).onResult(any());
487     }
488 
489     @Test
testGetCredentialProviderServices_allProviders()490     public void testGetCredentialProviderServices_allProviders() throws RemoteException {
491         verifyGetCredentialProviderServices(CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS);
492     }
493 
494     @Test
testGetCredentialProviderServices_userProviders()495     public void testGetCredentialProviderServices_userProviders() throws RemoteException {
496         verifyGetCredentialProviderServices(CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
497     }
498 
499     @Test
testGetCredentialProviderServices_systemProviders()500     public void testGetCredentialProviderServices_systemProviders() throws RemoteException {
501         verifyGetCredentialProviderServices(
502                 CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY);
503     }
504 
505     @Test
testGetCredentialProviderServicesForTesting_allProviders()506     public void testGetCredentialProviderServicesForTesting_allProviders() throws RemoteException {
507         verifyGetCredentialProviderServicesForTesting(
508                 CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS);
509     }
510 
511     @Test
testGetCredentialProviderServicesForTesting_userProviders()512     public void testGetCredentialProviderServicesForTesting_userProviders() throws RemoteException {
513         verifyGetCredentialProviderServicesForTesting(
514                 CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
515     }
516 
517     @Test
testGetCredentialProviderServicesForTesting_systemProviders()518     public void testGetCredentialProviderServicesForTesting_systemProviders()
519             throws RemoteException {
520         verifyGetCredentialProviderServicesForTesting(
521                 CredentialManager.PROVIDER_FILTER_SYSTEM_PROVIDERS_ONLY);
522     }
523 
verifyGetCredentialProviderServices(int testFilter)524     private void verifyGetCredentialProviderServices(int testFilter) throws RemoteException {
525         when(mMockCredentialManagerService.getCredentialProviderServices(TEST_USER_ID, testFilter))
526                 .thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
527 
528         List<CredentialProviderInfo> output =
529                 mCredentialManager.getCredentialProviderServices(TEST_USER_ID, testFilter);
530 
531         assertThat(output).containsExactlyElementsIn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
532     }
533 
verifyGetCredentialProviderServicesForTesting(int testFilter)534     private void verifyGetCredentialProviderServicesForTesting(int testFilter)
535             throws RemoteException {
536         when(mMockCredentialManagerService.getCredentialProviderServicesForTesting(testFilter))
537                 .thenReturn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
538 
539         List<CredentialProviderInfo> output =
540                 mCredentialManager.getCredentialProviderServicesForTesting(testFilter);
541 
542         assertThat(output).containsExactlyElementsIn(TEST_CREDENTIAL_PROVIDER_INFO_LIST);
543     }
544 
545     @Test
testSetEnabledProviders_nullProviders()546     public void testSetEnabledProviders_nullProviders() {
547         assertThrows(
548                 NullPointerException.class,
549                 () ->
550                         mCredentialManager.setEnabledProviders(
551                                 null, null, 0, mExecutor, response -> {}));
552     }
553 
554     @Test
testSetEnabledProviders_nullExecutor()555     public void testSetEnabledProviders_nullExecutor() {
556         assertThrows(
557                 NullPointerException.class,
558                 () ->
559                         mCredentialManager.setEnabledProviders(
560                                 List.of("foo"), List.of("foo"), 0, null, response -> {}));
561     }
562 
563     @Test
testSetEnabledProviders_nullCallback()564     public void testSetEnabledProviders_nullCallback() {
565         assertThrows(
566                 NullPointerException.class,
567                 () ->
568                         mCredentialManager.setEnabledProviders(
569                                 List.of("foo"), List.of("foo"), 0, mExecutor, null));
570     }
571 
572     @Test
testSetEnabledProviders_failed()573     public void testSetEnabledProviders_failed() throws RemoteException {
574         OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
575 
576         ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor =
577                 ArgumentCaptor.forClass(ISetEnabledProvidersCallback.class);
578         ArgumentCaptor<SetEnabledProvidersException> errorCaptor =
579                 ArgumentCaptor.forClass(SetEnabledProvidersException.class);
580 
581         final List<String> providers = List.of("foo", "bar");
582         final int userId = 0;
583         mCredentialManager.setEnabledProviders(providers, providers, userId, mExecutor, callback);
584         verify(mMockCredentialManagerService)
585                 .setEnabledProviders(eq(providers), eq(providers), eq(0), callbackCaptor.capture());
586 
587         final String errorType = "unknown";
588         final String errorMessage = "Unknown error";
589         callbackCaptor.getValue().onError(errorType, errorMessage);
590         verify(callback).onError(errorCaptor.capture());
591 
592         assertThat(errorCaptor.getValue().getType()).isEqualTo(errorType);
593         assertThat(errorCaptor.getValue().getMessage()).isEqualTo(errorMessage);
594     }
595 
596     @Test
testSetEnabledProviders_success()597     public void testSetEnabledProviders_success() throws RemoteException {
598         OutcomeReceiver<Void, SetEnabledProvidersException> callback = mock(OutcomeReceiver.class);
599 
600         ArgumentCaptor<ISetEnabledProvidersCallback> callbackCaptor =
601                 ArgumentCaptor.forClass(ISetEnabledProvidersCallback.class);
602 
603         final List<String> providers = List.of("foo", "bar");
604         final List<String> primaryProviders = List.of("foo");
605         final int userId = 0;
606         mCredentialManager.setEnabledProviders(
607                 primaryProviders, providers, userId, mExecutor, callback);
608 
609         verify(mMockCredentialManagerService)
610                 .setEnabledProviders(
611                         eq(primaryProviders), eq(providers), eq(0), callbackCaptor.capture());
612 
613         callbackCaptor.getValue().onResponse();
614         verify(callback).onResult(any());
615     }
616 
617     @Test
testRegisterCredentialDescription_nullRequest()618     public void testRegisterCredentialDescription_nullRequest() {
619         assertThrows(
620                 NullPointerException.class,
621                 () -> mCredentialManager.registerCredentialDescription(null));
622     }
623 
624     @Test
testRegisterCredentialDescription_success()625     public void testRegisterCredentialDescription_success() throws RemoteException {
626         mCredentialManager.registerCredentialDescription(mRegisterRequest);
627         verify(mMockCredentialManagerService)
628                 .registerCredentialDescription(same(mRegisterRequest), eq(mPackageName));
629     }
630 
631     @Test
testUnregisterCredentialDescription_nullRequest()632     public void testUnregisterCredentialDescription_nullRequest() {
633         assertThrows(
634                 NullPointerException.class,
635                 () -> mCredentialManager.unregisterCredentialDescription(null));
636     }
637 
638     @Test
testUnregisterCredentialDescription_success()639     public void testUnregisterCredentialDescription_success() throws RemoteException {
640         mCredentialManager.unregisterCredentialDescription(mUnregisterRequest);
641         verify(mMockCredentialManagerService)
642                 .unregisterCredentialDescription(same(mUnregisterRequest), eq(mPackageName));
643     }
644 }
645