Chromium Code Reviews| Index: net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java |
| diff --git a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3e3f9d511e15b5ccffad5bdfde0b757f3fdacec0 |
| --- /dev/null |
| +++ b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java |
| @@ -0,0 +1,168 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.net; |
| + |
| +import static org.hamcrest.CoreMatchers.equalTo; |
| +import static org.hamcrest.CoreMatchers.notNullValue; |
| +import static org.hamcrest.CoreMatchers.nullValue; |
| +import static org.junit.Assert.assertThat; |
| +import static org.junit.Assert.fail; |
| +import static org.mockito.Matchers.anyInt; |
| +import static org.mockito.Matchers.anyLong; |
| +import static org.mockito.Matchers.anyString; |
| +import static org.mockito.Mockito.doNothing; |
| +import static org.mockito.Mockito.mock; |
| +import static org.mockito.Mockito.spy; |
| +import static org.mockito.Mockito.verify; |
| +import static org.mockito.Mockito.when; |
| + |
| +import android.accounts.AccountManager; |
| +import android.accounts.AccountManagerCallback; |
| +import android.accounts.AccountManagerFuture; |
| +import android.accounts.AuthenticatorException; |
| +import android.accounts.OperationCanceledException; |
| +import android.app.Activity; |
| +import android.os.Bundle; |
| +import android.os.Handler; |
| + |
| +import org.chromium.base.BaseChromiumApplication; |
| +import org.chromium.testing.local.LocalRobolectricTestRunner; |
| +import org.junit.Test; |
| +import org.junit.runner.RunWith; |
| +import org.robolectric.Robolectric; |
| +import org.robolectric.annotation.Config; |
| +import org.robolectric.annotation.Implementation; |
| +import org.robolectric.annotation.Implements; |
| +import org.robolectric.shadows.ShadowAccountManager; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Robolectic tests for HttpNegotiateAuthenticator |
|
cbentzel
2015/06/30 12:53:55
Nit: Robolectric
aberent
2015/07/02 21:13:35
Done.
|
| + */ |
| +@RunWith(LocalRobolectricTestRunner.class) |
| +@Config(manifest = Config.NONE, |
| + shadows = HttpNegotiateAuthenticatorTest.ExtendedShadowAccountManager.class, |
| + application = BaseChromiumApplication.class) |
| +public class HttpNegotiateAuthenticatorTest { |
| + static final String KEY_INCOMING_AUTH_TOKEN = "incomingAuthToken"; |
| + static final String KEY_SPNEGO_CONTEXT = "spnegoContext"; |
| + static final String KEY_CAN_DELEGATE = "canDelegate"; |
| + |
| + static final String SPNEGO_FEATURE = "SPNEGO"; |
| + static final String SPNEGO_TOKEN_TYPE_BASE = "SPNEGO:HOSTBASED:"; |
| + |
| + static int sCallCount = 0; |
| + static String sAccountTypeReceived; |
| + static String sAuthTokenTypeReceived; |
| + static String sFeaturesReceived[]; |
| + static Bundle sAddAccountOptionsReceived; |
| + static Bundle sAuthTokenOptionsReceived; |
| + static AccountManagerCallback<Bundle> sCallbackReceived; |
| + static Handler sHandlerReceived; |
| + |
| + /** |
| + * Robolectic's ShadowAccountManager doesn't implement getAccountsByTypeAndFeature so extend it. |
| + * We simply check the call is correct, and don't try to emulate it |
| + * Note: Shadow classes need to be public and static. |
| + */ |
| + @Implements(AccountManager.class) |
| + public static class ExtendedShadowAccountManager extends ShadowAccountManager { |
| + @Implementation |
| + public AccountManagerFuture<Bundle> getAuthTokenByFeatures(String accountType, |
| + String authTokenType, String[] features, Activity activity, |
| + Bundle addAccountOptions, Bundle getAuthTokenOptions, |
| + AccountManagerCallback<Bundle> callback, Handler handler) { |
| + sCallCount++; |
| + sAccountTypeReceived = accountType; |
| + sAuthTokenTypeReceived = authTokenType; |
| + sFeaturesReceived = features; |
| + sAddAccountOptionsReceived = addAccountOptions; |
| + sAuthTokenOptionsReceived = getAuthTokenOptions; |
| + sCallbackReceived = callback; |
| + sHandlerReceived = handler; |
| + |
| + return null; |
| + } |
| + } |
| + |
| + /** |
| + * Test of {@link HttpNegotiateAuthenticator#getNextAuthToken} |
| + */ |
| + @Test |
| + public void testGetNextAuthToken() { |
| + HttpNegotiateAuthenticator authenticator = |
| + HttpNegotiateAuthenticator.create("Dummy_Account"); |
| + Robolectric.buildActivity(Activity.class).create().start().resume().visible(); |
| + authenticator.getNextAuthToken(0, "test_principal", "", true); |
| + assertThat("getAuthTokenByFeatures called precisely once", sCallCount, equalTo(1)); |
| + assertThat("Received account type matches input", sAccountTypeReceived, |
| + equalTo("Dummy_Account")); |
| + assertThat("AuthTokenType is \"SPNEGO:HOSTBASED:test_principal\"", sAuthTokenTypeReceived, |
| + equalTo("SPNEGO:HOSTBASED:test_principal")); |
| + assertThat("Features are precisely {\"SPNEGO\"}", sFeaturesReceived, |
| + equalTo(new String[] {"SPNEGO"})); |
| + assertThat("No account options requested", sAddAccountOptionsReceived, nullValue()); |
| + assertThat("There is no existing context", |
| + sAuthTokenOptionsReceived.get(KEY_SPNEGO_CONTEXT), nullValue()); |
| + assertThat("The existing token is empty", |
| + sAuthTokenOptionsReceived.getString(KEY_INCOMING_AUTH_TOKEN), equalTo("")); |
| + assertThat("Delegation is allowed", sAuthTokenOptionsReceived.getBoolean(KEY_CAN_DELEGATE), |
| + equalTo(true)); |
| + assertThat("getAuthTokenByFeatures was called with a callback", sCallbackReceived, |
| + notNullValue()); |
| + assertThat("getAuthTokenByFeatures was called with a handler", sHandlerReceived, |
| + notNullValue()); |
| + } |
| + |
| + /** |
| + * Test of callback called when getting the auth token completes. |
| + */ |
| + @Test |
| + public void testAccountManagerCallbackRun() { |
| + // Spy on the authenticator so that we can override and intercept the native method call. |
| + HttpNegotiateAuthenticator authenticator = |
| + spy(HttpNegotiateAuthenticator.create("Dummy_Account")); |
| + doNothing().when(authenticator).nativeSetResult(anyLong(), anyInt(), anyString()); |
| + |
| + Robolectric.buildActivity(Activity.class).create().start().resume().visible(); |
| + |
| + // Call getNextAuthToken to get the callback |
| + authenticator.getNextAuthToken(1234, "test_principal", "", true); |
| + |
| + // Avoid warning when creating mock accountManagerFuture, can't take .class of an |
| + // instantiated generic type, yet compiler complains if I leave it uninstantiated. |
| + @SuppressWarnings("unchecked") |
| + AccountManagerFuture<Bundle> accountManagerFuture = mock(AccountManagerFuture.class); |
| + Bundle resultBundle = new Bundle(); |
| + Bundle context = new Bundle(); |
| + context.putString("String", "test_context"); |
| + resultBundle.putBundle(KEY_SPNEGO_CONTEXT, context); |
| + resultBundle.putString(AccountManager.KEY_AUTHTOKEN, "output_token"); |
| + try { |
| + when(accountManagerFuture.getResult()).thenReturn(resultBundle); |
| + } catch (OperationCanceledException | AuthenticatorException | IOException e) { |
| + // Can never happen - artifact of Mockito. |
| + fail(); |
| + } |
| + sCallbackReceived.run(accountManagerFuture); |
| + verify(authenticator).nativeSetResult(1234, 0, "output_token"); |
| + |
| + // Check that the next call to getNextAuthToken uses the correct context |
| + authenticator.getNextAuthToken(5678, "test_principal", "", true); |
| + assertThat("The spnego context is preserved between calls", |
| + sAuthTokenOptionsReceived.getBundle(KEY_SPNEGO_CONTEXT), equalTo(context)); |
| + |
| + // Test exception path |
|
cbentzel
2015/06/30 12:53:55
Should you also test the non-ABORTED error cases?
aberent
2015/07/02 21:13:35
Done.
|
| + try { |
| + when(accountManagerFuture.getResult()).thenThrow(new OperationCanceledException()); |
| + } catch (OperationCanceledException | AuthenticatorException | IOException e) { |
| + // Can never happen - artifact of Mockito. |
| + fail(); |
| + } |
| + sCallbackReceived.run(accountManagerFuture); |
| + verify(authenticator).nativeSetResult(5678, NetError.ERR_ABORTED, null); |
| + } |
| +} |