diff options
Diffstat (limited to 'chrome/browser/sync/sync_setup_wizard_unittest.cc')
-rw-r--r-- | chrome/browser/sync/sync_setup_wizard_unittest.cc | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc new file mode 100644 index 0000000..3a04746 --- /dev/null +++ b/chrome/browser/sync/sync_setup_wizard_unittest.cc @@ -0,0 +1,376 @@ +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef CHROME_PERSONALIZATION + +#include "testing/gtest/include/gtest/gtest.h" + +#include "base/json_writer.h" +#include "base/scoped_ptr.h" +#include "base/stl_util-inl.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_setup_flow.h" +#include "chrome/browser/sync/sync_setup_wizard.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/test/browser_with_test_window_test.h" +#include "chrome/test/testing_profile.h" +#include "chrome/test/test_browser_window.h" + +static const char* kTestUser = "chrome.p13n.test@gmail.com"; +static const char* kTestPassword = "passwd"; + +// A PSS subtype to inject. +class ProfileSyncServiceForWizardTest : public ProfileSyncService { + public: + explicit ProfileSyncServiceForWizardTest(Profile* profile) + : ProfileSyncService(profile), user_accepted_merge_and_sync_(false), + user_cancelled_dialog_(false) { + RegisterPreferences(); + } + + virtual ~ProfileSyncServiceForWizardTest() { } + + virtual void OnUserSubmittedAuth(const std::string& username, + const std::string& password) { + username_ = username; + password_ = password; + } + virtual void OnUserAcceptedMergeAndSync() { + user_accepted_merge_and_sync_ = true; + } + virtual void OnUserCancelledDialog() { + user_cancelled_dialog_ = true; + } + + virtual string16 GetAuthenticatedUsername() const { + return UTF8ToUTF16(username_); + } + + void set_auth_state(const std::string& last_email, AuthErrorState state) { + last_attempted_user_email_ = last_email; + last_auth_error_ = state; + } + + void ResetTestStats() { + username_.clear(); + password_.clear(); + user_accepted_merge_and_sync_ = false; + user_cancelled_dialog_ = false; + } + + std::string username_; + std::string password_; + bool user_accepted_merge_and_sync_; + bool user_cancelled_dialog_; + + private: + DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceForWizardTest); +}; + +class TestingProfileWithSyncService : public TestingProfile { + public: + TestingProfileWithSyncService() { + sync_service_.reset(new ProfileSyncServiceForWizardTest(this)); + } + + virtual ProfileSyncService* GetProfileSyncService() { + return sync_service_.get(); + } + private: + scoped_ptr<ProfileSyncService> sync_service_; +}; + +class TestBrowserWindowForWizardTest : public TestBrowserWindow { + public: + explicit TestBrowserWindowForWizardTest(Browser* browser) + : TestBrowserWindow(browser), flow_(NULL), + was_show_html_dialog_called_(false) { + } + + virtual ~TestBrowserWindowForWizardTest() { + if (flow_.get()) { + // In real life, the handlers are destroyed by the DOMUI infrastructure, + // which calls GetDOMMessageHandlers to take ownership. This does not + // exist in our test, so we perform cleanup manually. + std::vector<DOMMessageHandler*> handlers; + flow_->GetDOMMessageHandlers(&handlers); + // The handler contract is that they are valid for the lifetime of the + // HTMLDialogUIDelegate, but are cleaned up after the dialog is closed + // and/or deleted. + flow_.reset(); + STLDeleteElements(&handlers); + } + } + + // We intercept this call to hijack the flow created and then use it to + // drive the wizard as if we were the HTML page. + virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window) { + flow_.reset(static_cast<SyncSetupFlow*>(delegate)); + was_show_html_dialog_called_ = true; + } + + bool TestAndResetWasShowHTMLDialogCalled() { + bool ret = was_show_html_dialog_called_; + was_show_html_dialog_called_ = false; + return ret; + } + + // Simulates the user (or browser view hierarchy) closing the html dialog. + // Handles cleaning up the delegate and associated handlers. + void CloseDialog() { + if (flow_.get()) { + std::vector<DOMMessageHandler*> handlers; + flow_->GetDOMMessageHandlers(&handlers); + // The flow deletes itself here. Don't use reset(). + flow_.release()->OnDialogClosed(""); + STLDeleteElements(&handlers); + } + } + + SyncSetupFlow* flow() { return flow_.get(); } + + private: + // In real life, this is owned by the view that is opened by the browser. We + // mock all that out, so we need to take ownership so the flow doesn't leak. + scoped_ptr<SyncSetupFlow> flow_; + + bool was_show_html_dialog_called_; +}; + +class SyncSetupWizardTest : public BrowserWithTestWindowTest { + public: + SyncSetupWizardTest() : test_window_(NULL), wizard_(NULL) { } + virtual ~SyncSetupWizardTest() { } + virtual void SetUp() { + set_profile(new TestingProfileWithSyncService()); + profile()->CreateBookmarkModel(false); + // Wait for the bookmarks model to load. + profile()->BlockUntilBookmarkModelLoaded(); + set_browser(new Browser(Browser::TYPE_NORMAL, profile())); + test_window_ = new TestBrowserWindowForWizardTest(browser()); + set_window(test_window_); + browser()->set_window(window()); + BrowserList::SetLastActive(browser()); + service_ = static_cast<ProfileSyncServiceForWizardTest*>( + profile()->GetProfileSyncService()); + wizard_.reset(new SyncSetupWizard(service_)); + } + + virtual void TearDown() { + test_window_ = NULL; + service_ = NULL; + wizard_.reset(); + } + + TestBrowserWindowForWizardTest* test_window_; + scoped_ptr<SyncSetupWizard> wizard_; + ProfileSyncServiceForWizardTest* service_; +}; + +TEST_F(SyncSetupWizardTest, InitialStepLogin) { + DictionaryValue dialog_args; + SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); + std::string json_start_args; + JSONWriter::Write(&dialog_args, false, &json_start_args); + ListValue credentials; + std::string auth = "{\"user\":\""; + auth += std::string(kTestUser) + "\",\"pass\":\""; + auth += std::string(kTestPassword) + "\"}"; + credentials.Append(new StringValue(auth)); + + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->flow()); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); + EXPECT_EQ(json_start_args, test_window_->flow()->dialog_start_args_); + + // Simulate the user submitting credentials. + test_window_->flow()->flow_handler_->HandleSubmitAuth(&credentials); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + EXPECT_EQ(kTestUser, service_->username_); + EXPECT_EQ(kTestPassword, service_->password_); + EXPECT_FALSE(service_->user_accepted_merge_and_sync_); + EXPECT_FALSE(service_->user_cancelled_dialog_); + service_->ResetTestStats(); + + // Simulate failed credentials. + service_->set_auth_state(kTestUser, AUTH_ERROR_INVALID_GAIA_CREDENTIALS); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + dialog_args.Clear(); + SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); + EXPECT_TRUE(2 == dialog_args.GetSize()); + std::string actual_user; + dialog_args.GetString(L"user", &actual_user); + EXPECT_EQ(kTestUser, actual_user); + int error = -1; + dialog_args.GetInteger(L"error", &error); + EXPECT_EQ(static_cast<int>(AUTH_ERROR_INVALID_GAIA_CREDENTIALS), error); + service_->set_auth_state(kTestUser, AUTH_ERROR_NONE); + + // Simulate success. + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, + test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::DONE); // No merge and sync. + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->current_state_); +} + +TEST_F(SyncSetupWizardTest, InitialStepMergeAndSync) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->end_state_); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + + test_window_->flow()->flow_handler_->HandleSubmitMergeAndSync(NULL); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + EXPECT_EQ(std::string(), service_->username_); + EXPECT_EQ(std::string(), service_->password_); + EXPECT_TRUE(service_->user_accepted_merge_and_sync_); + EXPECT_FALSE(service_->user_cancelled_dialog_); + service_->ResetTestStats(); + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); // No merge and sync. + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + EXPECT_EQ(SyncSetupWizard::DONE_FIRST_TIME, + test_window_->flow()->current_state_); +} + +TEST_F(SyncSetupWizardTest, DialogCancelled) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + // Simulate the user closing the dialog. + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->user_cancelled_dialog_); + EXPECT_EQ(std::string(), service_->username_); + EXPECT_EQ(std::string(), service_->password_); + EXPECT_FALSE(service_->user_accepted_merge_and_sync_); + + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->user_cancelled_dialog_); + EXPECT_EQ(std::string(), service_->username_); + EXPECT_EQ(std::string(), service_->password_); + EXPECT_FALSE(service_->user_accepted_merge_and_sync_); +} + +TEST_F(SyncSetupWizardTest, InvalidTransitions) { + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::DONE); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::DONE); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); + EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_EQ(SyncSetupWizard::MERGE_AND_SYNC, + test_window_->flow()->current_state_); + + wizard_->Step(SyncSetupWizard::FATAL_ERROR); + EXPECT_EQ(SyncSetupWizard::FATAL_ERROR, test_window_->flow()->current_state_); +} + +TEST_F(SyncSetupWizardTest, FullSuccessfulRunSetsPref) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + wizard_->Step(SyncSetupWizard::DONE); + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( + prefs::kSyncHasSetupCompleted)); +} + +TEST_F(SyncSetupWizardTest, FirstFullSuccessfulRunSetsPref) { + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); + test_window_->CloseDialog(); + EXPECT_FALSE(wizard_->IsVisible()); + EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean( + prefs::kSyncHasSetupCompleted)); +} + +TEST_F(SyncSetupWizardTest, DiscreteRun) { + DictionaryValue dialog_args; + // For a discrete run, we need to have ran through setup once. + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC); + wizard_->Step(SyncSetupWizard::DONE); + test_window_->CloseDialog(); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); + + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_EQ(SyncSetupWizard::GAIA_SUCCESS, test_window_->flow()->end_state_); + + service_->set_auth_state(kTestUser, AUTH_ERROR_INVALID_GAIA_CREDENTIALS); + wizard_->Step(SyncSetupWizard::GAIA_LOGIN); + EXPECT_TRUE(wizard_->IsVisible()); + SyncSetupFlow::GetArgsForGaiaLogin(service_, &dialog_args); + EXPECT_TRUE(2 == dialog_args.GetSize()); + std::string actual_user; + dialog_args.GetString(L"user", &actual_user); + EXPECT_EQ(kTestUser, actual_user); + int error = -1; + dialog_args.GetInteger(L"error", &error); + EXPECT_EQ(static_cast<int>(AUTH_ERROR_INVALID_GAIA_CREDENTIALS), error); + service_->set_auth_state(kTestUser, AUTH_ERROR_NONE); + + wizard_->Step(SyncSetupWizard::GAIA_SUCCESS); + EXPECT_TRUE(test_window_->TestAndResetWasShowHTMLDialogCalled()); +} + +#endif // CHROME_PERSONALIZATION |