1// Copyright (c) 2012 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#include "base/prefs/pref_service.h"
6#include "base/prefs/scoped_user_pref_update.h"
7#include "base/run_loop.h"
8#include "base/strings/utf_string_conversions.h"
9#include "base/values.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/content_settings/cookie_settings.h"
12#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/profiles/profile_info_cache.h"
15#include "chrome/browser/profiles/profile_io_data.h"
16#include "chrome/browser/profiles/profile_manager.h"
17#include "chrome/browser/signin/chrome_signin_client.h"
18#include "chrome/browser/signin/chrome_signin_client_factory.h"
19#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
20#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
21#include "chrome/browser/signin/fake_signin_manager.h"
22#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
23#include "chrome/browser/signin/signin_manager_factory.h"
24#include "chrome/browser/signin/signin_names_io_thread.h"
25#include "chrome/browser/signin/signin_promo.h"
26#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
27#include "chrome/browser/sync/profile_sync_service_factory.h"
28#include "chrome/browser/sync/test_profile_sync_service.h"
29#include "chrome/browser/ui/sync/one_click_signin_helper.h"
30#include "chrome/browser/ui/webui/signin/login_ui_service.h"
31#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
32#include "chrome/common/pref_names.h"
33#include "chrome/grit/chromium_strings.h"
34#include "chrome/grit/generated_resources.h"
35#include "chrome/test/base/chrome_render_view_host_test_harness.h"
36#include "chrome/test/base/testing_browser_process.h"
37#include "chrome/test/base/testing_pref_service_syncable.h"
38#include "chrome/test/base/testing_profile.h"
39#include "chrome/test/base/testing_profile_manager.h"
40#include "components/autofill/core/common/password_form.h"
41#include "components/signin/core/browser/profile_oauth2_token_service.h"
42#include "components/signin/core/browser/signin_manager.h"
43#include "components/sync_driver/pref_names.h"
44#include "content/public/browser/browser_context.h"
45#include "content/public/browser/navigation_details.h"
46#include "content/public/browser/navigation_entry.h"
47#include "content/public/browser/web_contents.h"
48#include "content/public/browser/web_contents_delegate.h"
49#include "content/public/common/frame_navigate_params.h"
50#include "content/public/common/url_constants.h"
51#include "content/public/test/mock_render_process_host.h"
52#include "testing/gmock/include/gmock/gmock.h"
53#include "testing/gtest/include/gtest/gtest.h"
54#include "ui/base/l10n/l10n_util.h"
55
56using ::testing::_;
57using ::testing::AtLeast;
58using ::testing::Return;
59
60namespace {
61
62// Used to confirm OneClickSigninHelper does not trigger redirect when there is
63// a pending navigation.
64class MockWebContentsDelegate : public content::WebContentsDelegate {
65 public:
66  MOCK_METHOD2(OpenURLFromTab,
67               content::WebContents*(content::WebContents* source,
68                                     const content::OpenURLParams& params));
69};
70
71class SigninManagerMock : public FakeSigninManager {
72 public:
73  explicit SigninManagerMock(Profile* profile) : FakeSigninManager(profile) {
74    Initialize(NULL);
75  }
76  MOCK_CONST_METHOD1(IsAllowedUsername, bool(const std::string& username));
77};
78
79static KeyedService* BuildSigninManagerMock(content::BrowserContext* profile) {
80  return new SigninManagerMock(static_cast<Profile*>(profile));
81}
82
83class TestProfileIOData : public ProfileIOData {
84 public:
85  TestProfileIOData(Profile::ProfileType profile_type,
86                    PrefService* pref_service, PrefService* local_state,
87                    CookieSettings* cookie_settings)
88      : ProfileIOData(profile_type) {
89    // Initialize the IO members required for these tests, but keep them on
90    // this thread since we don't use a background thread here.
91    google_services_username()->Init(prefs::kGoogleServicesUsername,
92                                     pref_service);
93    reverse_autologin_enabled()->Init(prefs::kReverseAutologinEnabled,
94                                      pref_service);
95    one_click_signin_rejected_email_list()->Init(
96        prefs::kReverseAutologinRejectedEmailList, pref_service);
97
98    google_services_username_pattern()->Init(
99        prefs::kGoogleServicesUsernamePattern, local_state);
100
101    sync_disabled()->Init(sync_driver::prefs::kSyncManaged, pref_service);
102
103    signin_allowed()->Init(prefs::kSigninAllowed, pref_service);
104
105    set_signin_names_for_testing(new SigninNamesOnIOThread());
106    SetCookieSettingsForTesting(cookie_settings);
107  }
108
109  virtual ~TestProfileIOData() {
110    signin_names()->ReleaseResourcesOnUIThread();
111  }
112
113  // ProfileIOData overrides:
114  virtual void InitializeInternal(
115      ProfileParams* profile_params,
116      content::ProtocolHandlerMap* protocol_handlers,
117      content::URLRequestInterceptorScopedVector request_interceptors)
118      const OVERRIDE {
119    NOTREACHED();
120  }
121  virtual void InitializeExtensionsRequestContext(
122      ProfileParams* profile_params) const OVERRIDE {
123    NOTREACHED();
124  }
125  virtual net::URLRequestContext* InitializeAppRequestContext(
126      net::URLRequestContext* main_context,
127      const StoragePartitionDescriptor& details,
128      scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
129          protocol_handler_interceptor,
130      content::ProtocolHandlerMap* protocol_handlers,
131      content::URLRequestInterceptorScopedVector request_interceptors)
132      const OVERRIDE {
133    NOTREACHED();
134    return NULL;
135  }
136  virtual net::URLRequestContext* InitializeMediaRequestContext(
137      net::URLRequestContext* original_context,
138      const StoragePartitionDescriptor& details) const OVERRIDE {
139    NOTREACHED();
140    return NULL;
141  }
142  virtual net::URLRequestContext*
143      AcquireMediaRequestContext() const OVERRIDE {
144    NOTREACHED();
145    return NULL;
146  }
147  virtual net::URLRequestContext* AcquireIsolatedAppRequestContext(
148      net::URLRequestContext* main_context,
149      const StoragePartitionDescriptor& partition_descriptor,
150      scoped_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
151          protocol_handler_interceptor,
152      content::ProtocolHandlerMap* protocol_handlers,
153      content::URLRequestInterceptorScopedVector request_interceptors)
154      const OVERRIDE {
155    NOTREACHED();
156    return NULL;
157  }
158  virtual net::URLRequestContext*
159      AcquireIsolatedMediaRequestContext(
160          net::URLRequestContext* app_context,
161          const StoragePartitionDescriptor& partition_descriptor)
162          const OVERRIDE {
163    NOTREACHED();
164    return NULL;
165  }
166};
167
168class TestURLRequest : public base::SupportsUserData {
169 public:
170  TestURLRequest() {}
171  virtual ~TestURLRequest() {}
172};
173
174class OneClickTestProfileSyncService : public TestProfileSyncService {
175 public:
176  virtual ~OneClickTestProfileSyncService() {}
177
178  // Helper routine to be used in conjunction with
179  // BrowserContextKeyedServiceFactory::SetTestingFactory().
180  static KeyedService* Build(content::BrowserContext* profile) {
181    return new OneClickTestProfileSyncService(static_cast<Profile*>(profile));
182  }
183
184  // Need to control this for certain tests.
185  virtual bool FirstSetupInProgress() const OVERRIDE {
186    return first_setup_in_progress_;
187  }
188
189  virtual bool sync_initialized() const OVERRIDE { return sync_initialized_; }
190
191  // Controls return value of FirstSetupInProgress. Because some bits
192  // of UI depend on that value, it's useful to control it separately
193  // from the internal work and components that are triggered (such as
194  // ReconfigureDataTypeManager) to facilitate unit tests.
195  void set_first_setup_in_progress(bool in_progress) {
196    first_setup_in_progress_ = in_progress;
197  }
198
199  void set_sync_initialized(bool initialized) {
200    sync_initialized_ = initialized;
201  }
202
203 private:
204  explicit OneClickTestProfileSyncService(Profile* profile)
205      : TestProfileSyncService(
206          scoped_ptr<ProfileSyncComponentsFactory>(
207              new ProfileSyncComponentsFactoryMock()),
208          profile,
209          SigninManagerFactory::GetForProfile(profile),
210          ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
211          browser_sync::MANUAL_START),
212        first_setup_in_progress_(false),
213        sync_initialized_(false) {}
214
215  bool first_setup_in_progress_;
216  bool sync_initialized_;
217};
218
219}  // namespace
220
221class OneClickSigninHelperTest : public ChromeRenderViewHostTestHarness {
222 public:
223  OneClickSigninHelperTest();
224
225  virtual void SetUp() OVERRIDE;
226  virtual void TearDown() OVERRIDE;
227
228  // Sets up the sign-in manager for tests.  If |username| is
229  // is not empty, the profile of the mock WebContents will be connected to
230  // the given account.
231  void SetUpSigninManager(const std::string& username);
232
233  // Set the ID of the signin process that the test will assume to be the
234  // only process allowed to sign the user in to Chrome.
235  void SetTrustedSigninProcessID(int id);
236
237  void AddEmailToOneClickRejectedList(const std::string& email);
238  void EnableOneClick(bool enable);
239  void AllowSigninCookies(bool enable);
240  void SetAllowedUsernamePattern(const std::string& pattern);
241  void SubmitGAIAPassword(OneClickSigninHelper* helper);
242
243  SigninManagerMock* signin_manager_;
244  FakeProfileOAuth2TokenService* fake_oauth2_token_service_;
245
246 protected:
247  GoogleServiceAuthError no_error_;
248
249 private:
250  // ChromeRenderViewHostTestHarness overrides:
251  virtual content::BrowserContext* CreateBrowserContext() OVERRIDE;
252
253  // The ID of the signin process the test will assume to be trusted.
254  // By default, set to the test RenderProcessHost's process ID, but
255  // overridden by SetTrustedSigninProcessID.
256  int trusted_signin_process_id_;
257
258  DISALLOW_COPY_AND_ASSIGN(OneClickSigninHelperTest);
259};
260
261OneClickSigninHelperTest::OneClickSigninHelperTest()
262    : signin_manager_(NULL),
263      fake_oauth2_token_service_(NULL),
264      no_error_(GoogleServiceAuthError::NONE),
265      trusted_signin_process_id_(-1) {
266}
267
268void OneClickSigninHelperTest::SetUp() {
269  signin::ForceWebBasedSigninFlowForTesting(true);
270  content::RenderViewHostTestHarness::SetUp();
271  SetTrustedSigninProcessID(process()->GetID());
272}
273
274void OneClickSigninHelperTest::TearDown() {
275  signin::ForceWebBasedSigninFlowForTesting(false);
276  content::RenderViewHostTestHarness::TearDown();
277}
278
279void OneClickSigninHelperTest::SetTrustedSigninProcessID(int id) {
280  trusted_signin_process_id_ = id;
281}
282
283void OneClickSigninHelperTest::SetUpSigninManager(const std::string& username) {
284  SigninClient* signin_client =
285      ChromeSigninClientFactory::GetForProfile(profile());
286  if (signin_client)
287    signin_client->SetSigninProcess(trusted_signin_process_id_);
288
289  signin_manager_ = static_cast<SigninManagerMock*>(
290      SigninManagerFactory::GetForProfile(profile()));
291  if (!username.empty()) {
292    ASSERT_TRUE(signin_manager_);
293    signin_manager_->SetAuthenticatedUsername(username);
294  }
295}
296
297void OneClickSigninHelperTest::EnableOneClick(bool enable) {
298  PrefService* pref_service = profile()->GetPrefs();
299  pref_service->SetBoolean(prefs::kReverseAutologinEnabled, enable);
300}
301
302void OneClickSigninHelperTest::AddEmailToOneClickRejectedList(
303    const std::string& email) {
304  PrefService* pref_service = profile()->GetPrefs();
305  ListPrefUpdate updater(pref_service,
306                         prefs::kReverseAutologinRejectedEmailList);
307  updater->AppendIfNotPresent(new base::StringValue(email));
308}
309
310void OneClickSigninHelperTest::AllowSigninCookies(bool enable) {
311  CookieSettings* cookie_settings =
312      CookieSettings::Factory::GetForProfile(profile()).get();
313  cookie_settings->SetDefaultCookieSetting(enable ? CONTENT_SETTING_ALLOW
314                                                  : CONTENT_SETTING_BLOCK);
315}
316
317void OneClickSigninHelperTest::SetAllowedUsernamePattern(
318    const std::string& pattern) {
319  PrefService* local_state = g_browser_process->local_state();
320  local_state->SetString(prefs::kGoogleServicesUsernamePattern, pattern);
321}
322
323void OneClickSigninHelperTest::SubmitGAIAPassword(
324    OneClickSigninHelper* helper) {
325  autofill::PasswordForm password_form;
326  password_form.origin = GURL("https://accounts.google.com");
327  password_form.signon_realm = "https://accounts.google.com";
328  password_form.password_value = base::UTF8ToUTF16("password");
329  helper->PasswordSubmitted(password_form);
330}
331
332content::BrowserContext* OneClickSigninHelperTest::CreateBrowserContext() {
333  TestingProfile::Builder builder;
334  builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
335                            BuildFakeProfileOAuth2TokenService);
336  builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
337                            BuildSigninManagerMock);
338  scoped_ptr<TestingProfile> profile = builder.Build();
339
340  fake_oauth2_token_service_ =
341      static_cast<FakeProfileOAuth2TokenService*>(
342          ProfileOAuth2TokenServiceFactory::GetForProfile(profile.get()));
343
344  return profile.release();
345}
346
347class OneClickSigninHelperIOTest : public OneClickSigninHelperTest {
348 public:
349  OneClickSigninHelperIOTest();
350
351  virtual void SetUp() OVERRIDE;
352
353  TestProfileIOData* CreateTestProfileIOData(Profile::ProfileType profile_type);
354
355 protected:
356  TestingProfileManager testing_profile_manager_;
357  TestURLRequest request_;
358  const GURL valid_gaia_url_;
359
360 private:
361  DISALLOW_COPY_AND_ASSIGN(OneClickSigninHelperIOTest);
362};
363
364OneClickSigninHelperIOTest::OneClickSigninHelperIOTest()
365    : testing_profile_manager_(
366          TestingBrowserProcess::GetGlobal()),
367      valid_gaia_url_("https://accounts.google.com/") {
368}
369
370void OneClickSigninHelperIOTest::SetUp() {
371  OneClickSigninHelperTest::SetUp();
372  ASSERT_TRUE(testing_profile_manager_.SetUp());
373}
374
375TestProfileIOData* OneClickSigninHelperIOTest::CreateTestProfileIOData(
376    Profile::ProfileType profile_type) {
377  PrefService* pref_service = profile()->GetPrefs();
378  PrefService* local_state = g_browser_process->local_state();
379  CookieSettings* cookie_settings =
380      CookieSettings::Factory::GetForProfile(profile()).get();
381  TestProfileIOData* io_data = new TestProfileIOData(
382      profile_type, pref_service, local_state, cookie_settings);
383  io_data->set_reverse_autologin_pending_email("user@gmail.com");
384  return io_data;
385}
386
387class OneClickSigninHelperIncognitoTest : public OneClickSigninHelperTest {
388 protected:
389  // content::RenderViewHostTestHarness.
390  virtual content::BrowserContext* CreateBrowserContext() OVERRIDE;
391};
392
393content::BrowserContext*
394OneClickSigninHelperIncognitoTest::CreateBrowserContext() {
395  // Simulate an incognito profile to run this test. RenderViewHostTestHarness
396  // takes ownership of the return value, so it can't be a "proper" incognito
397  // profile, since they are owned by their parent, non-incognito profile.
398  scoped_ptr<TestingProfile> profile = TestingProfile::Builder().Build();
399  profile->ForceIncognito(true);
400  return profile.release();
401}
402
403TEST_F(OneClickSigninHelperTest, CanOfferNoContents) {
404  std::string error_message;
405  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
406      NULL, OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
407      "user@gmail.com", &error_message));
408  EXPECT_EQ("", error_message);
409  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
410      NULL, OneClickSigninHelper::CAN_OFFER_FOR_ALL,
411      "user@gmail.com", &error_message));
412  EXPECT_EQ("", error_message);
413  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
414      NULL,
415      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
416      std::string(),
417      &error_message));
418  EXPECT_EQ("", error_message);
419}
420
421TEST_F(OneClickSigninHelperTest, CanOffer) {
422  SetUpSigninManager(std::string());
423
424  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
425        WillRepeatedly(Return(true));
426
427  EnableOneClick(true);
428  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
429      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
430      "user@gmail.com", NULL));
431  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
432      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
433      "user@gmail.com", NULL));
434  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
435      web_contents(),
436      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
437      std::string(),
438      NULL));
439
440  EnableOneClick(false);
441
442  std::string error_message;
443  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
444      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
445      "user@gmail.com", &error_message));
446  EXPECT_EQ("", error_message);
447
448  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
449      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
450      "user@gmail.com", &error_message));
451  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
452      web_contents(),
453      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
454      std::string(),
455      &error_message));
456  EXPECT_EQ("", error_message);
457}
458
459TEST_F(OneClickSigninHelperTest, CanOfferFirstSetup) {
460  SetUpSigninManager(std::string());
461
462  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
463        WillRepeatedly(Return(true));
464
465  // Invoke OneClickTestProfileSyncService factory function and grab result.
466  OneClickTestProfileSyncService* sync =
467      static_cast<OneClickTestProfileSyncService*>(
468          ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
469              profile(), OneClickTestProfileSyncService::Build));
470  sync->set_sync_initialized(false);
471  sync->Initialize();
472  sync->set_sync_initialized(true);
473  sync->set_first_setup_in_progress(true);
474
475  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
476      web_contents(),
477      OneClickSigninHelper::CAN_OFFER_FOR_ALL,
478      "foo@gmail.com", NULL));
479  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
480      web_contents(),
481      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
482      "foo@gmail.com", NULL));
483  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
484      web_contents(),
485      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
486      std::string(),
487      NULL));
488}
489
490TEST_F(OneClickSigninHelperTest, CanOfferProfileConnected) {
491  SetUpSigninManager("foo@gmail.com");
492
493  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
494      WillRepeatedly(Return(true));
495
496  std::string error_message;
497  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
498      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
499      "foo@gmail.com", &error_message));
500  EXPECT_EQ("", error_message);
501  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
502      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
503      "foo", &error_message));
504  EXPECT_EQ("", error_message);
505  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
506      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
507      "user@gmail.com", &error_message));
508  EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL,
509                                      base::UTF8ToUTF16("foo@gmail.com")),
510            error_message);
511  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
512      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
513      "foo@gmail.com", &error_message));
514  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
515      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
516      "foo", &error_message));
517  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
518      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
519      "user@gmail.com", &error_message));
520  EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_SYNC_WRONG_EMAIL,
521                                      base::UTF8ToUTF16("foo@gmail.com")),
522            error_message);
523  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
524      web_contents(),
525      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
526      std::string(),
527      &error_message));
528}
529
530TEST_F(OneClickSigninHelperTest, CanOfferUsernameNotAllowed) {
531  SetUpSigninManager(std::string());
532
533  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
534      WillRepeatedly(Return(false));
535
536  std::string error_message;
537  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
538      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
539      "foo@gmail.com", &error_message));
540  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED),
541            error_message);
542  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
543      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
544      "foo@gmail.com", &error_message));
545  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SYNC_LOGIN_NAME_PROHIBITED),
546            error_message);
547  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
548      web_contents(),
549      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
550      std::string(),
551      &error_message));
552}
553
554TEST_F(OneClickSigninHelperTest, CanOfferWithRejectedEmail) {
555  SetUpSigninManager(std::string());
556
557  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
558        WillRepeatedly(Return(true));
559
560  AddEmailToOneClickRejectedList("foo@gmail.com");
561  AddEmailToOneClickRejectedList("user@gmail.com");
562
563  std::string error_message;
564  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
565      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
566      "foo@gmail.com", &error_message));
567  EXPECT_EQ("", error_message);
568  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
569      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
570      "user@gmail.com", &error_message));
571  EXPECT_EQ("", error_message);
572  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
573      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
574      "foo@gmail.com", &error_message));
575  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
576      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
577      "user@gmail.com", &error_message));
578  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
579      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
580      "john@gmail.com", &error_message));
581}
582
583TEST_F(OneClickSigninHelperIncognitoTest, CanOfferIncognito) {
584  SetUpSigninManager(std::string());
585
586  std::string error_message;
587  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
588      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
589      "user@gmail.com", &error_message));
590  EXPECT_EQ("", error_message);
591  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
592      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
593      "user@gmail.com", &error_message));
594  EXPECT_EQ("", error_message);
595  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
596      web_contents(),
597      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
598      std::string(),
599      &error_message));
600  EXPECT_EQ("", error_message);
601}
602
603TEST_F(OneClickSigninHelperTest, CanOfferNoSigninCookies) {
604  SetUpSigninManager(std::string());
605  AllowSigninCookies(false);
606
607  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
608        WillRepeatedly(Return(true));
609
610  std::string error_message;
611  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
612      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
613      "user@gmail.com", &error_message));
614  EXPECT_EQ("", error_message);
615  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
616      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
617      "user@gmail.com", &error_message));
618  EXPECT_EQ("", error_message);
619  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
620      web_contents(),
621      OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY,
622      std::string(),
623      &error_message));
624  EXPECT_EQ("", error_message);
625}
626
627TEST_F(OneClickSigninHelperTest, CanOfferDisabledByPolicy) {
628  SetUpSigninManager(std::string());
629
630  EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
631        WillRepeatedly(Return(true));
632
633  EnableOneClick(true);
634  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
635      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
636      "user@gmail.com", NULL));
637
638  // Simulate a policy disabling signin by writing kSigninAllowed directly.
639  profile()->GetTestingPrefService()->SetManagedPref(
640      prefs::kSigninAllowed, new base::FundamentalValue(false));
641
642  EXPECT_FALSE(OneClickSigninHelper::CanOffer(
643      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
644      "user@gmail.com", NULL));
645
646  // Reset the preference value to true.
647  profile()->GetTestingPrefService()->SetManagedPref(
648      prefs::kSigninAllowed, new base::FundamentalValue(true));
649
650  // Simulate a policy disabling sync by writing kSyncManaged directly.
651  profile()->GetTestingPrefService()->SetManagedPref(
652      sync_driver::prefs::kSyncManaged, new base::FundamentalValue(true));
653
654  // Should still offer even if sync is disabled by policy.
655  EXPECT_TRUE(OneClickSigninHelper::CanOffer(
656      web_contents(), OneClickSigninHelper::CAN_OFFER_FOR_ALL,
657      "user@gmail.com", NULL));
658}
659
660// Should not crash if a helper instance is not associated with an incognito
661// web contents.
662TEST_F(OneClickSigninHelperIncognitoTest, ShowInfoBarUIThreadIncognito) {
663  SetUpSigninManager(std::string());
664  OneClickSigninHelper* helper =
665      OneClickSigninHelper::FromWebContents(web_contents());
666  EXPECT_EQ(NULL, helper);
667
668  OneClickSigninHelper::ShowInfoBarUIThread(
669      "session_index", "email", OneClickSigninHelper::AUTO_ACCEPT_ACCEPTED,
670      signin::SOURCE_UNKNOWN, GURL(), process()->GetID(),
671      rvh()->GetRoutingID());
672}
673
674// Checks that the state of OneClickSigninHelper is cleaned when there is a
675// navigation away from the sign in flow that is not triggered by the
676// web contents.
677TEST_F(OneClickSigninHelperTest, CleanTransientStateOnNavigate) {
678  content::WebContents* contents = web_contents();
679
680  OneClickSigninHelper::CreateForWebContentsWithPasswordManager(contents, NULL);
681  OneClickSigninHelper* helper =
682      OneClickSigninHelper::FromWebContents(contents);
683  helper->SetDoNotClearPendingEmailForTesting();
684  helper->auto_accept_ = OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT;
685
686  content::LoadCommittedDetails details;
687  content::FrameNavigateParams params;
688  params.url = GURL("http://crbug.com");
689  params.transition = ui::PAGE_TRANSITION_TYPED;
690  helper->DidNavigateMainFrame(details, params);
691
692  EXPECT_EQ(OneClickSigninHelper::AUTO_ACCEPT_NONE, helper->auto_accept_);
693}
694
695TEST_F(OneClickSigninHelperTest, NoRedirectToNTPWithPendingEntry) {
696  content::NavigationController& controller = web_contents()->GetController();
697  EXPECT_FALSE(controller.GetPendingEntry());
698
699  const GURL fooWebUIURL("chrome://foo");
700  controller.LoadURL(fooWebUIURL, content::Referrer(),
701                     ui::PAGE_TRANSITION_TYPED, std::string());
702  EXPECT_EQ(fooWebUIURL, controller.GetPendingEntry()->GetURL());
703
704  MockWebContentsDelegate delegate;
705  EXPECT_CALL(delegate, OpenURLFromTab(_, _)).Times(0);
706  web_contents()->SetDelegate(&delegate);
707  OneClickSigninHelper::RedirectToNtpOrAppsPage(
708      web_contents(), signin::SOURCE_UNKNOWN);
709
710  EXPECT_EQ(fooWebUIURL, controller.GetPendingEntry()->GetURL());
711}
712
713// I/O thread tests
714
715TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThread) {
716  scoped_ptr<TestProfileIOData> io_data(
717      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
718  EXPECT_EQ(OneClickSigninHelper::CAN_OFFER,
719            OneClickSigninHelper::CanOfferOnIOThreadImpl(
720                valid_gaia_url_, &request_, io_data.get()));
721}
722
723TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadIncognito) {
724  scoped_ptr<TestProfileIOData> io_data(
725      CreateTestProfileIOData(Profile::INCOGNITO_PROFILE));
726  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
727            OneClickSigninHelper::CanOfferOnIOThreadImpl(
728                valid_gaia_url_, &request_, io_data.get()));
729}
730
731TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadNoIOData) {
732  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
733            OneClickSigninHelper::CanOfferOnIOThreadImpl(
734                valid_gaia_url_, &request_, NULL));
735}
736
737TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadBadURL) {
738  scoped_ptr<TestProfileIOData> io_data(
739      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
740  EXPECT_EQ(
741      OneClickSigninHelper::IGNORE_REQUEST,
742      OneClickSigninHelper::CanOfferOnIOThreadImpl(
743          GURL("https://foo.com/"), &request_, io_data.get()));
744  EXPECT_EQ(OneClickSigninHelper::IGNORE_REQUEST,
745            OneClickSigninHelper::CanOfferOnIOThreadImpl(
746                GURL("http://accounts.google.com/"),
747                &request_,
748                io_data.get()));
749}
750
751TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadDisabled) {
752  EnableOneClick(false);
753  scoped_ptr<TestProfileIOData> io_data(
754      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
755  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
756            OneClickSigninHelper::CanOfferOnIOThreadImpl(
757                valid_gaia_url_, &request_, io_data.get()));
758}
759
760TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadSignedIn) {
761  PrefService* pref_service = profile()->GetPrefs();
762  pref_service->SetString(prefs::kGoogleServicesUsername, "user@gmail.com");
763
764  scoped_ptr<TestProfileIOData> io_data(
765      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
766  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
767            OneClickSigninHelper::CanOfferOnIOThreadImpl(
768                valid_gaia_url_, &request_, io_data.get()));
769}
770
771TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadEmailNotAllowed) {
772  SetAllowedUsernamePattern("*@example.com");
773  scoped_ptr<TestProfileIOData> io_data(
774      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
775  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
776            OneClickSigninHelper::CanOfferOnIOThreadImpl(
777                valid_gaia_url_,  &request_, io_data.get()));
778}
779
780TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadEmailAlreadyUsed) {
781  ProfileInfoCache* cache = testing_profile_manager_.profile_info_cache();
782  const base::FilePath& user_data_dir = cache->GetUserDataDir();
783  cache->AddProfileToCache(user_data_dir.Append(FILE_PATH_LITERAL("user")),
784                           base::UTF8ToUTF16("user"),
785                           base::UTF8ToUTF16("user@gmail.com"), 0,
786                           std::string());
787
788  scoped_ptr<TestProfileIOData> io_data(
789      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
790  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
791            OneClickSigninHelper::CanOfferOnIOThreadImpl(
792                valid_gaia_url_, &request_, io_data.get()));
793}
794
795TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadWithRejectedEmail) {
796  AddEmailToOneClickRejectedList("user@gmail.com");
797  scoped_ptr<TestProfileIOData> io_data(
798      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
799  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
800            OneClickSigninHelper::CanOfferOnIOThreadImpl(
801                valid_gaia_url_, &request_, io_data.get()));
802}
803
804TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadNoSigninCookies) {
805  AllowSigninCookies(false);
806  scoped_ptr<TestProfileIOData> io_data(
807      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
808  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
809            OneClickSigninHelper::CanOfferOnIOThreadImpl(
810                valid_gaia_url_, &request_, io_data.get()));
811}
812
813TEST_F(OneClickSigninHelperIOTest, CanOfferOnIOThreadDisabledByPolicy) {
814  scoped_ptr<TestProfileIOData> io_data(
815      CreateTestProfileIOData(Profile::REGULAR_PROFILE));
816  EXPECT_EQ(OneClickSigninHelper::CAN_OFFER,
817            OneClickSigninHelper::CanOfferOnIOThreadImpl(
818                valid_gaia_url_, &request_, io_data.get()));
819
820  // Simulate a policy disabling signin by writing kSigninAllowed directly.
821  // We should not offer to sign in the browser.
822  profile()->GetTestingPrefService()->SetManagedPref(
823      prefs::kSigninAllowed, new base::FundamentalValue(false));
824  EXPECT_EQ(OneClickSigninHelper::DONT_OFFER,
825            OneClickSigninHelper::CanOfferOnIOThreadImpl(
826                valid_gaia_url_, &request_, io_data.get()));
827
828  // Reset the preference.
829  profile()->GetTestingPrefService()->SetManagedPref(
830      prefs::kSigninAllowed, new base::FundamentalValue(true));
831
832  // Simulate a policy disabling sync by writing kSyncManaged directly.
833  // We should still offer to sign in the browser.
834  profile()->GetTestingPrefService()->SetManagedPref(
835      sync_driver::prefs::kSyncManaged, new base::FundamentalValue(true));
836  EXPECT_EQ(OneClickSigninHelper::CAN_OFFER,
837            OneClickSigninHelper::CanOfferOnIOThreadImpl(
838                valid_gaia_url_, &request_, io_data.get()));
839}
840
841
842class MockStarterWrapper
843    : public testing::StrictMock<OneClickSigninHelper::SyncStarterWrapper> {
844 public:
845  MockStarterWrapper(
846      const OneClickSigninHelper::StartSyncArgs& args,
847      OneClickSigninSyncStarter::StartSyncMode start_mode);
848
849  MOCK_METHOD1(DisplayErrorBubble, void(const std::string& error_message));
850  MOCK_METHOD0(StartSigninOAuthHelper, void());
851  MOCK_METHOD2(StartOneClickSigninSyncStarter,
852               void(const std::string& email,
853                    const std::string& refresh_token));
854};
855
856MockStarterWrapper::MockStarterWrapper(
857    const OneClickSigninHelper::StartSyncArgs& args,
858    OneClickSigninSyncStarter::StartSyncMode start_mode)
859    : testing::StrictMock<OneClickSigninHelper::SyncStarterWrapper>(
860          args, start_mode) {
861}
862
863class OneClickSyncStarterWrapperTest : public testing::Test {
864 public:
865  virtual void SetUp() OVERRIDE {
866    TestingProfile::Builder builder;
867    profile_ = builder.Build();
868  }
869
870  virtual void TearDown() OVERRIDE {
871    // Let the SyncStarterWrapper delete itself.
872    base::RunLoop().RunUntilIdle();
873  }
874
875  void SetCookie(const std::string& value) {
876    // Set a valid LSID cookie in the test cookie store.
877    scoped_refptr<net::CookieMonster> cookie_monster =
878        profile()->GetCookieMonster();
879    net::CookieOptions options;
880    options.set_include_httponly();
881    cookie_monster->SetCookieWithOptionsAsync(
882          GURL("https://accounts.google.com"),
883          value, options,
884          net::CookieMonster::SetCookiesCallback());
885  }
886
887  void SimulateRefreshTokenFetched(
888      SigninOAuthHelper::Consumer* consumer,
889      const std::string& email,
890      const std::string& display_email,
891      const std::string& refresh_token) {
892    consumer->OnSigninOAuthInformationAvailable(
893        email, display_email, refresh_token);
894  }
895
896  TestingProfile* profile() { return profile_.get(); }
897
898 private:
899  content::TestBrowserThreadBundle thread_bundle_;
900  scoped_ptr<TestingProfile> profile_;
901};
902
903TEST_F(OneClickSyncStarterWrapperTest, SignInWithRefreshToken) {
904  OneClickSigninHelper::StartSyncArgs args;
905  args.email = "foo@gmail.com";
906  args.password = "password";
907  args.refresh_token = "refresh_token";
908  MockStarterWrapper* wrapper = new MockStarterWrapper(
909      args, OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
910
911  EXPECT_CALL(*wrapper,
912              StartOneClickSigninSyncStarter("foo@gmail.com",
913                                             "refresh_token"));
914  wrapper->Start();
915}
916
917TEST_F(OneClickSyncStarterWrapperTest, SignInWithPasswordNoRefreshToken) {
918  OneClickSigninHelper::StartSyncArgs args;
919  args.email = "foo@gmail.com";
920  args.password = "password";
921  MockStarterWrapper* wrapper = new MockStarterWrapper(
922      args, OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
923
924  EXPECT_CALL(*wrapper, StartSigninOAuthHelper());
925  EXPECT_CALL(*wrapper,
926              StartOneClickSigninSyncStarter("foo@gmail.com",
927                                             "refresh_token"));
928  wrapper->Start();
929  SimulateRefreshTokenFetched(wrapper, "foo@gmail.com", "foo@gmail.com",
930                              "refresh_token");
931}
932
933TEST_F(OneClickSyncStarterWrapperTest, SignInWithWrongEmail) {
934  OneClickSigninHelper::StartSyncArgs args;
935  args.email = "foo@gmail.com";
936  args.password = "password";
937  MockStarterWrapper* wrapper = new MockStarterWrapper(
938      args, OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
939
940  EXPECT_CALL(*wrapper, StartSigninOAuthHelper());
941  EXPECT_CALL(*wrapper, DisplayErrorBubble(_));
942  wrapper->Start();
943  SimulateRefreshTokenFetched(wrapper, "bar@gmail.com", "bar@gmail.com",
944                              "refresh_token");
945}
946
947TEST_F(OneClickSyncStarterWrapperTest, SignInWithEmptyPasswordValidCookie) {
948  OneClickSigninHelper::StartSyncArgs args;
949  args.email = "foo@gmail.com";
950  args.profile = profile();
951  MockStarterWrapper* wrapper = new MockStarterWrapper(
952      args, OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
953  SetCookie("LSID=1234; secure; httponly");
954
955  EXPECT_CALL(*wrapper, StartSigninOAuthHelper());
956  EXPECT_CALL(*wrapper,
957              StartOneClickSigninSyncStarter("foo@gmail.com",
958                                             "refresh_token"));
959  wrapper->Start();
960  base::RunLoop().RunUntilIdle();
961  SimulateRefreshTokenFetched(wrapper, "foo@gmail.com", "foo@gmail.com",
962                              "refresh_token");
963}
964
965TEST_F(OneClickSyncStarterWrapperTest, SignInWithEmptyPasswordNoCookie) {
966  OneClickSigninHelper::StartSyncArgs args;
967  args.email = "foo@gmail.com";
968  args.profile = profile();
969  MockStarterWrapper* wrapper = new MockStarterWrapper(
970      args, OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
971
972  EXPECT_CALL(*wrapper, DisplayErrorBubble(_));
973  wrapper->Start();
974  base::RunLoop().RunUntilIdle();
975}
976
977TEST_F(OneClickSyncStarterWrapperTest, SignInWithEmptyPasswordInvalidCookie) {
978  OneClickSigninHelper::StartSyncArgs args;
979  args.email = "foo@gmail.com";
980  args.profile = profile();
981  MockStarterWrapper* wrapper = new MockStarterWrapper(
982      args, OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
983  SetCookie("LSID=1234; domain=google.com; secure; httponly");
984
985  EXPECT_CALL(*wrapper, DisplayErrorBubble(_));
986  wrapper->Start();
987  base::RunLoop().RunUntilIdle();
988}
989