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 22using ::testing::NiceMock; 23using ::testing::Return; 24using ::testing::ReturnRef; 25using ::testing::_; 26 27namespace { 28 29class FakeLoginUIService: public LoginUIService { 30 public: 31 FakeLoginUIService() : LoginUIService(NULL) {} 32}; 33 34class 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 52KeyedService* BuildMockLoginUIService(content::BrowserContext* profile) { 53 return new FakeLoginUIService(); 54} 55 56// Same as BrowserWithTestWindowTest, but uses MockBrowser to test calls to 57// ExecuteCommand method. 58class 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. 79void 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. 124TEST_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