Home | History | Annotate | Download | only in sync
      1 // Copyright 2014 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_error_notifier_ash.h"
      6 
      7 #include "ash/test/ash_test_base.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "chrome/browser/browser_process.h"
     10 #include "chrome/browser/notifications/notification.h"
     11 #include "chrome/browser/notifications/notification_ui_manager.h"
     12 #include "chrome/browser/sync/profile_sync_service_mock.h"
     13 #include "chrome/browser/sync/sync_error_controller.h"
     14 #include "chrome/browser/ui/browser.h"
     15 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
     16 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
     17 #include "chrome/common/pref_names.h"
     18 #include "chrome/test/base/testing_browser_process.h"
     19 #include "chrome/test/base/testing_profile.h"
     20 #include "chrome/test/base/testing_profile_manager.h"
     21 #include "testing/gmock/include/gmock/gmock.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 #include "ui/message_center/notification.h"
     24 
     25 #if defined(OS_WIN)
     26 #include "chrome/browser/ui/ash/ash_util.h"
     27 #include "ui/aura/test/test_screen.h"
     28 #include "ui/gfx/screen.h"
     29 #include "ui/gfx/screen_type_delegate.h"
     30 #endif
     31 
     32 using ::testing::NiceMock;
     33 using ::testing::Return;
     34 using ::testing::ReturnRef;
     35 using ::testing::_;
     36 
     37 namespace ash {
     38 namespace test {
     39 
     40 namespace {
     41 
     42 static const char kTestAccountId[] = "testuser (at) test.com";
     43 
     44 // Notification ID corresponding to kProfileSyncNotificationId + kTestAccountId.
     45 static const std::string kNotificationId =
     46     "chrome://settings/sync/testuser@test.com";
     47 
     48 #if defined(OS_WIN)
     49 class ScreenTypeDelegateDesktop : public gfx::ScreenTypeDelegate {
     50  public:
     51   ScreenTypeDelegateDesktop() {}
     52   virtual ~ScreenTypeDelegateDesktop() {}
     53   virtual gfx::ScreenType GetScreenTypeForNativeView(
     54       gfx::NativeView view) OVERRIDE {
     55     return chrome::IsNativeViewInAsh(view) ?
     56         gfx::SCREEN_TYPE_ALTERNATE :
     57         gfx::SCREEN_TYPE_NATIVE;
     58   }
     59 
     60  private:
     61   DISALLOW_COPY_AND_ASSIGN(ScreenTypeDelegateDesktop);
     62 };
     63 #endif
     64 
     65 class FakeLoginUIService: public LoginUIService {
     66  public:
     67   FakeLoginUIService() : LoginUIService(NULL) {}
     68   virtual ~FakeLoginUIService() {}
     69 };
     70 
     71 class FakeLoginUI : public LoginUIService::LoginUI {
     72  public:
     73   FakeLoginUI() : focus_ui_call_count_(0) {}
     74 
     75   virtual ~FakeLoginUI() {}
     76 
     77   int focus_ui_call_count() const { return focus_ui_call_count_; }
     78 
     79  private:
     80   // LoginUIService::LoginUI:
     81   virtual void FocusUI() OVERRIDE {
     82     ++focus_ui_call_count_;
     83   }
     84   virtual void CloseUI() OVERRIDE {}
     85 
     86   int focus_ui_call_count_;
     87 };
     88 
     89 KeyedService* BuildMockLoginUIService(
     90     content::BrowserContext* profile) {
     91   return new FakeLoginUIService();
     92 }
     93 
     94 class SyncErrorNotifierTest : public AshTestBase  {
     95  public:
     96   SyncErrorNotifierTest() {}
     97   virtual ~SyncErrorNotifierTest() {}
     98 
     99   virtual void SetUp() OVERRIDE {
    100     profile_manager_.reset(
    101         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
    102     ASSERT_TRUE(profile_manager_->SetUp());
    103 
    104     profile_ = profile_manager_->CreateTestingProfile(kTestAccountId);
    105 
    106     TestingBrowserProcess::GetGlobal();
    107     AshTestBase::SetUp();
    108 
    109     // Set up a desktop screen for Windows to hold native widgets, used when
    110     // adding desktop widgets (i.e., message center notifications).
    111 #if defined(OS_WIN)
    112     test_screen_.reset(aura::TestScreen::Create(gfx::Size()));
    113     gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_.get());
    114     gfx::Screen::SetScreenTypeDelegate(new ScreenTypeDelegateDesktop);
    115 #endif
    116 
    117     service_.reset(new NiceMock<ProfileSyncServiceMock>(profile_));
    118 
    119     FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>(
    120         LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse(
    121             profile_, BuildMockLoginUIService));
    122     login_ui_service->SetLoginUI(&login_ui_);
    123 
    124     error_controller_.reset(new SyncErrorController(service_.get()));
    125     error_notifier_.reset(new SyncErrorNotifier(error_controller_.get(),
    126                                                 profile_));
    127 
    128     notification_ui_manager_ = g_browser_process->notification_ui_manager();
    129   }
    130 
    131   virtual void TearDown() OVERRIDE {
    132     error_notifier_->Shutdown();
    133     service_.reset();
    134 #if defined(OS_WIN)
    135     test_screen_.reset();
    136 #endif
    137     profile_manager_.reset();
    138 
    139     AshTestBase::TearDown();
    140   }
    141 
    142  protected:
    143   // Utility function to test that SyncErrorNotifier behaves correctly for the
    144   // given error condition.
    145   void VerifySyncErrorNotifierResult(GoogleServiceAuthError::State error_state,
    146                                      bool is_signed_in,
    147                                      bool is_error) {
    148     EXPECT_CALL(*service_, HasSyncSetupCompleted())
    149                 .WillRepeatedly(Return(is_signed_in));
    150 
    151     GoogleServiceAuthError auth_error(error_state);
    152     EXPECT_CALL(*service_, GetAuthError()).WillRepeatedly(
    153         ReturnRef(auth_error));
    154 
    155     error_controller_->OnStateChanged();
    156     EXPECT_EQ(is_error, error_controller_->HasError());
    157 
    158     // If there is an error we should see a notification.
    159     const Notification* notification = notification_ui_manager_->
    160         FindById(kNotificationId);
    161     if (is_error) {
    162       ASSERT_TRUE(notification);
    163       ASSERT_FALSE(notification->title().empty());
    164       ASSERT_FALSE(notification->title().empty());
    165       ASSERT_EQ((size_t)1, notification->buttons().size());
    166     } else {
    167       ASSERT_FALSE(notification);
    168     }
    169   }
    170 
    171 #if defined(OS_WIN)
    172   scoped_ptr<gfx::Screen> test_screen_;
    173 #endif
    174   scoped_ptr<TestingProfileManager> profile_manager_;
    175   scoped_ptr<SyncErrorController> error_controller_;
    176   scoped_ptr<SyncErrorNotifier> error_notifier_;
    177   scoped_ptr<NiceMock<ProfileSyncServiceMock> > service_;
    178   TestingProfile* profile_;
    179   FakeLoginUI login_ui_;
    180   NotificationUIManager* notification_ui_manager_;
    181 
    182   DISALLOW_COPY_AND_ASSIGN(SyncErrorNotifierTest);
    183 };
    184 
    185 } // namespace
    186 
    187 // Test that SyncErrorNotifier shows an notification if a passphrase is
    188 // required.
    189 // Disabled on Windows: http://crbug.com/373238
    190 #if defined(OS_WIN)
    191 #define MAYBE_PassphraseNotification DISABLED_PassphraseNotification
    192 #else
    193 #define MAYBE_PassphraseNotification PassphraseNotification
    194 #endif
    195 TEST_F(SyncErrorNotifierTest, MAYBE_PassphraseNotification) {
    196   ASSERT_FALSE(notification_ui_manager_->FindById(kNotificationId));
    197 
    198   browser_sync::SyncBackendHost::Status status;
    199   EXPECT_CALL(*service_, QueryDetailedSyncStatus(_))
    200               .WillRepeatedly(Return(false));
    201 
    202   EXPECT_CALL(*service_, IsPassphraseRequired())
    203               .WillRepeatedly(Return(true));
    204   EXPECT_CALL(*service_, IsPassphraseRequiredForDecryption())
    205               .WillRepeatedly(Return(true));
    206   {
    207     SCOPED_TRACE("Expected a notification for passphrase error");
    208     VerifySyncErrorNotifierResult(GoogleServiceAuthError::NONE,
    209                                   true /* signed in */,
    210                                   true /* error */);
    211   }
    212 
    213   // Check that no notification is shown if there is no error.
    214   EXPECT_CALL(*service_, IsPassphraseRequired())
    215               .WillRepeatedly(Return(false));
    216   EXPECT_CALL(*service_, IsPassphraseRequiredForDecryption())
    217               .WillRepeatedly(Return(false));
    218   {
    219     SCOPED_TRACE("Not expecting notification since no error exists");
    220     VerifySyncErrorNotifierResult(GoogleServiceAuthError::NONE,
    221                                   true /* signed in */,
    222                                   false /* no error */);
    223   }
    224 
    225   // Check that no notification is shown if sync setup is not completed.
    226   EXPECT_CALL(*service_, IsPassphraseRequired())
    227               .WillRepeatedly(Return(true));
    228   EXPECT_CALL(*service_, IsPassphraseRequiredForDecryption())
    229               .WillRepeatedly(Return(true));
    230   {
    231     SCOPED_TRACE("Not expecting notification since sync setup is incomplete");
    232     VerifySyncErrorNotifierResult(
    233         GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
    234         false /* not signed in */,
    235         false /* no error */);
    236   }
    237 }
    238 
    239 }  // namespace test
    240 }  // namespace ash
    241