Commit 90d7ab3f authored by Alice Wang's avatar Alice Wang Committed by Chromium LUCI CQ

[Android][Signin] Refactor and test ForcedSigninProcessor

This CL refactors and tests ForcedSigninProcessor.

Bug: 1045525
Change-Id: Id4948e2c546ddb7e0bee374e5ff2fdf5530f6afa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2617941
Commit-Queue: Alice Wang <aliceywang@chromium.org>
Reviewed-by: default avatarTanmoy Mollik <triploblastic@chromium.org>
Reviewed-by: default avatarWenyu Fu <wenyufu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842465}
parent 636bacc6
...@@ -91,6 +91,7 @@ chrome_junit_test_java_sources = [ ...@@ -91,6 +91,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/firstrun/FirstRunAppRestrictionInfoTest.java", "junit/src/org/chromium/chrome/browser/firstrun/FirstRunAppRestrictionInfoTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java", "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java", "junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessorTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java", "junit/src/org/chromium/chrome/browser/firstrun/PolicyLoadListenerUnitTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/SkipTosDialogPolicyListenerUnitTest.java", "junit/src/org/chromium/chrome/browser/firstrun/SkipTosDialogPolicyListenerUnitTest.java",
"junit/src/org/chromium/chrome/browser/firstrun/TosDialogBehaviorSharedPrefInvalidatorUnitTest.java", "junit/src/org/chromium/chrome/browser/firstrun/TosDialogBehaviorSharedPrefInvalidatorUnitTest.java",
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
package org.chromium.chrome.browser.firstrun; package org.chromium.chrome.browser.firstrun;
import android.accounts.Account;
import android.app.Activity; import android.app.Activity;
import org.chromium.base.Log;
import org.chromium.chrome.browser.SyncFirstSetupCompleteSource; import org.chromium.chrome.browser.SyncFirstSetupCompleteSource;
import org.chromium.chrome.browser.childaccounts.ChildAccountService; import org.chromium.chrome.browser.childaccounts.ChildAccountService;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
...@@ -20,28 +20,28 @@ import org.chromium.components.signin.AccountManagerFacadeProvider; ...@@ -20,28 +20,28 @@ import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.ChildAccountStatus; import org.chromium.components.signin.ChildAccountStatus;
import org.chromium.components.signin.metrics.SigninAccessPoint; import org.chromium.components.signin.metrics.SigninAccessPoint;
import java.util.List;
/** /**
* A helper to perform all necessary steps for forced sign in. * A helper to perform all necessary steps for forced sign in.
* The helper performs: * The helper performs:
* - necessary child account checks; * - necessary child account checks;
* - automatic non-interactive forced sign in for child accounts; and * - automatic non-interactive sign in for child accounts; and
* The helper calls the observer's onSignInComplete() if * The helper calls the observer's onSignInComplete() if
* - nothing needs to be done, or when * - nothing needs to be done, or when
* - the sign in is complete. * - the sign in is complete.
* *
* Usage: * Usage:
* ForcedSigninProcessor.start(appContext). * ForcedSigninProcessor.start().
*/ */
public final class ForcedSigninProcessor { public final class ForcedSigninProcessor {
private static final String TAG = "ForcedSignin";
/* /*
* Only for static usage. * Only for static usage.
*/ */
private ForcedSigninProcessor() {} private ForcedSigninProcessor() {}
/** /**
* Check whether a forced automatic signin is required and process it if it is. * Check whether an automatic signin is required and process it if it is.
* This is triggered once per Chrome Application lifetime and every time the Account state * This is triggered once per Chrome Application lifetime and every time the Account state
* changes with early exit if an account has already been signed in. * changes with early exit if an account has already been signed in.
*/ */
...@@ -50,37 +50,32 @@ public final class ForcedSigninProcessor { ...@@ -50,37 +50,32 @@ public final class ForcedSigninProcessor {
boolean hasChildAccount = ChildAccountStatus.isChild(status); boolean hasChildAccount = ChildAccountStatus.isChild(status);
AccountManagementFragment.setSignOutAllowedPreferenceValue(!hasChildAccount); AccountManagementFragment.setSignOutAllowedPreferenceValue(!hasChildAccount);
if (hasChildAccount) { if (hasChildAccount) {
processForcedSignIn(); // Account cache is already available when child account status is ready.
final List<Account> accounts =
AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts();
assert accounts.size() == 1 : "Child account should be the only account on device!";
signinAndEnableSync(accounts.get(0));
} }
}); });
} }
/** /**
* Processes the fully automatic non-FRE-related forced sign-in. * Processes the fully automatic non-FRE-related forced sign-in.
* This is used to enforce the environment for Android EDU and child accounts. * This is used to enforce the environment for child accounts.
*/ */
private static void processForcedSignIn() { private static void signinAndEnableSync(final Account childAccount) {
final Profile profile = Profile.getLastUsedRegularProfile(); final Profile profile = Profile.getLastUsedRegularProfile();
if (FirstRunUtils.canAllowSync() if (FirstRunUtils.canAllowSync()
&& IdentityServicesProvider.get().getIdentityManager(profile).hasPrimaryAccount()) { && IdentityServicesProvider.get().getIdentityManager(profile).hasPrimaryAccount()) {
// TODO(https://crbug.com/1044206): Remove this. // TODO(https://crbug.com/1044206): Remove this.
ProfileSyncService.get().setFirstSetupComplete(SyncFirstSetupCompleteSource.BASIC_FLOW); ProfileSyncService.get().setFirstSetupComplete(SyncFirstSetupCompleteSource.BASIC_FLOW);
} }
final SigninManager signinManager = final SigninManager signinManager =
IdentityServicesProvider.get().getSigninManager(profile); IdentityServicesProvider.get().getSigninManager(profile);
// By definition we have finished all the checks for first run. // By definition we have finished all the checks for first run.
signinManager.onFirstRunCheckDone(); signinManager.onFirstRunCheckDone();
if (!FirstRunUtils.canAllowSync() || !signinManager.isSignInAllowed()) { if (FirstRunUtils.canAllowSync() && signinManager.isSignInAllowed()) {
Log.d(TAG, "Sign in disallowed"); signinManager.signinAndEnableSync(SigninAccessPoint.FORCED_SIGNIN, childAccount,
return;
}
AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts(accounts -> {
if (accounts.size() != 1) {
Log.d(TAG, "Incorrect number of accounts (%d)", accounts.size());
return;
}
signinManager.signinAndEnableSync(SigninAccessPoint.FORCED_SIGNIN, accounts.get(0),
new SigninManager.SignInCallback() { new SigninManager.SignInCallback() {
@Override @Override
public void onSignInComplete() { public void onSignInComplete() {
...@@ -92,7 +87,7 @@ public final class ForcedSigninProcessor { ...@@ -92,7 +87,7 @@ public final class ForcedSigninProcessor {
@Override @Override
public void onSignInAborted() {} public void onSignInAborted() {}
}); });
}); }
} }
/** /**
......
// Copyright 2021 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.chrome.browser.firstrun;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accounts.Account;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.SyncFirstSetupCompleteSource;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.chrome.browser.signin.services.SigninManager;
import org.chromium.chrome.browser.signin.services.SigninManager.SignInCallback;
import org.chromium.chrome.browser.sync.ProfileSyncService;
import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
import org.chromium.components.signin.AccountUtils;
import org.chromium.components.signin.ChildAccountStatus;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.components.signin.metrics.SigninAccessPoint;
import org.chromium.components.signin.test.util.FakeAccountManagerFacade;
/**
* JUnit tests for {@link ForcedSigninProcessor}.
*/
@RunWith(BaseRobolectricTestRunner.class)
public class ForcedSigninProcessorTest {
private static final Account CHILD_ACCOUNT =
AccountUtils.createAccountFromName("child.account@gmail.com");
private final FakeAccountManagerFacade mFakeFacade = new FakeAccountManagerFacade(null) {
@Override
public void checkChildAccountStatus(Account account, ChildAccountStatusListener listener) {
listener.onStatusReady(account.equals(CHILD_ACCOUNT) ? ChildAccountStatus.REGULAR_CHILD
: ChildAccountStatus.NOT_CHILD);
}
};
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
public final AccountManagerTestRule mAccountManagerTestRule =
new AccountManagerTestRule(mFakeFacade);
@Mock
private Profile mProfileMock;
@Mock
private ProfileSyncService mProfileSyncServiceMock;
@Mock
private SigninManager mSigninManagerMock;
@Mock
private IdentityManager mIdentityManagerMock;
@Before
public void setUp() {
Profile.setLastUsedProfileForTesting(mProfileMock);
ProfileSyncService.overrideForTests(mProfileSyncServiceMock);
IdentityServicesProvider.setInstanceForTests(mock(IdentityServicesProvider.class));
when(IdentityServicesProvider.get().getIdentityManager(mProfileMock))
.thenReturn(mIdentityManagerMock);
when(mIdentityManagerMock.hasPrimaryAccount()).thenReturn(false);
when(IdentityServicesProvider.get().getSigninManager(mProfileMock))
.thenReturn(mSigninManagerMock);
doAnswer(invocation -> {
SignInCallback callback = invocation.getArgument(2);
callback.onSignInComplete();
return null;
})
.when(mSigninManagerMock)
.signinAndEnableSync(anyInt(), any(Account.class), notNull());
}
@Test
public void testStartWhenMoreThanOneAccountsOnDevice() {
mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
mAccountManagerTestRule.addAccount("adult.account@gmail.com");
ForcedSigninProcessor.start();
verify(mSigninManagerMock, never()).onFirstRunCheckDone();
}
@Test
public void testStartWhenAdultAccountOnDevice() {
mAccountManagerTestRule.addAccount("adult.account@gmail.com");
ForcedSigninProcessor.start();
verify(mSigninManagerMock, never()).onFirstRunCheckDone();
}
@Test
public void testStartWhenSigninNotAllowed() {
mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
when(mSigninManagerMock.isSignInAllowed()).thenReturn(false);
ForcedSigninProcessor.start();
verify(mSigninManagerMock).onFirstRunCheckDone();
verify(mSigninManagerMock, never())
.signinAndEnableSync(anyInt(), any(Account.class), any());
verify(mProfileSyncServiceMock, never())
.setFirstSetupComplete(SyncFirstSetupCompleteSource.BASIC_FLOW);
}
@Test
public void testStartWhenSigninAllowed() {
mAccountManagerTestRule.addAccount(CHILD_ACCOUNT);
when(mSigninManagerMock.isSignInAllowed()).thenReturn(true);
ForcedSigninProcessor.start();
verify(mSigninManagerMock).onFirstRunCheckDone();
verify(mSigninManagerMock)
.signinAndEnableSync(
eq(SigninAccessPoint.FORCED_SIGNIN), eq(CHILD_ACCOUNT), notNull());
verify(mProfileSyncServiceMock)
.setFirstSetupComplete(SyncFirstSetupCompleteSource.BASIC_FLOW);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment