// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/sync/sync_global_error.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/sync/profile_sync_service_mock.h" #include "chrome/browser/sync/sync_error_controller.h" #include "chrome/browser/sync/sync_global_error_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_source.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::NiceMock; using ::testing::Return; using ::testing::ReturnRef; using ::testing::_; namespace { class FakeLoginUIService: public LoginUIService { public: FakeLoginUIService() : LoginUIService(NULL) {} }; class FakeLoginUI : public LoginUIService::LoginUI { public: FakeLoginUI() : focus_ui_call_count_(0) {} virtual ~FakeLoginUI() {} int focus_ui_call_count() const { return focus_ui_call_count_; } private: // Overridden from LoginUIService::LoginUI: virtual void FocusUI() OVERRIDE { ++focus_ui_call_count_; } virtual void CloseUI() OVERRIDE {} int focus_ui_call_count_; }; KeyedService* BuildMockLoginUIService(content::BrowserContext* profile) { return new FakeLoginUIService(); } // Same as BrowserWithTestWindowTest, but uses MockBrowser to test calls to // ExecuteCommand method. class SyncGlobalErrorTest : public BrowserWithTestWindowTest { public: SyncGlobalErrorTest() {} virtual ~SyncGlobalErrorTest() {} virtual void SetUp() OVERRIDE { profile_.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile()); BrowserWithTestWindowTest::SetUp(); } Profile* profile() { return profile_.get(); } private: scoped_ptr profile_; DISALLOW_COPY_AND_ASSIGN(SyncGlobalErrorTest); }; // Utility function to test that SyncGlobalError behaves correctly for the given // error condition. void VerifySyncGlobalErrorResult(NiceMock* service, FakeLoginUIService* login_ui_service, Browser* browser, SyncErrorController* error, SyncGlobalError* global_error, GoogleServiceAuthError::State error_state, bool is_signed_in, bool is_error) { EXPECT_CALL(*service, HasSyncSetupCompleted()) .WillRepeatedly(Return(is_signed_in)); GoogleServiceAuthError auth_error(error_state); EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error)); error->OnStateChanged(); EXPECT_EQ(is_error, error->HasError()); // If there is an error then a menu item and bubble view should be shown. EXPECT_EQ(is_error, global_error->HasMenuItem()); EXPECT_EQ(is_error, global_error->HasBubbleView()); // If there is an error then labels should not be empty. EXPECT_NE(0, global_error->MenuItemCommandID()); EXPECT_NE(is_error, global_error->MenuItemLabel().empty()); EXPECT_NE(is_error, global_error->GetBubbleViewAcceptButtonLabel().empty()); // We never have a cancel button. EXPECT_TRUE(global_error->GetBubbleViewCancelButtonLabel().empty()); // We always return a hardcoded title. EXPECT_FALSE(global_error->GetBubbleViewTitle().empty()); // Test message handler. if (is_error) { FakeLoginUI* login_ui = static_cast( login_ui_service->current_login_ui()); global_error->ExecuteMenuItem(browser); ASSERT_GT(login_ui->focus_ui_call_count(), 0); global_error->BubbleViewAcceptButtonPressed(browser); global_error->BubbleViewDidClose(browser); } } } // namespace // Test that SyncGlobalError shows an error if a passphrase is required. TEST_F(SyncGlobalErrorTest, PassphraseGlobalError) { NiceMock service(profile()); FakeLoginUIService* login_ui_service = static_cast( LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile(), BuildMockLoginUIService)); FakeLoginUI login_ui; login_ui_service->SetLoginUI(&login_ui); SyncErrorController error(&service); SyncGlobalError global_error(&error, &service); browser_sync::SyncBackendHost::Status status; EXPECT_CALL(service, QueryDetailedSyncStatus(_)) .WillRepeatedly(Return(false)); EXPECT_CALL(service, IsPassphraseRequired()) .WillRepeatedly(Return(true)); EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) .WillRepeatedly(Return(true)); VerifySyncGlobalErrorResult( &service, login_ui_service, browser(), &error, &global_error, GoogleServiceAuthError::NONE, true /* signed in*/, true /* error */); // Check that no menu item is shown if there is no error. EXPECT_CALL(service, IsPassphraseRequired()) .WillRepeatedly(Return(false)); EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) .WillRepeatedly(Return(false)); VerifySyncGlobalErrorResult( &service, login_ui_service, browser(), &error, &global_error, GoogleServiceAuthError::NONE, true /* signed in */, false /* no error */); // Check that no menu item is shown if sync setup is not completed. EXPECT_CALL(service, IsPassphraseRequired()) .WillRepeatedly(Return(true)); EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) .WillRepeatedly(Return(true)); VerifySyncGlobalErrorResult( &service, login_ui_service, browser(), &error, &global_error, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, false /* not signed in */, false /* no error */); global_error.Shutdown(); }