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 "chrome/browser/sync/sync_global_error.h" 6 7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/sync/profile_sync_service_mock.h" 9 #include "chrome/browser/sync/sync_error_controller.h" 10 #include "chrome/browser/sync/sync_global_error_factory.h" 11 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/webui/signin/login_ui_service.h" 13 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" 14 #include "chrome/test/base/browser_with_test_window_test.h" 15 #include "chrome/test/base/testing_profile.h" 16 #include "content/public/browser/notification_observer.h" 17 #include "content/public/browser/notification_registrar.h" 18 #include "content/public/browser/notification_source.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 using ::testing::NiceMock; 23 using ::testing::Return; 24 using ::testing::ReturnRef; 25 using ::testing::_; 26 27 namespace { 28 29 class FakeLoginUIService: public LoginUIService { 30 public: 31 FakeLoginUIService() : LoginUIService(NULL) {} 32 }; 33 34 class FakeLoginUI : public LoginUIService::LoginUI { 35 public: 36 FakeLoginUI() : focus_ui_call_count_(0) {} 37 38 virtual ~FakeLoginUI() {} 39 40 int focus_ui_call_count() const { return focus_ui_call_count_; } 41 42 private: 43 // Overridden from LoginUIService::LoginUI: 44 virtual void FocusUI() OVERRIDE { 45 ++focus_ui_call_count_; 46 } 47 virtual void CloseUI() OVERRIDE {} 48 49 int focus_ui_call_count_; 50 }; 51 52 KeyedService* BuildMockLoginUIService(content::BrowserContext* profile) { 53 return new FakeLoginUIService(); 54 } 55 56 // Same as BrowserWithTestWindowTest, but uses MockBrowser to test calls to 57 // ExecuteCommand method. 58 class SyncGlobalErrorTest : public BrowserWithTestWindowTest { 59 public: 60 SyncGlobalErrorTest() {} 61 virtual ~SyncGlobalErrorTest() {} 62 63 virtual void SetUp() OVERRIDE { 64 profile_.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile()); 65 66 BrowserWithTestWindowTest::SetUp(); 67 } 68 69 Profile* profile() { return profile_.get(); } 70 71 private: 72 scoped_ptr<TestingProfile> profile_; 73 74 DISALLOW_COPY_AND_ASSIGN(SyncGlobalErrorTest); 75 }; 76 77 // Utility function to test that SyncGlobalError behaves correctly for the given 78 // error condition. 79 void VerifySyncGlobalErrorResult(NiceMock<ProfileSyncServiceMock>* service, 80 FakeLoginUIService* login_ui_service, 81 Browser* browser, 82 SyncErrorController* error, 83 SyncGlobalError* global_error, 84 GoogleServiceAuthError::State error_state, 85 bool is_signed_in, 86 bool is_error) { 87 EXPECT_CALL(*service, HasSyncSetupCompleted()) 88 .WillRepeatedly(Return(is_signed_in)); 89 90 GoogleServiceAuthError auth_error(error_state); 91 EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error)); 92 93 error->OnStateChanged(); 94 EXPECT_EQ(is_error, error->HasError()); 95 96 // If there is an error then a menu item and bubble view should be shown. 97 EXPECT_EQ(is_error, global_error->HasMenuItem()); 98 EXPECT_EQ(is_error, global_error->HasBubbleView()); 99 100 // If there is an error then labels should not be empty. 101 EXPECT_NE(0, global_error->MenuItemCommandID()); 102 EXPECT_NE(is_error, global_error->MenuItemLabel().empty()); 103 EXPECT_NE(is_error, global_error->GetBubbleViewAcceptButtonLabel().empty()); 104 105 // We never have a cancel button. 106 EXPECT_TRUE(global_error->GetBubbleViewCancelButtonLabel().empty()); 107 // We always return a hardcoded title. 108 EXPECT_FALSE(global_error->GetBubbleViewTitle().empty()); 109 110 // Test message handler. 111 if (is_error) { 112 FakeLoginUI* login_ui = static_cast<FakeLoginUI*>( 113 login_ui_service->current_login_ui()); 114 global_error->ExecuteMenuItem(browser); 115 ASSERT_GT(login_ui->focus_ui_call_count(), 0); 116 global_error->BubbleViewAcceptButtonPressed(browser); 117 global_error->BubbleViewDidClose(browser); 118 } 119 } 120 121 } // namespace 122 123 // Test that SyncGlobalError shows an error if a passphrase is required. 124 TEST_F(SyncGlobalErrorTest, PassphraseGlobalError) { 125 NiceMock<ProfileSyncServiceMock> service(profile()); 126 127 FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>( 128 LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse( 129 profile(), BuildMockLoginUIService)); 130 FakeLoginUI login_ui; 131 login_ui_service->SetLoginUI(&login_ui); 132 133 SyncErrorController error(&service); 134 SyncGlobalError global_error(&error, &service); 135 136 browser_sync::SyncBackendHost::Status status; 137 EXPECT_CALL(service, QueryDetailedSyncStatus(_)) 138 .WillRepeatedly(Return(false)); 139 140 EXPECT_CALL(service, IsPassphraseRequired()) 141 .WillRepeatedly(Return(true)); 142 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) 143 .WillRepeatedly(Return(true)); 144 VerifySyncGlobalErrorResult( 145 &service, login_ui_service, browser(), &error, &global_error, 146 GoogleServiceAuthError::NONE, true /* signed in*/, true /* error */); 147 148 // Check that no menu item is shown if there is no error. 149 EXPECT_CALL(service, IsPassphraseRequired()) 150 .WillRepeatedly(Return(false)); 151 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) 152 .WillRepeatedly(Return(false)); 153 VerifySyncGlobalErrorResult( 154 &service, login_ui_service, browser(), &error, &global_error, 155 GoogleServiceAuthError::NONE, true /* signed in */, false /* no error */); 156 157 // Check that no menu item is shown if sync setup is not completed. 158 EXPECT_CALL(service, IsPassphraseRequired()) 159 .WillRepeatedly(Return(true)); 160 EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) 161 .WillRepeatedly(Return(true)); 162 VerifySyncGlobalErrorResult( 163 &service, login_ui_service, browser(), &error, &global_error, 164 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, 165 false /* not signed in */, false /* no error */); 166 167 global_error.Shutdown(); 168 } 169