OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/ui/authentication/authentication_flow.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #import "base/mac/scoped_block.h" |
| 10 #import "base/mac/scoped_nsobject.h" |
| 11 #include "base/memory/ptr_util.h" |
| 12 #include "base/test/ios/wait_util.h" |
| 13 #include "components/pref_registry/pref_registry_syncable.h" |
| 14 #include "components/sync_preferences/pref_service_mock_factory.h" |
| 15 #include "components/sync_preferences/pref_service_syncable.h" |
| 16 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" |
| 17 #include "ios/chrome/browser/prefs/browser_prefs.h" |
| 18 #include "ios/chrome/browser/signin/authentication_service_factory.h" |
| 19 #import "ios/chrome/browser/signin/authentication_service_fake.h" |
| 20 #import "ios/chrome/browser/ui/authentication/authentication_flow_performer.h" |
| 21 #include "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service
.h" |
| 22 #include "ios/web/public/test/test_web_thread_bundle.h" |
| 23 #import "testing/gtest_mac.h" |
| 24 #import "testing/platform_test.h" |
| 25 #import "third_party/ocmock/gtest_support.h" |
| 26 #import "third_party/ocmock/ocmock_extensions.h" |
| 27 #include "ui/base/l10n/l10n_util.h" |
| 28 |
| 29 namespace { |
| 30 |
| 31 class AuthenticationFlowTest : public PlatformTest { |
| 32 protected: |
| 33 void SetUp() override { |
| 34 PlatformTest::SetUp(); |
| 35 |
| 36 TestChromeBrowserState::Builder builder; |
| 37 builder.AddTestingFactory( |
| 38 AuthenticationServiceFactory::GetInstance(), |
| 39 AuthenticationServiceFake::CreateAuthenticationService); |
| 40 builder.SetPrefService(CreatePrefService()); |
| 41 browser_state_ = builder.Build(); |
| 42 ios::FakeChromeIdentityService* identityService = |
| 43 ios::FakeChromeIdentityService::GetInstanceFromChromeProvider(); |
| 44 identityService->AddIdentities(@[ @"identity1", @"identity2" ]); |
| 45 identity1_ = |
| 46 [identityService->GetAllIdentitiesSortedForDisplay() objectAtIndex:0]; |
| 47 identity2_ = |
| 48 [identityService->GetAllIdentitiesSortedForDisplay() objectAtIndex:1]; |
| 49 sign_in_completion_.reset( |
| 50 ^(BOOL success) { |
| 51 finished_ = true; |
| 52 signed_in_success_ = success; |
| 53 }, |
| 54 base::scoped_policy::RETAIN); |
| 55 finished_ = false; |
| 56 signed_in_success_ = false; |
| 57 } |
| 58 |
| 59 std::unique_ptr<sync_preferences::PrefServiceSyncable> CreatePrefService() { |
| 60 sync_preferences::PrefServiceMockFactory factory; |
| 61 scoped_refptr<user_prefs::PrefRegistrySyncable> registry( |
| 62 new user_prefs::PrefRegistrySyncable); |
| 63 std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs = |
| 64 factory.CreateSyncable(registry.get()); |
| 65 RegisterBrowserStatePrefs(registry.get()); |
| 66 return prefs; |
| 67 } |
| 68 |
| 69 AuthenticationFlowPerformer* GetAuthenticationFlowPerformer() { |
| 70 return static_cast<AuthenticationFlowPerformer*>(performer_.get()); |
| 71 } |
| 72 |
| 73 // Creates a new AuthenticationFlow with default values for fields that are |
| 74 // not directly useful. |
| 75 void CreateAuthenticationFlow(ShouldClearData shouldClearData, |
| 76 PostSignInAction postSignInAction) { |
| 77 ChromeIdentity* identity = identity1_; |
| 78 view_controller_.reset( |
| 79 [[OCMockObject niceMockForClass:[UIViewController class]] retain]); |
| 80 authentication_flow_.reset([[AuthenticationFlow alloc] |
| 81 initWithBrowserState:browser_state_.get() |
| 82 identity:identity |
| 83 shouldClearData:shouldClearData |
| 84 postSignInAction:postSignInAction |
| 85 presentingViewController:view_controller_]); |
| 86 performer_.reset([[OCMockObject |
| 87 mockForClass:[AuthenticationFlowPerformer class]] retain]); |
| 88 [authentication_flow_ |
| 89 setPerformerForTesting:GetAuthenticationFlowPerformer()]; |
| 90 } |
| 91 |
| 92 // Checks if the AuthenticationFlow operation has completed, and whether it |
| 93 // was successful. |
| 94 void CheckSignInCompletion(bool expectedSignedIn) { |
| 95 base::test::ios::WaitUntilCondition(^bool { |
| 96 return finished_; |
| 97 }); |
| 98 EXPECT_EQ(true, finished_); |
| 99 EXPECT_EQ(expectedSignedIn, signed_in_success_); |
| 100 [performer_ verify]; |
| 101 } |
| 102 |
| 103 web::TestWebThreadBundle thread_bundle_; |
| 104 base::scoped_nsobject<AuthenticationFlow> authentication_flow_; |
| 105 std::unique_ptr<TestChromeBrowserState> browser_state_; |
| 106 ChromeIdentity* identity1_; |
| 107 ChromeIdentity* identity2_; |
| 108 base::scoped_nsobject<OCMockObject> performer_; |
| 109 base::mac::ScopedBlock<signin_ui::CompletionCallback> sign_in_completion_; |
| 110 base::scoped_nsobject<UIViewController> view_controller_; |
| 111 |
| 112 // State of the flow |
| 113 bool finished_; |
| 114 bool signed_in_success_; |
| 115 }; |
| 116 |
| 117 // Tests a Sign In of a normal account on the same profile, merging user data |
| 118 // and showing the sync settings. |
| 119 TEST_F(AuthenticationFlowTest, TestSignInSimple) { |
| 120 CreateAuthenticationFlow(SHOULD_CLEAR_DATA_MERGE_DATA, |
| 121 POST_SIGNIN_ACTION_START_SYNC); |
| 122 |
| 123 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 124 [authentication_flow_ didFetchManagedStatus:nil]; |
| 125 }] fetchManagedStatus:browser_state_.get() |
| 126 forIdentity:identity1_]; |
| 127 |
| 128 [[[performer_ expect] andReturnBool:NO] |
| 129 shouldHandleMergeCaseForIdentity:identity1_ |
| 130 browserState:browser_state_.get()]; |
| 131 |
| 132 [[performer_ expect] signInIdentity:identity1_ |
| 133 withHostedDomain:nil |
| 134 toBrowserState:browser_state_.get()]; |
| 135 |
| 136 [[performer_ expect] commitSyncForBrowserState:browser_state_.get()]; |
| 137 |
| 138 [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; |
| 139 |
| 140 CheckSignInCompletion(true); |
| 141 } |
| 142 |
| 143 // Tests that signing in an already signed in account correctly signs it out |
| 144 // and back in. |
| 145 TEST_F(AuthenticationFlowTest, TestAlreadySignedIn) { |
| 146 CreateAuthenticationFlow(SHOULD_CLEAR_DATA_MERGE_DATA, |
| 147 POST_SIGNIN_ACTION_NONE); |
| 148 |
| 149 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 150 [authentication_flow_ didFetchManagedStatus:nil]; |
| 151 }] fetchManagedStatus:browser_state_.get() |
| 152 forIdentity:identity1_]; |
| 153 |
| 154 [[[performer_ expect] andReturnBool:NO] |
| 155 shouldHandleMergeCaseForIdentity:identity1_ |
| 156 browserState:browser_state_.get()]; |
| 157 |
| 158 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 159 [authentication_flow_ didSignOut]; |
| 160 }] signOutBrowserState:browser_state_.get()]; |
| 161 |
| 162 [[performer_ expect] signInIdentity:identity1_ |
| 163 withHostedDomain:nil |
| 164 toBrowserState:browser_state_.get()]; |
| 165 |
| 166 AuthenticationServiceFactory::GetForBrowserState(browser_state_.get()) |
| 167 ->SignIn(identity1_, std::string()); |
| 168 [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; |
| 169 |
| 170 CheckSignInCompletion(true); |
| 171 } |
| 172 |
| 173 // Tests a Sign In of a different account, requiring a sign out of the already |
| 174 // signed in account, and asking the user whether data should be cleared or |
| 175 // merged. |
| 176 TEST_F(AuthenticationFlowTest, TestSignOutUserChoice) { |
| 177 CreateAuthenticationFlow(SHOULD_CLEAR_DATA_USER_CHOICE, |
| 178 POST_SIGNIN_ACTION_START_SYNC); |
| 179 |
| 180 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 181 [authentication_flow_ didFetchManagedStatus:nil]; |
| 182 }] fetchManagedStatus:browser_state_.get() |
| 183 forIdentity:identity1_]; |
| 184 |
| 185 [[[performer_ expect] andReturnBool:YES] |
| 186 shouldHandleMergeCaseForIdentity:identity1_ |
| 187 browserState:browser_state_.get()]; |
| 188 |
| 189 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 190 [authentication_flow_ |
| 191 didChooseClearDataPolicy:SHOULD_CLEAR_DATA_CLEAR_DATA]; |
| 192 }] promptMergeCaseForIdentity:identity1_ |
| 193 browserState:browser_state_.get() |
| 194 viewController:view_controller_]; |
| 195 |
| 196 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 197 [authentication_flow_ didSignOut]; |
| 198 }] signOutBrowserState:browser_state_.get()]; |
| 199 |
| 200 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 201 [authentication_flow_ didClearData]; |
| 202 }] clearData:browser_state_.get()]; |
| 203 |
| 204 [[performer_ expect] signInIdentity:identity1_ |
| 205 withHostedDomain:nil |
| 206 toBrowserState:browser_state_.get()]; |
| 207 |
| 208 [[performer_ expect] commitSyncForBrowserState:browser_state_.get()]; |
| 209 |
| 210 AuthenticationServiceFactory::GetForBrowserState(browser_state_.get()) |
| 211 ->SignIn(identity2_, std::string()); |
| 212 [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; |
| 213 |
| 214 CheckSignInCompletion(true); |
| 215 } |
| 216 |
| 217 // Tests the cancelling of a Sign In. |
| 218 TEST_F(AuthenticationFlowTest, TestCancel) { |
| 219 CreateAuthenticationFlow(SHOULD_CLEAR_DATA_USER_CHOICE, |
| 220 POST_SIGNIN_ACTION_START_SYNC); |
| 221 |
| 222 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 223 [authentication_flow_ didFetchManagedStatus:nil]; |
| 224 }] fetchManagedStatus:browser_state_.get() |
| 225 forIdentity:identity1_]; |
| 226 |
| 227 [[[performer_ expect] andReturnBool:YES] |
| 228 shouldHandleMergeCaseForIdentity:identity1_ |
| 229 browserState:browser_state_.get()]; |
| 230 |
| 231 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 232 [authentication_flow_ cancelAndDismiss]; |
| 233 }] promptMergeCaseForIdentity:identity1_ |
| 234 browserState:browser_state_.get() |
| 235 viewController:view_controller_]; |
| 236 |
| 237 [[performer_ expect] cancelAndDismiss]; |
| 238 |
| 239 [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; |
| 240 |
| 241 CheckSignInCompletion(false); |
| 242 } |
| 243 |
| 244 // Tests the fetch managed status failure case. |
| 245 TEST_F(AuthenticationFlowTest, TestFailFetchManagedStatus) { |
| 246 CreateAuthenticationFlow(SHOULD_CLEAR_DATA_MERGE_DATA, |
| 247 POST_SIGNIN_ACTION_START_SYNC); |
| 248 |
| 249 NSError* error = [NSError errorWithDomain:@"foo" code:0 userInfo:nil]; |
| 250 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 251 [authentication_flow_ didFailFetchManagedStatus:error]; |
| 252 }] fetchManagedStatus:browser_state_.get() |
| 253 forIdentity:identity1_]; |
| 254 |
| 255 [[[performer_ expect] andDo:^(NSInvocation* invocation) { |
| 256 ProceduralBlock completionBlock; |
| 257 [invocation getArgument:&completionBlock atIndex:3]; |
| 258 completionBlock(); |
| 259 }] showAuthenticationError:[OCMArg any] |
| 260 withCompletion:[OCMArg any] |
| 261 viewController:view_controller_]; |
| 262 |
| 263 [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; |
| 264 |
| 265 CheckSignInCompletion(false); |
| 266 } |
| 267 |
| 268 // Tests the managed sign in confirmation dialog is shown when signing in to |
| 269 // a managed identity. |
| 270 TEST_F(AuthenticationFlowTest, TestShowManagedConfirmation) { |
| 271 CreateAuthenticationFlow(SHOULD_CLEAR_DATA_CLEAR_DATA, |
| 272 POST_SIGNIN_ACTION_START_SYNC); |
| 273 |
| 274 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 275 [authentication_flow_ didFetchManagedStatus:@"foo.com"]; |
| 276 }] fetchManagedStatus:browser_state_.get() |
| 277 forIdentity:identity1_]; |
| 278 |
| 279 [[[performer_ expect] andReturnBool:NO] |
| 280 shouldHandleMergeCaseForIdentity:identity1_ |
| 281 browserState:browser_state_.get()]; |
| 282 |
| 283 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 284 [authentication_flow_ didAcceptManagedConfirmation]; |
| 285 }] showManagedConfirmationForHostedDomain:@"foo.com" |
| 286 viewController:view_controller_]; |
| 287 |
| 288 [[[performer_ expect] andDo:^(NSInvocation*) { |
| 289 [authentication_flow_ didClearData]; |
| 290 }] clearData:browser_state_.get()]; |
| 291 |
| 292 [[performer_ expect] signInIdentity:identity1_ |
| 293 withHostedDomain:@"foo.com" |
| 294 toBrowserState:browser_state_.get()]; |
| 295 |
| 296 [[performer_ expect] commitSyncForBrowserState:browser_state_.get()]; |
| 297 |
| 298 [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; |
| 299 |
| 300 CheckSignInCompletion(true); |
| 301 } |
| 302 |
| 303 } // namespace |
OLD | NEW |