Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java

Issue 1422693002: Make Android HttpNegotiateAuthenticator work without an activity (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@AppStatusWebview
Patch Set: Add more tests Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.net; 5 package org.chromium.net;
6 6
7 import static org.hamcrest.CoreMatchers.equalTo; 7 import static org.hamcrest.CoreMatchers.equalTo;
8 import static org.hamcrest.CoreMatchers.notNullValue; 8 import static org.hamcrest.CoreMatchers.notNullValue;
9 import static org.hamcrest.CoreMatchers.nullValue; 9 import static org.hamcrest.CoreMatchers.nullValue;
10 import static org.junit.Assert.assertThat; 10 import static org.junit.Assert.assertThat;
11 import static org.junit.Assert.fail; 11 import static org.junit.Assert.fail;
12 import static org.mockito.Matchers.any;
12 import static org.mockito.Matchers.anyInt; 13 import static org.mockito.Matchers.anyInt;
13 import static org.mockito.Matchers.anyLong; 14 import static org.mockito.Matchers.anyLong;
14 import static org.mockito.Matchers.anyString; 15 import static org.mockito.Matchers.anyString;
15 import static org.mockito.Matchers.eq; 16 import static org.mockito.Matchers.eq;
17 import static org.mockito.Matchers.isNull;
16 import static org.mockito.Mockito.doNothing; 18 import static org.mockito.Mockito.doNothing;
17 import static org.mockito.Mockito.mock; 19 import static org.mockito.Mockito.mock;
18 import static org.mockito.Mockito.spy; 20 import static org.mockito.Mockito.spy;
21 import static org.mockito.Mockito.times;
19 import static org.mockito.Mockito.verify; 22 import static org.mockito.Mockito.verify;
23 import static org.mockito.Mockito.verifyZeroInteractions;
20 import static org.mockito.Mockito.when; 24 import static org.mockito.Mockito.when;
21 25
26 import android.accounts.Account;
22 import android.accounts.AccountManager; 27 import android.accounts.AccountManager;
23 import android.accounts.AccountManagerCallback; 28 import android.accounts.AccountManagerCallback;
24 import android.accounts.AccountManagerFuture; 29 import android.accounts.AccountManagerFuture;
25 import android.accounts.AuthenticatorException; 30 import android.accounts.AuthenticatorException;
26 import android.accounts.OperationCanceledException; 31 import android.accounts.OperationCanceledException;
27 import android.app.Activity; 32 import android.app.Activity;
33 import android.app.Application;
34 import android.content.BroadcastReceiver;
35 import android.content.Context;
36 import android.content.Intent;
28 import android.os.Bundle; 37 import android.os.Bundle;
29 import android.os.Handler; 38 import android.os.Handler;
30 39
40 import junit.framework.Assert;
41
42 import org.chromium.base.ApplicationStatus;
31 import org.chromium.base.BaseChromiumApplication; 43 import org.chromium.base.BaseChromiumApplication;
32 import org.chromium.base.test.shadows.ShadowMultiDex; 44 import org.chromium.base.test.shadows.ShadowMultiDex;
45 import org.chromium.net.HttpNegotiateAuthenticator.GetAccountsCallback;
46 import org.chromium.net.HttpNegotiateAuthenticator.RequestData;
33 import org.chromium.testing.local.LocalRobolectricTestRunner; 47 import org.chromium.testing.local.LocalRobolectricTestRunner;
48 import org.junit.After;
34 import org.junit.Before; 49 import org.junit.Before;
35 import org.junit.Test; 50 import org.junit.Test;
36 import org.junit.runner.RunWith; 51 import org.junit.runner.RunWith;
52 import org.mockito.ArgumentCaptor;
53 import org.mockito.Captor;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
37 import org.robolectric.Robolectric; 56 import org.robolectric.Robolectric;
38 import org.robolectric.annotation.Config; 57 import org.robolectric.annotation.Config;
39 import org.robolectric.annotation.Implementation; 58 import org.robolectric.annotation.Implementation;
40 import org.robolectric.annotation.Implements; 59 import org.robolectric.annotation.Implements;
41 import org.robolectric.shadows.ShadowAccountManager; 60 import org.robolectric.shadows.ShadowAccountManager;
61 import org.robolectric.shadows.ShadowApplication;
42 62
43 import java.io.IOException; 63 import java.io.IOException;
64 import java.util.List;
44 65
45 /** 66 /**
46 * Robolectric tests for HttpNegotiateAuthenticator 67 * Robolectric tests for HttpNegotiateAuthenticator
47 */ 68 */
48 @RunWith(LocalRobolectricTestRunner.class) 69 @RunWith(LocalRobolectricTestRunner.class)
49 @Config(manifest = Config.NONE, application = BaseChromiumApplication.class, 70 @Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
50 shadows = {HttpNegotiateAuthenticatorTest.ExtendedShadowAccountManager.c lass, 71 shadows = {HttpNegotiateAuthenticatorTest.ExtendedShadowAccountManager.c lass,
51 ShadowMultiDex.class}) 72 ShadowMultiDex.class})
52 public class HttpNegotiateAuthenticatorTest { 73 public class HttpNegotiateAuthenticatorTest {
53 private static class GetAuthTokenByFeaturesInvocation {
dgn 2015/10/30 12:35:39 Not needed anymore since we use Mockito mocks inst
54 // Since the account manager is an SDK singleton (it is fetched using Ac countManager.get()),
55 // we can't validate its method calls with Mockito, so do so using our s hadow method.
56 int mCallCount;
57 String mAccountTypeReceived;
58 String mAuthTokenTypeReceived;
59 String mFeaturesReceived[];
60 Bundle mAddAccountOptionsReceived;
61 Bundle mAuthTokenOptionsReceived;
62 AccountManagerCallback<Bundle> mCallbackReceived;
63 Handler mHandlerReceived;
64
65 public AccountManagerFuture<Bundle> getAuthTokenByFeatures(String accoun tType,
66 String authTokenType, String[] features, Activity activity,
67 Bundle addAccountOptions, Bundle getAuthTokenOptions,
68 AccountManagerCallback<Bundle> callback, Handler handler) {
69 mCallCount++;
70 mAccountTypeReceived = accountType;
71 mAuthTokenTypeReceived = authTokenType;
72 mFeaturesReceived = features;
73 mAddAccountOptionsReceived = addAccountOptions;
74 mAuthTokenOptionsReceived = getAuthTokenOptions;
75 mCallbackReceived = callback;
76 mHandlerReceived = handler;
77
78 return null;
79 }
80 }
81
82 private static GetAuthTokenByFeaturesInvocation sInvocation;
83
84 /** 74 /**
85 * Robolectic's ShadowAccountManager doesn't implement getAccountsByTypeAndF eature so extend it. 75 * User the AccountManager to inject a mock instance.
86 * We simply check the call is correct, and don't try to emulate it. This al so allows us to do
87 * more checking than we could using a vanilla shadow.
88 *
89 * Note: Shadow classes need to be public and static. 76 * Note: Shadow classes need to be public and static.
90 */ 77 */
91 @Implements(AccountManager.class) 78 @Implements(AccountManager.class)
92 public static class ExtendedShadowAccountManager extends ShadowAccountManage r { 79 public static class ExtendedShadowAccountManager extends ShadowAccountManage r {
93 @Implementation 80 @Implementation
94 public AccountManagerFuture<Bundle> getAuthTokenByFeatures(String accoun tType, 81 public static AccountManager get(Context context) {
95 String authTokenType, String[] features, Activity activity, 82 return sMockAccountManager;
96 Bundle addAccountOptions, Bundle getAuthTokenOptions,
97 AccountManagerCallback<Bundle> callback, Handler handler) {
98 return sInvocation.getAuthTokenByFeatures(accountType, authTokenType , features,
99 activity, addAccountOptions, getAuthTokenOptions, callback, handler);
100 } 83 }
101 } 84 }
102 85
86 @Mock
87 private static AccountManager sMockAccountManager;
88 @Captor
89 private ArgumentCaptor<AccountManagerCallback<Bundle>> mBundleCallbackCaptor ;
dgn 2015/10/30 12:35:39 Captors are done that way to avoid unchecked cast
aberent 2015/10/30 16:38:10 nit: Comment to explain this?
dgn 2015/10/30 17:04:40 It's a completely standard way to declare captors,
90 @Captor
91 private ArgumentCaptor<AccountManagerCallback<Account[]>> mAccountCallbackCa ptor;
92 @Captor
93 private ArgumentCaptor<Bundle> mBundleCaptor;
94
103 @Before 95 @Before
104 public void setUp() { 96 public void setUp() {
105 sInvocation = new GetAuthTokenByFeaturesInvocation(); 97 MockitoAnnotations.initMocks(this);
98 }
99
100 @After
101 public void tearDown() {
102 ApplicationStatus.destroyForTesting();
106 } 103 }
107 104
108 /** 105 /**
109 * Test of {@link HttpNegotiateAuthenticator#getNextAuthToken} 106 * Test of {@link HttpNegotiateAuthenticator#getNextAuthToken}
110 */ 107 */
111 @Test 108 @Test
112 public void testGetNextAuthToken() { 109 public void testGetNextAuthToken() {
113 HttpNegotiateAuthenticator authenticator = 110 final String accountType = "Dummy_Account";
114 HttpNegotiateAuthenticator.create("Dummy_Account"); 111 HttpNegotiateAuthenticator authenticator = HttpNegotiateAuthenticator.cr eate(accountType);
115 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble(); 112 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
113
116 authenticator.getNextAuthToken(0, "test_principal", "", true); 114 authenticator.getNextAuthToken(0, "test_principal", "", true);
117 assertThat( 115
118 "getAuthTokenByFeatures called precisely once", sInvocation.mCal lCount, equalTo(1)); 116 verify(sMockAccountManager).getAuthTokenByFeatures(
119 assertThat("Received account type matches input", sInvocation.mAccountTy peReceived, 117 eq(accountType),
120 equalTo("Dummy_Account")); 118 eq("SPNEGO:HOSTBASED:test_principal"),
121 assertThat("AuthTokenType is \"SPNEGO:HOSTBASED:test_principal\"", 119 eq(new String[] {"SPNEGO"}),
122 sInvocation.mAuthTokenTypeReceived, equalTo("SPNEGO:HOSTBASED:te st_principal")); 120 any(Activity.class),
123 assertThat("Features are precisely {\"SPNEGO\"}", sInvocation.mFeaturesR eceived, 121 isNull(Bundle.class),
124 equalTo(new String[] {"SPNEGO"})); 122 mBundleCaptor.capture(),
125 assertThat("No account options requested", sInvocation.mAddAccountOption sReceived, 123 mBundleCallbackCaptor.capture(),
126 nullValue()); 124 any(Handler.class));
125
127 assertThat("There is no existing context", 126 assertThat("There is no existing context",
128 sInvocation.mAuthTokenOptionsReceived.get( 127 mBundleCaptor.getValue().get(HttpNegotiateConstants.KEY_SPNEGO_C ONTEXT),
129 HttpNegotiateConstants.KEY_SPNEGO_CONTEXT),
130 nullValue()); 128 nullValue());
131 assertThat("The existing token is empty", 129 assertThat("The existing token is empty",
132 sInvocation.mAuthTokenOptionsReceived.getString( 130 mBundleCaptor.getValue().getString(HttpNegotiateConstants.KEY_IN COMING_AUTH_TOKEN),
133 HttpNegotiateConstants.KEY_INCOMING_AUTH_TOKEN),
134 equalTo("")); 131 equalTo(""));
135 assertThat("Delegation is allowed", sInvocation.mAuthTokenOptionsReceive d.getBoolean( 132 assertThat("Delegation is allowed",
136 HttpNegotiateConstants.KEY_C AN_DELEGATE), 133 mBundleCaptor.getValue().getBoolean(HttpNegotiateConstants.KEY_C AN_DELEGATE),
137 equalTo(true)); 134 equalTo(true));
138 assertThat("getAuthTokenByFeatures was called with a callback", 135 assertThat("getAuthTokenByFeatures was called with a callback",
139 sInvocation.mCallbackReceived, notNullValue()); 136 mBundleCallbackCaptor.getValue(), notNullValue());
140 assertThat("getAuthTokenByFeatures was called with a handler", sInvocati on.mHandlerReceived,
141 notNullValue());
142 } 137 }
143 138
144 /** 139 /**
140 * Test of {@link HttpNegotiateAuthenticator#getNextAuthToken} without a vis ible activity.
141 * This emulates the behavior with WebView, where the application is a gener ic one and doesn't
142 * set up the ApplicationStatus the same way.
143 */
144 @Test
145 @Config(application = Application.class)
146 public void testGetNextAuthTokenWithoutActivity() {
147 final String accountType = "Dummy_Account";
148 final Account[] returnedAccount = {new Account("name", accountType)};
149 HttpNegotiateAuthenticator authenticator = createWithoutNative(accountTy pe);
150
151 authenticator.getNextAuthToken(1234, "test_principal", "", true);
152
153 Assert.assertNull(ApplicationStatus.getLastTrackedFocusedActivity());
154 verify(sMockAccountManager).getAccountsByTypeAndFeatures(
155 eq(accountType),
156 eq(new String[]{"SPNEGO"}),
157 mAccountCallbackCaptor.capture(),
158 any(Handler.class));
159
160 mAccountCallbackCaptor.getValue().run(makeFuture(returnedAccount));
161
162 verify(sMockAccountManager).getAuthToken(
163 any(Account.class),
164 eq("SPNEGO:HOSTBASED:test_principal"),
165 mBundleCaptor.capture(),
166 eq(true),
167 any(HttpNegotiateAuthenticator.GetTokenCallback.class),
168 any(Handler.class));
169
170 assertThat("There is no existing context",
171 mBundleCaptor.getValue().get(HttpNegotiateConstants.KEY_SPNEGO_C ONTEXT),
172 nullValue());
173 assertThat("The existing token is empty",
174 mBundleCaptor.getValue().getString(HttpNegotiateConstants.KEY_IN COMING_AUTH_TOKEN),
175 equalTo(""));
176 assertThat("Delegation is allowed",
177 mBundleCaptor.getValue().getBoolean(HttpNegotiateConstants.KEY_C AN_DELEGATE),
178 equalTo(true));
179 }
180
181 /** Tests the behavior of {@link HttpNegotiateAuthenticator.GetAccountsCallb ack} */
182 @Test
183 public void testGetAccountCallback() {
184 String type = "Dummy_Account";
185 HttpNegotiateAuthenticator authenticator = createWithoutNative(type);
186 RequestData requestData = new RequestData();
187 requestData.nativeResultObject = 42;
188 requestData.accountManager = sMockAccountManager;
189 GetAccountsCallback callback = authenticator.new GetAccountsCallback(req uestData);
190
191 // Should fail because there are no accounts
192 callback.run(makeFuture(new Account[]{}));
193 verify(authenticator).nativeSetResult(
194 eq(42L),
195 eq(NetError.ERR_UNEXPECTED),
196 isNull(String.class));
197
198 // Should succeed, for a single account we use it for the AccountManager #getAuthToken call.
199 Account testAccount = new Account("a", type);
200 callback.run(makeFuture(new Account[]{testAccount}));
201 verify(sMockAccountManager).getAuthToken(
202 eq(testAccount),
203 anyString(),
204 any(Bundle.class),
205 eq(true),
206 any(HttpNegotiateAuthenticator.GetTokenCallback.class),
207 any(Handler.class));
208
209 // Should fail because there is more than one account
210 callback.run(makeFuture(new Account[]{new Account("a", type), new Accoun t("b", type)}));
211 verify(authenticator, times(2)).nativeSetResult(
212 eq(42L),
213 eq(NetError.ERR_UNEXPECTED),
214 isNull(String.class));
215 }
216
217 /**
218 * Tests the behavior of {@link HttpNegotiateAuthenticator.GetTokenCallback} when the result it
219 * receives contains an intent rather than a token directly.
220 */
221 @Test
222 public void testGetTokenCallbackWithIntent() {
223 String type = "Dummy_Account";
224 HttpNegotiateAuthenticator authenticator = createWithoutNative(type);
225 RequestData requestData = new RequestData();
226 requestData.nativeResultObject = 42;
227 requestData.authTokenType = "foo";
228 requestData.account = new Account("a", type);
229 requestData.accountManager = sMockAccountManager;
230 Bundle b = new Bundle();
231 b.putParcelable(AccountManager.KEY_INTENT, new Intent());
232
233 authenticator.new GetTokenCallback(requestData).run(makeFuture(b));
234 verifyZeroInteractions(sMockAccountManager);
235
236 // Verify that the broadcast receiver is registered
237 Intent intent = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION) ;
238 ShadowApplication shadowApplication = Robolectric.getShadowApplication() ;
239 List<BroadcastReceiver> receivers = shadowApplication.getReceiversForInt ent(intent);
240 assertThat("There is one registered broadcast receiver", receivers.size( ), equalTo(1));
241
242 // Send the intent to the receiver.
243 BroadcastReceiver receiver = receivers.get(0);
244 receiver.onReceive(Robolectric.getShadowApplication().getApplicationCont ext(), intent);
245
246 // Verify that the auth token is properly requested from the account man ager.
247 verify(sMockAccountManager).getAuthToken(
248 eq(new Account("a", type)),
249 eq("foo"),
250 isNull(Bundle.class),
251 eq(true),
252 any(HttpNegotiateAuthenticator.GetTokenCallback.class),
253 any(Handler.class));
254 }
255
256 /**
145 * Test of callback called when getting the auth token completes. 257 * Test of callback called when getting the auth token completes.
146 */ 258 */
147 @Test 259 @Test
148 public void testAccountManagerCallbackRun() { 260 public void testAccountManagerCallbackRun() {
149 // Spy on the authenticator so that we can override and intercept the na tive method call. 261 HttpNegotiateAuthenticator authenticator = createWithoutNative("Dummy_Ac count");
150 HttpNegotiateAuthenticator authenticator =
151 spy(HttpNegotiateAuthenticator.create("Dummy_Account"));
152 doNothing().when(authenticator).nativeSetResult(anyLong(), anyInt(), any String());
153 262
154 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble(); 263 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
155 264
156 // Call getNextAuthToken to get the callback 265 // Call getNextAuthToken to get the callback
157 authenticator.getNextAuthToken(1234, "test_principal", "", true); 266 authenticator.getNextAuthToken(1234, "test_principal", "", true);
267 verify(sMockAccountManager)
268 .getAuthTokenByFeatures(anyString(), anyString(), any(String[].c lass),
269 any(Activity.class), any(Bundle.class), any(Bundle.class ),
270 mBundleCallbackCaptor.capture(), any(Handler.class));
158 271
159 // Avoid warning when creating mock accountManagerFuture, can't take .cl ass of an
160 // instantiated generic type, yet compiler complains if I leave it unins tantiated.
161 @SuppressWarnings("unchecked")
162 AccountManagerFuture<Bundle> accountManagerFuture = mock(AccountManagerF uture.class);
163 Bundle resultBundle = new Bundle(); 272 Bundle resultBundle = new Bundle();
164 Bundle context = new Bundle(); 273 Bundle context = new Bundle();
165 context.putString("String", "test_context"); 274 context.putString("String", "test_context");
166 resultBundle.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, HttpNegoti ateConstants.OK); 275 resultBundle.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, HttpNegoti ateConstants.OK);
167 resultBundle.putBundle(HttpNegotiateConstants.KEY_SPNEGO_CONTEXT, contex t); 276 resultBundle.putBundle(HttpNegotiateConstants.KEY_SPNEGO_CONTEXT, contex t);
168 resultBundle.putString(AccountManager.KEY_AUTHTOKEN, "output_token"); 277 resultBundle.putString(AccountManager.KEY_AUTHTOKEN, "output_token");
278 mBundleCallbackCaptor.getValue().run(makeFuture(resultBundle));
279 verify(authenticator).nativeSetResult(1234, 0, "output_token");
280
281 // Check that the next call to getNextAuthToken uses the correct context
282 authenticator.getNextAuthToken(5678, "test_principal", "", true);
283 verify(sMockAccountManager, times(2))
284 .getAuthTokenByFeatures(anyString(), anyString(), any(String[].c lass),
285 any(Activity.class), any(Bundle.class), mBundleCaptor.ca pture(),
286 mBundleCallbackCaptor.capture(), any(Handler.class));
287
288 assertThat("The spnego context is preserved between calls",
289 mBundleCaptor.getValue().getBundle(HttpNegotiateConstants.KEY_SP NEGO_CONTEXT),
290 equalTo(context));
291
292 // Test exception path
293 mBundleCallbackCaptor.getValue().run(
294 this.<Bundle>makeFuture(new OperationCanceledException()));
295 verify(authenticator).nativeSetResult(5678, NetError.ERR_UNEXPECTED, nul l);
296 }
297
298 @Test
299 public void testAccountManagerCallbackNullErrorReturns() {
300 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
301 checkErrorReturn(null, NetError.ERR_UNEXPECTED);
302 }
303
304 @Test
305 public void testAccountManagerCallbackUnexpectedErrorReturns() {
306 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
307 checkErrorReturn(HttpNegotiateConstants.ERR_UNEXPECTED, NetError.ERR_UNE XPECTED);
308 }
309
310 @Test
311 public void testAccountManagerCallbackAbortedErrorReturns() {
312 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
313 checkErrorReturn(HttpNegotiateConstants.ERR_ABORTED, NetError.ERR_ABORTE D);
314 }
315
316 @Test
317 public void testAccountManagerCallbackSecLibErrorReturns() {
318 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
319 checkErrorReturn(HttpNegotiateConstants.ERR_UNEXPECTED_SECURITY_LIBRARY_ STATUS,
320 NetError.ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS);
321 }
322
323 @Test
324 public void testAccountManagerCallbackInvalidResponseErrorReturns() {
325 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
326 checkErrorReturn(
327 HttpNegotiateConstants.ERR_INVALID_RESPONSE, NetError.ERR_INVALI D_RESPONSE);
328 }
329
330 @Test
331 public void testAccountManagerCallbackInvalidAuthCredsErrorReturns() {
332 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
333 checkErrorReturn(HttpNegotiateConstants.ERR_INVALID_AUTH_CREDENTIALS,
334 NetError.ERR_INVALID_AUTH_CREDENTIALS);
335 }
336
337 @Test
338 public void testAccountManagerCallbackUnsuppAutchSchemeErrorReturns() {
339 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
340 checkErrorReturn(HttpNegotiateConstants.ERR_UNSUPPORTED_AUTH_SCHEME,
341 NetError.ERR_UNSUPPORTED_AUTH_SCHEME);
342 }
343
344 @Test
345 public void testAccountManagerCallbackMissingAuthCredsErrorReturns() {
346 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
347 checkErrorReturn(HttpNegotiateConstants.ERR_MISSING_AUTH_CREDENTIALS,
348 NetError.ERR_MISSING_AUTH_CREDENTIALS);
349 }
350
351 @Test
352 public void testAccountManagerCallbackUndocSecLibErrorReturns() {
353 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
354 checkErrorReturn(HttpNegotiateConstants.ERR_UNDOCUMENTED_SECURITY_LIBRAR Y_STATUS,
355 NetError.ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS);
356 }
357
358 @Test
359 public void testAccountManagerCallbackMalformedIdentityErrorReturns() {
360 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
361 checkErrorReturn(
362 HttpNegotiateConstants.ERR_MALFORMED_IDENTITY, NetError.ERR_MALF ORMED_IDENTITY);
363 }
364
365 @Test
366 public void testAccountManagerCallbackInvalidErrorReturns() {
367 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
368 // 9999 is not a valid return value
369 checkErrorReturn(9999, NetError.ERR_UNEXPECTED);
370 }
371
372 private void checkErrorReturn(Integer spnegoError, int expectedError) {
373 HttpNegotiateAuthenticator authenticator = createWithoutNative("Dummy_Ac count");
374
375 // Call getNextAuthToken to get the callback
376 authenticator.getNextAuthToken(1234, "test_principal", "", true);
377 verify(sMockAccountManager).getAuthTokenByFeatures(
378 anyString(),
379 anyString(),
380 any(String[].class),
381 any(Activity.class),
382 any(Bundle.class),
383 any(Bundle.class),
384 mBundleCallbackCaptor.capture(),
385 any(Handler.class));
386
387 Bundle resultBundle = new Bundle();
388 if (spnegoError != null) {
389 resultBundle.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, spnego Error);
390 }
391 mBundleCallbackCaptor.getValue().run(makeFuture(resultBundle));
392 verify(authenticator).nativeSetResult(anyLong(), eq(expectedError), anyS tring());
393 }
394
395 /**
396 * Returns a future that successfully returns the provided result.
397 * Hides mocking related annoyances: compiler warnings and irrelevant catch clauses.
398 */
399 private <T> AccountManagerFuture<T> makeFuture(T result) {
400 // Avoid warning when creating mock accountManagerFuture, can't take .cl ass of an
401 // instantiated generic type, yet compiler complains if I leave it unins tantiated.
402 @SuppressWarnings("unchecked")
403 AccountManagerFuture<T> accountManagerFuture = mock(AccountManagerFuture .class);
169 try { 404 try {
170 when(accountManagerFuture.getResult()).thenReturn(resultBundle); 405 when(accountManagerFuture.getResult()).thenReturn(result);
171 } catch (OperationCanceledException | AuthenticatorException | IOExcepti on e) { 406 } catch (OperationCanceledException | AuthenticatorException | IOExcepti on e) {
172 // Can never happen - artifact of Mockito. 407 // Can never happen - artifact of Mockito.
173 fail(); 408 fail();
174 } 409 }
175 sInvocation.mCallbackReceived.run(accountManagerFuture); 410 return accountManagerFuture;
176 verify(authenticator).nativeSetResult(1234, 0, "output_token"); 411 }
177 412
178 // Check that the next call to getNextAuthToken uses the correct context 413 /**
179 authenticator.getNextAuthToken(5678, "test_principal", "", true); 414 * Returns a future that fails with the provided exception when trying to ge t its result.
180 assertThat("The spnego context is preserved between calls", 415 * Hides mocking related annoyances: compiler warnings and irrelevant catch clauses.
181 sInvocation.mAuthTokenOptionsReceived.getBundle( 416 */
182 HttpNegotiateConstants.KEY_SPNEGO_CONTEXT), 417 private <T> AccountManagerFuture<T> makeFuture(Exception ex) {
183 equalTo(context)); 418 // Avoid warning when creating mock accountManagerFuture, can't take .cl ass of an
184 419 // instantiated generic type, yet compiler complains if I leave it unins tantiated.
185 // Test exception path 420 @SuppressWarnings("unchecked")
421 AccountManagerFuture<T> accountManagerFuture = mock(AccountManagerFuture .class);
186 try { 422 try {
187 when(accountManagerFuture.getResult()).thenThrow(new OperationCancel edException()); 423 when(accountManagerFuture.getResult()).thenThrow(ex);
188 } catch (OperationCanceledException | AuthenticatorException | IOExcepti on e) { 424 } catch (OperationCanceledException | AuthenticatorException | IOExcepti on e) {
189 // Can never happen - artifact of Mockito. 425 // Can never happen - artifact of Mockito.
190 fail(); 426 fail();
191 } 427 }
192 sInvocation.mCallbackReceived.run(accountManagerFuture); 428 return accountManagerFuture;
193 verify(authenticator).nativeSetResult(5678, NetError.ERR_ABORTED, null);
194 }
195
196 private void checkErrorReturn(Integer spnegoError, int expectedError) {
197 // Spy on the authenticator so that we can override and intercept the na tive method call.
198 HttpNegotiateAuthenticator authenticator =
199 spy(HttpNegotiateAuthenticator.create("Dummy_Account"));
200 doNothing().when(authenticator).nativeSetResult(anyLong(), anyInt(), any String());
201
202 Robolectric.buildActivity(Activity.class).create().start().resume().visi ble();
203
204 // Call getNextAuthToken to get the callback
205 authenticator.getNextAuthToken(1234, "test_principal", "", true);
206
207 // Avoid warning when creating mock accountManagerFuture, can't take .cl ass of an
208 // instantiated generic type, yet compiler complains if I leave it unins tantiated.
209 @SuppressWarnings("unchecked")
210 AccountManagerFuture<Bundle> accountManagerFuture = mock(AccountManagerF uture.class);
211 Bundle resultBundle = new Bundle();
212 if (spnegoError != null) {
213 resultBundle.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, spnego Error);
214 }
215 try {
216 when(accountManagerFuture.getResult()).thenReturn(resultBundle);
217 } catch (OperationCanceledException | AuthenticatorException | IOExcepti on e) {
218 // Can never happen - artifact of Mockito.
219 fail();
220 }
221 sInvocation.mCallbackReceived.run(accountManagerFuture);
222 verify(authenticator).nativeSetResult(anyLong(), eq(expectedError), anyS tring());
223 } 429 }
224 430
225 /** 431 /**
226 * Test of callback error returns when getting the auth token completes. 432 * Returns a new authenticator as a spy so that we can override and intercep t the native method
433 * calls.
227 */ 434 */
228 @Test 435 private HttpNegotiateAuthenticator createWithoutNative(String accountType) {
229 public void testAccountManagerCallbackErrorReturns() { 436 HttpNegotiateAuthenticator authenticator =
dgn 2015/10/30 12:35:39 Split to reset the state of the mocks between test
230 checkErrorReturn(null, NetError.ERR_UNEXPECTED); 437 spy(HttpNegotiateAuthenticator.create(accountType));
231 checkErrorReturn(HttpNegotiateConstants.ERR_UNEXPECTED, NetError.ERR_UNE XPECTED); 438 doNothing().when(authenticator).nativeSetResult(anyLong(), anyInt(), any String());
232 checkErrorReturn(HttpNegotiateConstants.ERR_ABORTED, NetError.ERR_ABORTE D); 439 return authenticator;
233 checkErrorReturn(HttpNegotiateConstants.ERR_UNEXPECTED_SECURITY_LIBRARY_ STATUS,
234 NetError.ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS);
235 checkErrorReturn(
236 HttpNegotiateConstants.ERR_INVALID_RESPONSE, NetError.ERR_INVALI D_RESPONSE);
237 checkErrorReturn(HttpNegotiateConstants.ERR_INVALID_AUTH_CREDENTIALS,
238 NetError.ERR_INVALID_AUTH_CREDENTIALS);
239 checkErrorReturn(HttpNegotiateConstants.ERR_UNSUPPORTED_AUTH_SCHEME,
240 NetError.ERR_UNSUPPORTED_AUTH_SCHEME);
241 checkErrorReturn(HttpNegotiateConstants.ERR_MISSING_AUTH_CREDENTIALS,
242 NetError.ERR_MISSING_AUTH_CREDENTIALS);
243 checkErrorReturn(HttpNegotiateConstants.ERR_UNDOCUMENTED_SECURITY_LIBRAR Y_STATUS,
244 NetError.ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS);
245 checkErrorReturn(
246 HttpNegotiateConstants.ERR_MALFORMED_IDENTITY, NetError.ERR_MALF ORMED_IDENTITY);
247 // 9999 is not a valid return value
248 checkErrorReturn(9999, NetError.ERR_UNEXPECTED);
249 } 440 }
250 } 441 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698