| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_mediator.h" |
| |
| #import <UIKit/UIKit.h> |
| |
| #import "base/feature_list.h" |
| #import "base/functional/callback_helpers.h" |
| #import "base/strings/sys_string_conversions.h" |
| #import "components/consent_auditor/fake_consent_auditor.h" |
| #import "components/password_manager/core/common/password_manager_features.h" |
| #import "components/sync/test/mock_sync_service.h" |
| #import "components/sync_preferences/pref_service_mock_factory.h" |
| #import "components/sync_preferences/pref_service_syncable.h" |
| #import "ios/chrome/browser/consent_auditor/consent_auditor_factory.h" |
| #import "ios/chrome/browser/consent_auditor/consent_auditor_test_utils.h" |
| #import "ios/chrome/browser/shared/model/application_context/application_context.h" |
| #import "ios/chrome/browser/shared/model/browser/test/test_browser.h" |
| #import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state.h" |
| #import "ios/chrome/browser/signin/authentication_service.h" |
| #import "ios/chrome/browser/signin/authentication_service_factory.h" |
| #import "ios/chrome/browser/signin/chrome_account_manager_service_factory.h" |
| #import "ios/chrome/browser/signin/fake_authentication_service_delegate.h" |
| #import "ios/chrome/browser/signin/fake_system_identity.h" |
| #import "ios/chrome/browser/signin/fake_system_identity_manager.h" |
| #import "ios/chrome/browser/signin/identity_manager_factory.h" |
| #import "ios/chrome/browser/sync/mock_sync_service_utils.h" |
| #import "ios/chrome/browser/sync/sync_service_factory.h" |
| #import "ios/chrome/browser/sync/sync_setup_service_factory.h" |
| #import "ios/chrome/browser/sync/sync_setup_service_mock.h" |
| #import "ios/chrome/browser/ui/authentication/authentication_flow.h" |
| #import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h" |
| #import "ios/chrome/browser/unified_consent/unified_consent_service_factory.h" |
| #import "ios/chrome/grit/ios_strings.h" |
| #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" |
| #import "ios/web/public/test/web_task_environment.h" |
| #import "testing/gmock/include/gmock/gmock.h" |
| #import "testing/platform_test.h" |
| #import "third_party/ocmock/OCMock/OCMock.h" |
| #import "third_party/ocmock/gtest_support.h" |
| #import "third_party/ocmock/ocmock_extensions.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| class UserSigninMediatorTest : public PlatformTest { |
| public: |
| UserSigninMediatorTest() : consent_string_ids_(ExpectedConsentStringIds()) {} |
| |
| void SetUp() override { |
| PlatformTest::SetUp(); |
| identity_ = [FakeSystemIdentity fakeIdentity1]; |
| fake_system_identity_manager()->AddIdentity(identity_); |
| TestChromeBrowserState::Builder builder; |
| builder.AddTestingFactory( |
| AuthenticationServiceFactory::GetInstance(), |
| AuthenticationServiceFactory::GetDefaultFactory()); |
| builder.AddTestingFactory(ConsentAuditorFactory::GetInstance(), |
| base::BindRepeating(&BuildFakeConsentAuditor)); |
| builder.AddTestingFactory(SyncServiceFactory::GetInstance(), |
| base::BindRepeating(&CreateMockSyncService)); |
| builder.AddTestingFactory( |
| SyncSetupServiceFactory::GetInstance(), |
| base::BindRepeating(&SyncSetupServiceMock::CreateKeyedService)); |
| browser_state_ = builder.Build(); |
| |
| AuthenticationServiceFactory::CreateAndInitializeForBrowserState( |
| browser_state_.get(), |
| std::make_unique<FakeAuthenticationServiceDelegate>()); |
| browser_ = std::make_unique<TestBrowser>(browser_state_.get()); |
| |
| mediator_delegate_mock_ = |
| OCMStrictProtocolMock(@protocol(UserSigninMediatorDelegate)); |
| mediator_ = [[UserSigninMediator alloc] |
| initWithAuthenticationService:authentication_service() |
| identityManager:identity_manager() |
| accountManagerService:account_manager_service() |
| consentAuditor:consent_auditor() |
| unifiedConsentService:unified_consent_service() |
| syncSetupService:sync_setup_service() |
| syncService:sync_service()]; |
| |
| mediator_.delegate = mediator_delegate_mock_; |
| |
| fake_consent_auditor_ = |
| static_cast<consent_auditor::FakeConsentAuditor*>(consent_auditor()); |
| sync_setup_service_mock_ = |
| static_cast<SyncSetupServiceMock*>(sync_setup_service()); |
| sync_service_mock_ = static_cast<syncer::MockSyncService*>(sync_service()); |
| } |
| |
| void TearDown() override { |
| [mediator_ disconnect]; |
| EXPECT_OCMOCK_VERIFY((id)mediator_delegate_mock_); |
| EXPECT_OCMOCK_VERIFY((id)performer_mock_); |
| EXPECT_OCMOCK_VERIFY((id)presenting_view_controller_mock_); |
| PlatformTest::TearDown(); |
| } |
| |
| // Sets up the necessary mocks for authentication operations in |
| // `authentication_flow_`. |
| void CreateAuthenticationFlow(PostSignInAction postSignInAction) { |
| presenting_view_controller_mock_ = |
| OCMStrictClassMock([UIViewController class]); |
| performer_mock_ = OCMStrictClassMock([AuthenticationFlowPerformer class]); |
| |
| authentication_flow_ = [[AuthenticationFlow alloc] |
| initWithBrowser:browser_.get() |
| identity:identity_ |
| accessPoint:signin_metrics::AccessPoint:: |
| ACCESS_POINT_UNKNOWN |
| postSignInAction:postSignInAction |
| presentingViewController:presenting_view_controller_mock_]; |
| [authentication_flow_ setPerformerForTesting:performer_mock_]; |
| } |
| |
| // Sets up the sign-in expectations for the AuthenticationFlowPerformer. |
| void SetPerformerSigninExpectations(PostSignInAction postSignInAction) { |
| OCMExpect([performer_mock_ fetchManagedStatus:browser_state_.get() |
| forIdentity:identity_]) |
| .andDo(^(NSInvocation*) { |
| NSLog(@" fetchManagedStatus "); |
| [authentication_flow_ didFetchManagedStatus:nil]; |
| }); |
| OCMExpect( |
| [performer_mock_ |
| signInIdentity:identity_ |
| atAccessPoint:signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN |
| withHostedDomain:nil |
| toBrowserState:browser_state_.get()]) |
| .andDo(^(NSInvocation* invocation) { |
| NSLog(@" signInIdentity "); |
| authentication_service()->SignIn(identity_); |
| }); |
| if (postSignInAction == PostSignInAction::kCommitSync) { |
| OCMExpect( |
| [performer_mock_ |
| shouldHandleMergeCaseForIdentity:identity_ |
| browserStatePrefs:browser_state_->GetPrefs()]) |
| .andReturn(NO); |
| NSLog(@" shouldHandleMergeCaseForIdentity "); |
| } |
| } |
| |
| void SetPerformerSignoutExpectations() { |
| OCMExpect([performer_mock_ signOutBrowserState:browser_state_.get()]) |
| .andDo(^(NSInvocation*) { |
| authentication_service()->SignOut( |
| signin_metrics::ProfileSignout::kTest, false, ^{ |
| [authentication_flow_ didSignOut]; |
| }); |
| }); |
| } |
| |
| // Sets up the sign-in failure expectations for the |
| // AuthenticationFlowPerformer. |
| void SetPerformerFailureExpectations() { |
| NSError* error = [NSError errorWithDomain:@"foo" code:0 userInfo:nil]; |
| OCMExpect([performer_mock_ fetchManagedStatus:browser_state_.get() |
| forIdentity:identity_]) |
| .andDo(^(NSInvocation*) { |
| [authentication_flow_ didFailFetchManagedStatus:error]; |
| }); |
| |
| OCMExpect([performer_mock_ |
| showAuthenticationError:[OCMArg any] |
| withCompletion:[OCMArg any] |
| viewController:presenting_view_controller_mock_ |
| browser:browser_.get()]) |
| .andDo(^(NSInvocation* invocation) { |
| __weak ProceduralBlock completionBlock; |
| [invocation getArgument:&completionBlock atIndex:3]; |
| if (completionBlock) { |
| completionBlock(); |
| } |
| }); |
| } |
| |
| // Sets up the expectations for cancelAndDismissAnimated in the |
| // AuthenticationFlowPerformer. |
| void SetPerformerCancelAndDismissExpectations(BOOL animated) { |
| OCMExpect([performer_mock_ fetchManagedStatus:browser_state_.get() |
| forIdentity:identity_]) |
| .andDo(^(NSInvocation*) { |
| [authentication_flow_ didFetchManagedStatus:nil]; |
| }); |
| OCMExpect([performer_mock_ |
| shouldHandleMergeCaseForIdentity:identity_ |
| browserStatePrefs:browser_state_->GetPrefs()]) |
| .andReturn(YES); |
| OCMExpect([performer_mock_ |
| promptMergeCaseForIdentity:identity_ |
| browser:browser_.get() |
| viewController:presenting_view_controller_mock_]); |
| OCMExpect([performer_mock_ cancelAndDismissAnimated:animated]); |
| } |
| |
| void ExpectNoConsent() { |
| EXPECT_EQ(0ul, fake_consent_auditor_->recorded_id_vectors().size()); |
| EXPECT_EQ(0ul, fake_consent_auditor_->recorded_confirmation_ids().size()); |
| } |
| |
| void ExpectConsent(int consentType) { |
| const std::vector<int>& recorded_ids = |
| fake_consent_auditor_->recorded_id_vectors().at(0); |
| EXPECT_EQ(ExpectedConsentStringIds(), recorded_ids); |
| EXPECT_EQ(consentType, |
| fake_consent_auditor_->recorded_confirmation_ids().at(0)); |
| EXPECT_EQ(consent_auditor::ConsentStatus::GIVEN, |
| fake_consent_auditor_->recorded_statuses().at(0)); |
| EXPECT_EQ(consent_auditor::Feature::CHROME_SYNC, |
| fake_consent_auditor_->recorded_features().at(0)); |
| EXPECT_EQ(identity_manager()->PickAccountIdForAccount( |
| base::SysNSStringToUTF8([identity_ gaiaID]), |
| base::SysNSStringToUTF8([identity_ userEmail])), |
| fake_consent_auditor_->account_id()); |
| } |
| |
| // Returns the list of string id that should be given to RecordGaiaConsent() |
| // then the consent is given. The list is ordered according to the position |
| // on the screen. |
| const std::vector<int> ExpectedConsentStringIds() const { |
| const int sync_dialog_title = |
| base::FeatureList::IsEnabled( |
| password_manager::features::kEnablePasswordsAccountStorage) |
| ? IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_TITLE_WITHOUT_PASSWORDS |
| : IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_TITLE; |
| return { |
| IDS_IOS_ACCOUNT_UNIFIED_CONSENT_TITLE, |
| sync_dialog_title, |
| IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SYNC_SUBTITLE, |
| IDS_IOS_ACCOUNT_UNIFIED_CONSENT_SETTINGS, |
| }; |
| } |
| |
| // Identity services. |
| AuthenticationService* authentication_service() { |
| return AuthenticationServiceFactory::GetForBrowserState( |
| browser_state_.get()); |
| } |
| |
| consent_auditor::ConsentAuditor* consent_auditor() { |
| return ConsentAuditorFactory::GetForBrowserState(browser_state_.get()); |
| } |
| |
| signin::IdentityManager* identity_manager() { |
| return IdentityManagerFactory::GetForBrowserState(browser_state_.get()); |
| } |
| |
| ChromeAccountManagerService* account_manager_service() { |
| return ChromeAccountManagerServiceFactory::GetForBrowserState( |
| browser_state_.get()); |
| } |
| |
| FakeSystemIdentityManager* fake_system_identity_manager() { |
| return FakeSystemIdentityManager::FromSystemIdentityManager( |
| GetApplicationContext()->GetSystemIdentityManager()); |
| } |
| |
| SyncSetupService* sync_setup_service() { |
| return SyncSetupServiceFactory::GetForBrowserState(browser_state_.get()); |
| } |
| |
| syncer::SyncService* sync_service() { |
| return SyncServiceFactory::GetForBrowserState(browser_state_.get()); |
| } |
| |
| unified_consent::UnifiedConsentService* unified_consent_service() { |
| return UnifiedConsentServiceFactory::GetForBrowserState( |
| browser_state_.get()); |
| } |
| |
| protected: |
| // Needed for test browser state created by TestChromeBrowserState(). |
| web::WebTaskEnvironment task_environment_; |
| IOSChromeScopedTestingLocalState scoped_testing_local_state_; |
| id<SystemIdentity> identity_ = nil; |
| |
| AuthenticationFlow* authentication_flow_ = nullptr; |
| std::unique_ptr<Browser> browser_; |
| std::unique_ptr<TestChromeBrowserState> browser_state_; |
| consent_auditor::FakeConsentAuditor* fake_consent_auditor_ = nullptr; |
| const std::vector<int> consent_string_ids_; |
| |
| UserSigninMediator* mediator_ = nil; |
| |
| id<UserSigninMediatorDelegate> mediator_delegate_mock_ = nil; |
| AuthenticationFlowPerformer* performer_mock_ = nil; |
| UIViewController* presenting_view_controller_mock_ = nil; |
| SyncSetupServiceMock* sync_setup_service_mock_ = nullptr; |
| syncer::MockSyncService* sync_service_mock_ = nullptr; |
| }; |
| |
| // Tests a successful authentication for a given identity. |
| TEST_F(UserSigninMediatorTest, AuthenticateWithIdentitySuccess) { |
| CreateAuthenticationFlow(PostSignInAction::kCommitSync); |
| SetPerformerSigninExpectations(PostSignInAction::kCommitSync); |
| |
| // Retrieving coordinator data for the mediator delegate. |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetConsentConfirmationId]) |
| .andReturn(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON); |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorGetConsentStringIds]) |
| .andReturn(&consent_string_ids_); |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(NO); |
| |
| // Sign-in result successful. |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultSuccess]); |
| EXPECT_CALL( |
| *sync_setup_service_mock_, |
| SetFirstSetupComplete(syncer::SyncFirstSetupCompleteSource::BASIC_FLOW)); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| base::RunLoop().RunUntilIdle(); |
| ExpectConsent(IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON); |
| } |
| |
| // Tests authenticating the identity when the settings link has been tapped. |
| TEST_F(UserSigninMediatorTest, AuthenticateWithSettingsLinkTapped) { |
| CreateAuthenticationFlow(PostSignInAction::kCommitSync); |
| SetPerformerSigninExpectations(PostSignInAction::kCommitSync); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(YES); |
| |
| // Sign-in result successful. |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultSuccess]); |
| EXPECT_CALL( |
| *sync_setup_service_mock_, |
| SetFirstSetupComplete(syncer::SyncFirstSetupCompleteSource::BASIC_FLOW)) |
| .Times(0); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| // Tests authentication failure for a given identity. |
| TEST_F(UserSigninMediatorTest, AuthenticateWithIdentityError) { |
| CreateAuthenticationFlow(PostSignInAction::kCommitSync); |
| SetPerformerFailureExpectations(); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(NO); |
| // Returns to sign-in flow. |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFailed]); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| base::RunLoop().RunUntilIdle(); |
| ExpectNoConsent(); |
| } |
| |
| // Tests a user sign-in operation cancel when authentication has not begun. |
| TEST_F(UserSigninMediatorTest, CancelAuthenticationNotInProgress) { |
| // Sign-in result cancel. |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultCanceledByUser]); |
| OCMExpect([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedOut); |
| |
| [mediator_ cancelSignin]; |
| ExpectNoConsent(); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests a user sign-in operation cancel when authentication is in progress. |
| TEST_F(UserSigninMediatorTest, CancelWithAuthenticationInProgress) { |
| SetPerformerCancelAndDismissExpectations(/*animated=*/NO); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(NO); |
| // Unsuccessful sign-in completion updates the primary button. |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultCanceledByUser]); |
| OCMExpect([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedOut); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| [mediator_ cancelSignin]; |
| base::RunLoop().RunUntilIdle(); |
| ExpectNoConsent(); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests a user sign-in operation cancel and dismiss when authentication has not |
| // begun. |
| TEST_F(UserSigninMediatorTest, CancelAndDismissAuthenticationNotInProgress) { |
| OCMExpect([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedOut); |
| __block bool completion_called = false; |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:NO |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| ExpectNoConsent(); |
| EXPECT_TRUE(completion_called); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests a user sign-in operation cancel and dismiss with animation when |
| // authentication is in progress. |
| TEST_F(UserSigninMediatorTest, |
| CancelAndDismissAuthenticationInProgressWithAnimation) { |
| CreateAuthenticationFlow(PostSignInAction::kCommitSync); |
| SetPerformerCancelAndDismissExpectations(/*animated=*/YES); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(NO); |
| // Unsuccessful sign-in completion updates the primary button. |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFailed]); |
| OCMExpect([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedOut); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| __block bool completion_called = false; |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:YES |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| ExpectNoConsent(); |
| EXPECT_TRUE(completion_called); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests a user sign-in operation cancel and dismiss without animation when |
| // authentication is in progress. |
| TEST_F(UserSigninMediatorTest, |
| CancelAndDismissAuthenticationInProgressWithoutAnimation) { |
| CreateAuthenticationFlow(PostSignInAction::kCommitSync); |
| SetPerformerCancelAndDismissExpectations(/*animated=*/NO); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(NO); |
| // Unsuccessful sign-in completion updates the primary button. |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFailed]); |
| OCMExpect([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedOut); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| __block bool completion_called = false; |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:NO |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| ExpectNoConsent(); |
| EXPECT_TRUE(completion_called); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests a user sign-in operation cancel and dismiss without animation when |
| // authentication is in progress. |
| TEST_F(UserSigninMediatorTest, CancelSyncAndStaySignin) { |
| EXPECT_CALL(*sync_service_mock_, StopAndClear()).Times(0); |
| |
| CreateAuthenticationFlow(PostSignInAction::kCommitSync); |
| SetPerformerSigninExpectations(PostSignInAction::kCommitSync); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(YES); |
| |
| // Sign-in result successful. |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultSuccess]); |
| EXPECT_CALL( |
| *sync_setup_service_mock_, |
| SetFirstSetupComplete(syncer::SyncFirstSetupCompleteSource::BASIC_FLOW)) |
| .Times(0); |
| |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| base::RunLoop().RunUntilIdle(); |
| OCMStub([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedInWithSyncDisabled); |
| OCMStub([mediator_delegate_mock_ signinIdentityOnStart]).andReturn(identity_); |
| __block bool completion_called = false; |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:YES |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(completion_called); |
| EXPECT_TRUE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests the following scenario: |
| // * Open the user sign-in dialog to turn on sync, with identity 2 |
| // * Select identity 1 |
| // * Open settings link |
| // * Cancel the user sign-in dialog |
| TEST_F(UserSigninMediatorTest, OpenSettingsLinkWithDifferentIdentityAndCancel) { |
| // Signs in with identity 2. |
| id<SystemIdentity> identity2 = [FakeSystemIdentity fakeIdentity2]; |
| fake_system_identity_manager()->AddIdentity(identity2); |
| authentication_service()->SignIn(identity2); |
| |
| // Opens the settings link with identity 1. |
| CreateAuthenticationFlow(PostSignInAction::kNone); |
| SetPerformerSignoutExpectations(); |
| SetPerformerSigninExpectations(PostSignInAction::kNone); |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(YES); |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultSuccess]); |
| EXPECT_CALL( |
| *sync_setup_service_mock_, |
| SetFirstSetupComplete(syncer::SyncFirstSetupCompleteSource::BASIC_FLOW)) |
| .Times(0); |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| base::RunLoop().RunUntilIdle(); |
| |
| // Cancels the sign-in dialog. |
| OCMStub([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedInWithSyncDisabled); |
| OCMStub([mediator_delegate_mock_ signinIdentityOnStart]).andReturn(identity2); |
| __block bool completion_called = false; |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:YES |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| |
| // Expects to be signed in with identity 2. |
| EXPECT_TRUE(completion_called); |
| EXPECT_TRUE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| EXPECT_TRUE([identity2 isEqual:authentication_service()->GetPrimaryIdentity( |
| signin::ConsentLevel::kSignin)]); |
| } |
| |
| // Tests the following scenario: |
| // * Open the user sign-in dialog to turn on sync, with identity 2 |
| // * Select identity 1 |
| // * Open settings link |
| // * Forget identity 2 (from another Google app) |
| // * Cancel the user sign-in dialog |
| TEST_F(UserSigninMediatorTest, |
| OpenSettingsLinkWithDifferentIdentityAndForgetIdentity) { |
| // Signs in with identity 2. |
| id<SystemIdentity> identity2 = |
| [FakeSystemIdentity identityWithEmail:@"foo2@gmail.com" |
| gaiaID:@"foo2ID" |
| name:@"Fake Foo 2"]; |
| fake_system_identity_manager()->AddIdentity(identity2); |
| authentication_service()->SignIn(identity2); |
| |
| // Opens the settings link with identity 1. |
| CreateAuthenticationFlow(PostSignInAction::kNone); |
| SetPerformerSignoutExpectations(); |
| SetPerformerSigninExpectations(PostSignInAction::kNone); |
| |
| OCMExpect( |
| [mediator_delegate_mock_ userSigninMediatorGetSettingsLinkWasTapped]) |
| .andReturn(YES); |
| OCMExpect([mediator_delegate_mock_ userSigninMediatorSigninFinishedWithResult: |
| SigninCoordinatorResultSuccess]); |
| EXPECT_CALL( |
| *sync_setup_service_mock_, |
| SetFirstSetupComplete(syncer::SyncFirstSetupCompleteSource::BASIC_FLOW)) |
| .Times(0); |
| [mediator_ authenticateWithIdentity:identity_ |
| authenticationFlow:authentication_flow_]; |
| base::RunLoop().RunUntilIdle(); |
| |
| // Forgets identity 2. |
| fake_system_identity_manager()->ForgetIdentity(identity2, base::DoNothing()); |
| |
| // Cancels the sign-in dialog. |
| OCMStub([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedInWithSyncDisabled); |
| OCMStub([mediator_delegate_mock_ signinIdentityOnStart]).andReturn(identity2); |
| __block bool completion_called = false; |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:YES |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| |
| // Expects to be signed out. |
| EXPECT_TRUE(completion_called); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |
| |
| // Tests the following scenario: |
| // * Open the user sign-in dialog to turn on sync, with identity_ |
| // * Forget identity_ |
| // * Cancel the user sign-in dialog |
| TEST_F(UserSigninMediatorTest, ForgetSignedInIdentityWhileTurnOnSyncIsOpened) { |
| fake_system_identity_manager()->ForgetIdentity(identity_, base::DoNothing()); |
| |
| // Cancels the sign-in dialog. |
| __block bool completion_called = false; |
| OCMStub([mediator_delegate_mock_ signinStateOnStart]) |
| .andReturn(IdentitySigninStateSignedInWithSyncDisabled); |
| OCMStub([mediator_delegate_mock_ signinIdentityOnStart]) |
| .andReturn(static_cast<id>(nil)); |
| [mediator_ cancelAndDismissAuthenticationFlowAnimated:YES |
| completion:^() { |
| completion_called = true; |
| }]; |
| base::RunLoop().RunUntilIdle(); |
| |
| // Expects to be signed out. |
| EXPECT_TRUE(completion_called); |
| EXPECT_FALSE(authentication_service()->HasPrimaryIdentity( |
| signin::ConsentLevel::kSignin)); |
| } |