Home | History | Annotate | Download | only in sync
      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 "base/basictypes.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/app/chrome_command_ids.h"
     10 #include "chrome/browser/signin/signin_manager.h"
     11 #include "chrome/browser/signin/signin_manager_factory.h"
     12 #include "chrome/browser/sync/profile_sync_service_mock.h"
     13 #include "chrome/browser/ui/browser.h"
     14 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
     15 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
     16 #include "chrome/test/base/browser_with_test_window_test.h"
     17 #include "chrome/test/base/testing_profile.h"
     18 #include "content/public/test/test_browser_thread.h"
     19 #include "testing/gmock/include/gmock/gmock-actions.h"
     20 #include "testing/gmock/include/gmock/gmock.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 using ::testing::NiceMock;
     24 using ::testing::Return;
     25 using ::testing::ReturnRef;
     26 using ::testing::_;
     27 using content::BrowserThread;
     28 
     29 namespace {
     30 
     31 #if 0
     32 // TODO(altimofeev) See below.
     33 class BrowserMock: public Browser {
     34  public:
     35   explicit BrowserMock(Type type, Profile* profile) : Browser(type, profile) {}
     36 
     37   MOCK_METHOD2(ExecuteCommandWithDisposition,
     38                void(int command_id, WindowOpenDisposition));
     39 };
     40 #endif
     41 
     42 class FakeLoginUIService: public LoginUIService {
     43  public:
     44   FakeLoginUIService() : LoginUIService(NULL) {}
     45 };
     46 
     47 class FakeLoginUI : public LoginUIService::LoginUI {
     48  public:
     49   FakeLoginUI() : focus_ui_call_count_(0) {}
     50 
     51   virtual ~FakeLoginUI() {}
     52 
     53   int focus_ui_call_count() const { return focus_ui_call_count_; }
     54 
     55  private:
     56   // Overridden from LoginUIService::LoginUI:
     57   virtual void FocusUI() OVERRIDE {
     58     ++focus_ui_call_count_;
     59   }
     60   virtual void CloseUI() OVERRIDE {}
     61 
     62   int focus_ui_call_count_;
     63 };
     64 
     65 BrowserContextKeyedService* BuildMockLoginUIService(
     66     content::BrowserContext* profile) {
     67   return new FakeLoginUIService();
     68 }
     69 
     70 // Same as BrowserWithTestWindowTest, but uses MockBrowser to test calls to
     71 // ExecuteCommand method.
     72 class SyncGlobalErrorTest : public BrowserWithTestWindowTest {
     73  public:
     74   SyncGlobalErrorTest() {}
     75   virtual ~SyncGlobalErrorTest() {}
     76 
     77 #if 0
     78   // TODO(altimofeev): see below.
     79   virtual void SetUp() OVERRIDE {
     80     testing::Test::SetUp();
     81 
     82     set_profile(CreateProfile());
     83     set_browser(new BrowserMock(Browser::TYPE_TABBED, profile()));
     84     set_window(new TestBrowserWindow(browser()));
     85     browser()->SetWindowForTesting(window());
     86   }
     87 
     88   virtual void TearDown() OVERRIDE {
     89     testing::Test::TearDown();
     90   }
     91 #endif
     92 
     93  private:
     94   DISALLOW_COPY_AND_ASSIGN(SyncGlobalErrorTest);
     95 };
     96 
     97 // Utility function to test that SyncGlobalError behaves correct for the given
     98 // error condition.
     99 void VerifySyncGlobalErrorResult(NiceMock<ProfileSyncServiceMock>* service,
    100                                  FakeLoginUIService* login_ui_service,
    101                                  Browser* browser,
    102                                  SyncGlobalError* error,
    103                                  GoogleServiceAuthError::State error_state,
    104                                  bool is_signed_in,
    105                                  bool is_error) {
    106   EXPECT_CALL(*service, HasSyncSetupCompleted())
    107               .WillRepeatedly(Return(is_signed_in));
    108 
    109   GoogleServiceAuthError auth_error(error_state);
    110   EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
    111 
    112   error->OnStateChanged();
    113 
    114   // If there is an error then a menu item and bubble view should be shown.
    115   EXPECT_EQ(error->HasMenuItem(), is_error);
    116   EXPECT_EQ(error->HasBubbleView(), is_error);
    117 
    118   // If there is an error then labels should not be empty.
    119   EXPECT_NE(error->MenuItemCommandID(), 0);
    120   EXPECT_NE(error->MenuItemLabel().empty(), is_error);
    121   EXPECT_NE(error->GetBubbleViewAcceptButtonLabel().empty(), is_error);
    122 
    123   // We never have a cancel button.
    124   EXPECT_TRUE(error->GetBubbleViewCancelButtonLabel().empty());
    125   // We always return a hardcoded title.
    126   EXPECT_FALSE(error->GetBubbleViewTitle().empty());
    127 
    128 #if defined(OS_CHROMEOS)
    129   // TODO(altimofeev): Implement this in a way that doesn't involve subclassing
    130   //                   Browser or using GMock on browser/ui types which is
    131   //                   banned. Consider observing NOTIFICATION_APP_TERMINATING
    132   //                   instead.
    133   //                   http://crbug.com/134675
    134 #else
    135 #if defined(OS_CHROMEOS)
    136   if (error_state != GoogleServiceAuthError::NONE) {
    137     // In CrOS sign-in/sign-out is made to fix the error.
    138     EXPECT_CALL(*static_cast<BrowserMock*>(browser),
    139                 ExecuteCommandWithDisposition(IDC_EXIT, _));
    140     error->ExecuteMenuItem(browser);
    141   }
    142 #else
    143   // Test message handler.
    144   if (is_error) {
    145     FakeLoginUI* login_ui = static_cast<FakeLoginUI*>(
    146         login_ui_service->current_login_ui());
    147     error->ExecuteMenuItem(browser);
    148     ASSERT_GT(login_ui->focus_ui_call_count(), 0);
    149     error->BubbleViewAcceptButtonPressed(browser);
    150     error->BubbleViewDidClose(browser);
    151   }
    152 #endif
    153 #endif
    154 }
    155 
    156 } // namespace
    157 
    158 // Test that SyncGlobalError shows an error if a passphrase is required.
    159 TEST_F(SyncGlobalErrorTest, PassphraseGlobalError) {
    160   scoped_ptr<Profile> profile(
    161       ProfileSyncServiceMock::MakeSignedInTestingProfile());
    162   NiceMock<ProfileSyncServiceMock> service(profile.get());
    163   SigninManagerBase* signin =
    164       SigninManagerFactory::GetForProfile(profile.get());
    165   FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>(
    166       LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse(
    167           profile.get(), BuildMockLoginUIService));
    168   FakeLoginUI login_ui;
    169   login_ui_service->SetLoginUI(&login_ui);
    170   SyncGlobalError error(&service, signin);
    171 
    172   browser_sync::SyncBackendHost::Status status;
    173   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
    174               .WillRepeatedly(Return(false));
    175 
    176   EXPECT_CALL(service, IsPassphraseRequired())
    177               .WillRepeatedly(Return(true));
    178   EXPECT_CALL(service, IsPassphraseRequiredForDecryption())
    179               .WillRepeatedly(Return(true));
    180   VerifySyncGlobalErrorResult(
    181       &service, login_ui_service, browser(), &error,
    182       GoogleServiceAuthError::NONE, true, true);
    183 }
    184