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

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

Powered by Google App Engine
This is Rietveld 408576698