From 38dc6d7d2e7f36490dbe6aed60cccfc76b11af45 Mon Sep 17 00:00:00 2001 From: "akalin@chromium.org" Date: Fri, 16 Oct 2009 02:43:28 +0000 Subject: TBR: nick@chromium.org git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29240 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/browser_window.h | 2 +- chrome/browser/sync/profile_sync_service.h | 2 +- chrome/browser/sync/sync_setup_flow.cc | 304 ----------------- chrome/browser/sync/sync_setup_flow.h | 189 ----------- chrome/browser/sync/sync_setup_wizard.cc | 199 ----------- chrome/browser/sync/sync_setup_wizard.h | 82 ----- chrome/browser/sync/sync_setup_wizard_unittest.cc | 376 --------------------- .../browser/sync/util/character_set_converters.h | 15 - chrome/browser/sync/util/user_settings_unittest.cc | 12 +- .../browser/tab_contents/tab_contents_view_mac.mm | 12 +- chrome/browser/views/sync/sync_setup_flow.cc | 301 +++++++++++++++++ chrome/browser/views/sync/sync_setup_flow.h | 189 +++++++++++ chrome/browser/views/sync/sync_setup_wizard.cc | 199 +++++++++++ chrome/browser/views/sync/sync_setup_wizard.h | 81 +++++ .../views/sync/sync_setup_wizard_unittest.cc | 376 +++++++++++++++++++++ 15 files changed, 1156 insertions(+), 1183 deletions(-) delete mode 100644 chrome/browser/sync/sync_setup_flow.cc delete mode 100644 chrome/browser/sync/sync_setup_flow.h delete mode 100644 chrome/browser/sync/sync_setup_wizard.cc delete mode 100644 chrome/browser/sync/sync_setup_wizard.h delete mode 100644 chrome/browser/sync/sync_setup_wizard_unittest.cc create mode 100644 chrome/browser/views/sync/sync_setup_flow.cc create mode 100644 chrome/browser/views/sync/sync_setup_flow.h create mode 100644 chrome/browser/views/sync/sync_setup_wizard.cc create mode 100644 chrome/browser/views/sync/sync_setup_wizard.h create mode 100644 chrome/browser/views/sync/sync_setup_wizard_unittest.cc (limited to 'chrome/browser') diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index f417166..a83fbbd 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -31,7 +31,7 @@ class Rect; // BrowserWindow interface // An interface implemented by the "view" of the Browser window. // -// NOTE: All getters may return NULL. +// NOTE: All getters except GetTabStrip() may return NULL. class BrowserWindow { public: // Show the window, or activates it if it's already visible. diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index 9eedbef..fab7ea5 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -20,7 +20,7 @@ #include "chrome/browser/sync/glue/change_processor.h" #include "chrome/browser/sync/glue/model_associator.h" #include "chrome/browser/sync/glue/sync_backend_host.h" -#include "chrome/browser/sync/sync_setup_wizard.h" +#include "chrome/browser/views/sync/sync_setup_wizard.h" #include "chrome/common/notification_registrar.h" #include "googleurl/src/gurl.h" diff --git a/chrome/browser/sync/sync_setup_flow.cc b/chrome/browser/sync/sync_setup_flow.cc deleted file mode 100644 index 2784572..0000000 --- a/chrome/browser/sync/sync_setup_flow.cc +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (c) 2009 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. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/sync_setup_flow.h" - -#include "app/gfx/font.h" -#include "app/gfx/font_util.h" -#include "base/histogram.h" -#include "base/json_reader.h" -#include "base/json_writer.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "base/values.h" -#include "chrome/browser/browser.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/sync/auth_error_state.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/common/pref_names.h" -#include "grit/locale_settings.h" - -// XPath expression for finding specific iframes. -static const wchar_t* kLoginIFrameXPath = L"//iframe[@id='login']"; -static const wchar_t* kMergeIFrameXPath = L"//iframe[@id='merge']"; -static const wchar_t* kDoneIframeXPath = L"//iframe[@id='done']"; - -// Helper function to read the JSON string from the Value parameter. -static std::string GetJsonResponse(const Value* content) { - if (!content || !content->IsType(Value::TYPE_LIST)) { - NOTREACHED(); - return std::string(); - } - const ListValue* args = static_cast(content); - if (args->GetSize() != 1) { - NOTREACHED(); - return std::string(); - } - - std::string result; - Value* value = NULL; - if (!args->Get(0, &value) || !value->GetAsString(&result)) { - NOTREACHED(); - return std::string(); - } - - return result; -} - -void FlowHandler::RegisterMessages() { - dom_ui_->RegisterMessageCallback("SubmitAuth", - NewCallback(this, &FlowHandler::HandleSubmitAuth)); - dom_ui_->RegisterMessageCallback("SubmitMergeAndSync", - NewCallback(this, &FlowHandler::HandleSubmitMergeAndSync)); -} - -static bool GetUsernameAndPassword(const std::string& json, - std::string* username, std::string* password) { - scoped_ptr parsed_value(JSONReader::Read(json, false)); - if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) - return false; - - DictionaryValue* result = static_cast(parsed_value.get()); - if (!result->GetString(L"user", username) || - !result->GetString(L"pass", password)) { - return false; - } - return true; -} - -void FlowHandler::HandleSubmitAuth(const Value* value) { - std::string json(GetJsonResponse(value)); - std::string username, password; - if (json.empty()) - return; - - if (!GetUsernameAndPassword(json, &username, &password)) { - // The page sent us something that we didn't understand. - // This probably indicates a programming error. - NOTREACHED(); - return; - } - - if (flow_) - flow_->OnUserSubmittedAuth(username, password); -} - -void FlowHandler::HandleSubmitMergeAndSync(const Value* value) { - if (flow_) - flow_->OnUserAcceptedMergeAndSync(); -} - -// Called by SyncSetupFlow::Advance. -void FlowHandler::ShowGaiaLogin(const DictionaryValue& args) { - std::string json; - JSONWriter::Write(&args, false, &json); - std::wstring javascript = std::wstring(L"showGaiaLogin") + - L"(" + UTF8ToWide(json) + L");"; - ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); -} - -void FlowHandler::ShowGaiaSuccessAndClose() { - ExecuteJavascriptInIFrame(kLoginIFrameXPath, L"showGaiaSuccessAndClose();"); -} - -void FlowHandler::ShowGaiaSuccessAndSettingUp() { - ExecuteJavascriptInIFrame(kLoginIFrameXPath, - L"showGaiaSuccessAndSettingUp();"); -} - -void FlowHandler::ShowMergeAndSync() { - if (dom_ui_) // NULL during testing. - dom_ui_->CallJavascriptFunction(L"showMergeAndSync"); -} - -void FlowHandler::ShowSetupDone(const std::wstring& user) { - StringValue synced_to_string(WideToUTF8(l10n_util::GetStringF( - IDS_SYNC_NTP_SYNCED_TO, user))); - std::string json; - JSONWriter::Write(&synced_to_string, false, &json); - std::wstring javascript = std::wstring(L"setSyncedToUser") + - L"(" + UTF8ToWide(json) + L");"; - ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); - - if (dom_ui_) - dom_ui_->CallJavascriptFunction(L"showSetupDone", synced_to_string); -} - -void FlowHandler::ShowFirstTimeDone(const std::wstring& user) { - ExecuteJavascriptInIFrame(kDoneIframeXPath, - L"setShowFirstTimeSetupSummary();"); - ShowSetupDone(user); -} - -void FlowHandler::ShowMergeAndSyncError() { - ExecuteJavascriptInIFrame(kMergeIFrameXPath, L"showMergeAndSyncError();"); -} - -void FlowHandler::ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, - const std::wstring& js) { - if (dom_ui_) { - RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); - rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); - } -} - -SyncSetupFlow::~SyncSetupFlow() { - flow_handler_->set_flow(NULL); -} - -void SyncSetupFlow::GetDialogSize(gfx::Size* size) const { - PrefService* prefs = service_->profile()->GetPrefs(); - gfx::Font approximate_web_font = gfx::Font::CreateFont( - prefs->GetString(prefs::kWebKitSansSerifFontFamily), - prefs->GetInteger(prefs::kWebKitDefaultFontSize)); - - gfx::Size s = gfx::GetLocalizedContentsSizeForFont( - IDS_SYNC_SETUP_WIZARD_WIDTH_CHARS, - IDS_SYNC_SETUP_WIZARD_HEIGHT_LINES, - approximate_web_font); - - size->set_width(s.width()); - size->set_height(s.height()); -} - -// A callback to notify the delegate that the dialog closed. -void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) { - DCHECK(json_retval.empty()); - container_->set_flow(NULL); // Sever ties from the wizard. - if (current_state_ == SyncSetupWizard::DONE || - current_state_ == SyncSetupWizard::DONE_FIRST_TIME) { - service_->SetSyncSetupCompleted(); - } - - // Record the state at which the user cancelled the signon dialog. - switch (current_state_) { - case SyncSetupWizard::GAIA_LOGIN: - ProfileSyncService::SyncEvent( - ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); - break; - case SyncSetupWizard::GAIA_SUCCESS: - ProfileSyncService::SyncEvent( - ProfileSyncService::CANCEL_DURING_SIGNON); - break; - case SyncSetupWizard::MERGE_AND_SYNC: - ProfileSyncService::SyncEvent( - ProfileSyncService::CANCEL_DURING_SIGNON_AFTER_MERGE); - break; - case SyncSetupWizard::DONE_FIRST_TIME: - case SyncSetupWizard::DONE: - UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime", - base::TimeTicks::Now() - login_start_time_); - break; - default: - break; - } - - service_->OnUserCancelledDialog(); - delete this; -} - -// static -void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service, - DictionaryValue* args) { - AuthErrorState error(service->GetAuthErrorState()); - if (!service->last_attempted_user_email().empty()) { - args->SetString(L"user", service->last_attempted_user_email()); - args->SetInteger(L"error", error); - } else { - std::wstring user(UTF16ToWide(service->GetAuthenticatedUsername())); - args->SetString(L"user", user); - args->SetInteger(L"error", user.empty() ? 0 : error); - } -} - -void SyncSetupFlow::GetDOMMessageHandlers( - std::vector* handlers) const { - handlers->push_back(flow_handler_); -} - -bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) { - switch (state) { - case SyncSetupWizard::GAIA_LOGIN: - return current_state_ == SyncSetupWizard::GAIA_LOGIN; - case SyncSetupWizard::GAIA_SUCCESS: - return current_state_ == SyncSetupWizard::GAIA_LOGIN; - case SyncSetupWizard::MERGE_AND_SYNC: - return current_state_ == SyncSetupWizard::GAIA_SUCCESS; - case SyncSetupWizard::FATAL_ERROR: - return true; // You can always hit the panic button. - case SyncSetupWizard::DONE_FIRST_TIME: - case SyncSetupWizard::DONE: - return current_state_ == SyncSetupWizard::MERGE_AND_SYNC || - current_state_ == SyncSetupWizard::GAIA_SUCCESS; - default: - NOTREACHED() << "Unhandled State: " << state; - return false; - } -} - -void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) { - if (!ShouldAdvance(advance_state)) - return; - switch (advance_state) { - case SyncSetupWizard::GAIA_LOGIN: { - DictionaryValue args; - SyncSetupFlow::GetArgsForGaiaLogin(service_, &args); - flow_handler_->ShowGaiaLogin(args); - break; - } - case SyncSetupWizard::GAIA_SUCCESS: - if (end_state_ == SyncSetupWizard::GAIA_SUCCESS) - flow_handler_->ShowGaiaSuccessAndClose(); - else - flow_handler_->ShowGaiaSuccessAndSettingUp(); - break; - case SyncSetupWizard::MERGE_AND_SYNC: - flow_handler_->ShowMergeAndSync(); - break; - case SyncSetupWizard::FATAL_ERROR: - if (current_state_ == SyncSetupWizard::MERGE_AND_SYNC) - flow_handler_->ShowMergeAndSyncError(); - break; - case SyncSetupWizard::DONE_FIRST_TIME: - flow_handler_->ShowFirstTimeDone( - UTF16ToWide(service_->GetAuthenticatedUsername())); - break; - case SyncSetupWizard::DONE: - flow_handler_->ShowSetupDone( - UTF16ToWide(service_->GetAuthenticatedUsername())); - break; - default: - NOTREACHED() << "Invalid advance state: " << advance_state; - } - current_state_ = advance_state; -} - -// static -SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service, - SyncSetupFlowContainer* container, - SyncSetupWizard::State start, - SyncSetupWizard::State end) { - DictionaryValue args; - if (start == SyncSetupWizard::GAIA_LOGIN) - SyncSetupFlow::GetArgsForGaiaLogin(service, &args); - std::string json_args; - JSONWriter::Write(&args, false, &json_args); - - Browser* b = BrowserList::GetLastActive(); - if (!b) - return NULL; - - FlowHandler* handler = new FlowHandler(); - SyncSetupFlow* flow = new SyncSetupFlow(start, end, json_args, - container, handler, service); - handler->set_flow(flow); - b->BrowserShowHtmlDialog(flow, NULL); - return flow; -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_setup_flow.h b/chrome/browser/sync/sync_setup_flow.h deleted file mode 100644 index 32e3db1..0000000 --- a/chrome/browser/sync/sync_setup_flow.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifdef CHROME_PERSONALIZATION - -#ifndef CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_ -#define CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_ - -#include -#include - -#include "app/l10n_util.h" -#include "base/time.h" -#include "chrome/browser/dom_ui/html_dialog_ui.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/sync/sync_setup_wizard.h" -#include "grit/generated_resources.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -class FlowHandler; -class SyncSetupFlowContainer; - -// The state machine used by SyncSetupWizard, exposed in its own header -// to facilitate testing of SyncSetupWizard. This class is used to open and -// run the html dialog and deletes itself when the dialog closes. -class SyncSetupFlow : public HtmlDialogUIDelegate { - public: - virtual ~SyncSetupFlow(); - - // Runs a flow from |start| to |end|, and does the work of actually showing - // the HTML dialog. |container| is kept up-to-date with the lifetime of the - // flow (e.g it is emptied on dialog close). - static SyncSetupFlow* Run(ProfileSyncService* service, - SyncSetupFlowContainer* container, - SyncSetupWizard::State start, - SyncSetupWizard::State end); - - // Fills |args| with "user" and "error" arguments by querying |service|. - static void GetArgsForGaiaLogin( - const ProfileSyncService* service, - DictionaryValue* args); - - // Triggers a state machine transition to advance_state. - void Advance(SyncSetupWizard::State advance_state); - - // HtmlDialogUIDelegate implementation. - // Get the HTML file path for the content to load in the dialog. - virtual GURL GetDialogContentURL() const { - return GURL("chrome://syncresources/setup"); - } - - // HtmlDialogUIDelegate implementation. - virtual void GetDOMMessageHandlers( - std::vector* handlers) const; - - // HtmlDialogUIDelegate implementation. - // Get the size of the dialog. - virtual void GetDialogSize(gfx::Size* size) const; - - // HtmlDialogUIDelegate implementation. - // Gets the JSON string input to use when opening the dialog. - virtual std::string GetDialogArgs() const { - return dialog_start_args_; - } - - // HtmlDialogUIDelegate implementation. - // A callback to notify the delegate that the dialog closed. - virtual void OnDialogClosed(const std::string& json_retval); - - // HtmlDialogUIDelegate implementation. - virtual std::wstring GetDialogTitle() const { - return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL); - } - - // HtmlDialogUIDelegate implementation. - virtual bool IsDialogModal() const { - return false; - } - - void OnUserSubmittedAuth(const std::string& username, - const std::string& password) { - service_->OnUserSubmittedAuth(username, password); - } - - void OnUserAcceptedMergeAndSync() { - service_->OnUserAcceptedMergeAndSync(); - } - - private: - FRIEND_TEST(SyncSetupWizardTest, InitialStepLogin); - FRIEND_TEST(SyncSetupWizardTest, InitialStepMergeAndSync); - FRIEND_TEST(SyncSetupWizardTest, DialogCancelled); - FRIEND_TEST(SyncSetupWizardTest, InvalidTransitions); - FRIEND_TEST(SyncSetupWizardTest, FullSuccessfulRunSetsPref); - FRIEND_TEST(SyncSetupWizardTest, DiscreteRun); - - // Use static Run method to get an instance. - SyncSetupFlow(SyncSetupWizard::State start_state, - SyncSetupWizard::State end_state, - const std::string& args, SyncSetupFlowContainer* container, - FlowHandler* handler, ProfileSyncService* service) - : container_(container), - dialog_start_args_(args), - current_state_(start_state), - end_state_(end_state), - login_start_time_(base::TimeTicks::Now()), - flow_handler_(handler), - service_(service) { - } - - // Returns true if |this| should transition its state machine to |state| - // based on |current_state_|, or false if that would be nonsense or is - // a no-op. - bool ShouldAdvance(SyncSetupWizard::State state); - - SyncSetupFlowContainer* container_; // Our container. Don't own this. - std::string dialog_start_args_; // The args to pass to the initial page. - - SyncSetupWizard::State current_state_; - SyncSetupWizard::State end_state_; // The goal. - - // Time that the GAIA_LOGIN step was received. - base::TimeTicks login_start_time_; - - // The handler needed for the entire flow. We don't own this. - FlowHandler* flow_handler_; - - // We need this to write the sentinel "setup completed" pref. - ProfileSyncService* service_; - - DISALLOW_COPY_AND_ASSIGN(SyncSetupFlow); -}; - -// A really simple wrapper for a SyncSetupFlow so that we don't have to -// add any public methods to the public SyncSetupWizard interface to notify it -// when the dialog closes. -class SyncSetupFlowContainer { - public: - SyncSetupFlowContainer() : flow_(NULL) { } - void set_flow(SyncSetupFlow* flow) { - DCHECK(!flow_ || !flow); - flow_ = flow; - } - - SyncSetupFlow* get_flow() { return flow_; } - private: - SyncSetupFlow* flow_; - - DISALLOW_COPY_AND_ASSIGN(SyncSetupFlowContainer); -}; - -// The FlowHandler connects the state machine to the dialog backing HTML and -// JS namespace by implementing DOMMessageHandler and being invoked by the -// SyncSetupFlow. Exposed here to facilitate testing. -class FlowHandler : public DOMMessageHandler { - public: - FlowHandler() {} - virtual ~FlowHandler() {} - - // DOMMessageHandler implementation. - virtual void RegisterMessages(); - - // Callbacks from the page. - void HandleSubmitAuth(const Value* value); - void HandleSubmitMergeAndSync(const Value* value); - - // These functions control which part of the HTML is visible. - void ShowGaiaLogin(const DictionaryValue& args); - void ShowGaiaSuccessAndClose(); - void ShowGaiaSuccessAndSettingUp(); - void ShowMergeAndSync(); - void ShowMergeAndSyncError(); - void ShowSetupDone(const std::wstring& user); - void ShowFirstTimeDone(const std::wstring& user); - - void set_flow(SyncSetupFlow* flow) { - flow_ = flow; - } - - private: - void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, - const std::wstring& js); - SyncSetupFlow* flow_; - DISALLOW_COPY_AND_ASSIGN(FlowHandler); -}; - -#endif // CHROME_BROWSER_SYNC_SYNC_SETUP_FLOW_H_ -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_setup_wizard.cc b/chrome/browser/sync/sync_setup_wizard.cc deleted file mode 100644 index 7d00ab9..0000000 --- a/chrome/browser/sync/sync_setup_wizard.cc +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifdef CHROME_PERSONALIZATION - -#include "chrome/browser/sync/sync_setup_wizard.h" - -#include "app/resource_bundle.h" -#include "base/message_loop.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/pref_service.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/dom_ui/chrome_url_data_manager.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/sync/sync_setup_flow.h" -#include "chrome/common/jstemplate_builder.h" -#include "chrome/common/url_constants.h" -#include "grit/app_resources.h" -#include "grit/browser_resources.h" - -class SyncResourcesSource : public ChromeURLDataManager::DataSource { - public: - SyncResourcesSource() - : DataSource(chrome::kSyncResourcesHost, MessageLoop::current()) { - } - virtual ~SyncResourcesSource() { } - - virtual void StartDataRequest(const std::string& path, int request_id); - - virtual std::string GetMimeType(const std::string& path) const { - if (path == chrome::kSyncThrobberPath) - return "image/png"; - else - return "text/html"; - } - private: - DISALLOW_COPY_AND_ASSIGN(SyncResourcesSource); -}; - -void SyncResourcesSource::StartDataRequest(const std::string& path_raw, - int request_id) { - scoped_refptr html_bytes(new RefCountedBytes); - if (path_raw == chrome::kSyncThrobberPath) { - ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER, - &html_bytes->data); - SendResponse(request_id, html_bytes); - return; - } - - std::string response; - if (path_raw == chrome::kSyncGaiaLoginPath) { - DictionaryValue localized_strings; - localized_strings.SetString(L"settingupsync", - l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP_SYNC)); - localized_strings.SetString(L"introduction", - l10n_util::GetString(IDS_SYNC_LOGIN_INTRODUCTION)); - localized_strings.SetString(L"signinprefix", - l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_PREFIX)); - localized_strings.SetString(L"signinsuffix", - l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_SUFFIX)); - localized_strings.SetString(L"cannotbeblank", - l10n_util::GetString(IDS_SYNC_CANNOT_BE_BLANK)); - localized_strings.SetString(L"emaillabel", - l10n_util::GetString(IDS_SYNC_LOGIN_EMAIL)); - localized_strings.SetString(L"passwordlabel", - l10n_util::GetString(IDS_SYNC_LOGIN_PASSWORD)); - localized_strings.SetString(L"invalidcredentials", - l10n_util::GetString(IDS_SYNC_INVALID_USER_CREDENTIALS)); - localized_strings.SetString(L"signin", - l10n_util::GetString(IDS_SYNC_SIGNIN)); - localized_strings.SetString(L"couldnotconnect", - l10n_util::GetString(IDS_SYNC_LOGIN_COULD_NOT_CONNECT)); - localized_strings.SetString(L"cannotaccessaccount", - l10n_util::GetString(IDS_SYNC_CANNOT_ACCESS_ACCOUNT)); - localized_strings.SetString(L"createaccount", - l10n_util::GetString(IDS_SYNC_CREATE_ACCOUNT)); - localized_strings.SetString(L"cancel", - l10n_util::GetString(IDS_CANCEL)); - localized_strings.SetString(L"settingup", - l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP)); - localized_strings.SetString(L"success", - l10n_util::GetString(IDS_SYNC_SUCCESS)); - localized_strings.SetString(L"errorsigningin", - l10n_util::GetString(IDS_SYNC_ERROR_SIGNING_IN)); - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_GAIA_LOGIN_HTML)); - SetFontAndTextDirection(&localized_strings); - response = jstemplate_builder::GetI18nTemplateHtml( - html, &localized_strings); - } else if (path_raw == chrome::kSyncMergeAndSyncPath) { - DictionaryValue localized_strings; - localized_strings.SetString(L"introduction", - l10n_util::GetString(IDS_SYNC_MERGE_INTRODUCTION)); - localized_strings.SetString(L"mergeandsynclabel", - l10n_util::GetString(IDS_SYNC_MERGE_AND_SYNC_LABEL)); - localized_strings.SetString(L"abortlabel", - l10n_util::GetString(IDS_ABORT)); - localized_strings.SetString(L"closelabel", - l10n_util::GetString(IDS_CLOSE)); - localized_strings.SetString(L"mergeandsyncwarning", - l10n_util::GetString(IDS_SYNC_MERGE_WARNING)); - localized_strings.SetString(L"setuperror", - l10n_util::GetString(IDS_SYNC_SETUP_ERROR)); - - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML)); - SetFontAndTextDirection(&localized_strings); - response = jstemplate_builder::GetI18nTemplateHtml( - html, &localized_strings); - } else if (path_raw == chrome::kSyncSetupDonePath) { - DictionaryValue localized_strings; - localized_strings.SetString(L"success", - l10n_util::GetString(IDS_SYNC_SUCCESS)); - localized_strings.SetString(L"setupsummary", - l10n_util::GetString(IDS_SYNC_SETUP_ALL_DONE)); - localized_strings.SetString(L"firsttimesetupsummary", - l10n_util::GetString(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE)); - localized_strings.SetString(L"okay", - l10n_util::GetString(IDS_SYNC_SETUP_OK_BUTTON_LABEL)); - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_SYNC_SETUP_DONE_HTML)); - SetFontAndTextDirection(&localized_strings); - response = jstemplate_builder::GetI18nTemplateHtml( - html, &localized_strings); - } else if (path_raw == chrome::kSyncSetupFlowPath) { - static const base::StringPiece html(ResourceBundle::GetSharedInstance() - .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML)); - response = html.as_string(); - } - // Send the response. - html_bytes->data.resize(response.size()); - std::copy(response.begin(), response.end(), html_bytes->data.begin()); - SendResponse(request_id, html_bytes); -} - -SyncSetupWizard::SyncSetupWizard(ProfileSyncService* service) - : service_(service), - flow_container_(new SyncSetupFlowContainer()) { - // Register data sources for HTML content we require. - // g_browser_process and/or io_thread may not exist during testing. - if (g_browser_process && g_browser_process->io_thread()) { - // Add our network layer data source for 'cloudy' URLs. - g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(&chrome_url_data_manager, - &ChromeURLDataManager::AddDataSource, - new SyncResourcesSource())); - } -} - -SyncSetupWizard::~SyncSetupWizard() { - delete flow_container_; -} - -void SyncSetupWizard::Step(State advance_state) { - SyncSetupFlow* flow = flow_container_->get_flow(); - if (flow) { - // A setup flow is in progress and dialog is currently showing. - flow->Advance(advance_state); - } else if (!service_->profile()->GetPrefs()->GetBoolean( - prefs::kSyncHasSetupCompleted)) { - if (IsTerminalState(advance_state)) - return; - // No flow is in progress, and we have never escorted the user all the - // way through the wizard flow. - flow_container_->set_flow( - SyncSetupFlow::Run(service_, flow_container_, advance_state, DONE)); - } else { - // No flow in in progress, but we've finished the wizard flow once before. - // This is just a discrete run. - if (IsTerminalState(advance_state)) - return; // Nothing to do. - flow_container_->set_flow(SyncSetupFlow::Run(service_, flow_container_, - advance_state, GetEndStateForDiscreteRun(advance_state))); - } -} - -// static -bool SyncSetupWizard::IsTerminalState(State advance_state) { - return advance_state == GAIA_SUCCESS || - advance_state == DONE || - advance_state == DONE_FIRST_TIME || - advance_state == FATAL_ERROR; -} - -bool SyncSetupWizard::IsVisible() const { - return flow_container_->get_flow() != NULL; -} - -// static -SyncSetupWizard::State SyncSetupWizard::GetEndStateForDiscreteRun( - State start_state) { - State result = start_state == GAIA_LOGIN ? GAIA_SUCCESS : DONE; - DCHECK_NE(DONE, result) << - "Invalid start state for discrete run: " << start_state; - return result; -} - -#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/sync/sync_setup_wizard.h b/chrome/browser/sync/sync_setup_wizard.h deleted file mode 100644 index d8a0d95..0000000 --- a/chrome/browser/sync/sync_setup_wizard.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifndef CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_ -#define CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_ - -#include "base/basictypes.h" - -#if defined(OS_LINUX) -typedef struct _GtkWidget GtkWidget; -typedef struct _GtkWindow GtkWindow; -#else -class SyncSetupFlowContainer; -#endif - -class ProfileSyncService; - -class SyncSetupWizard { - public: - enum State { - // Show the Google Account login UI. - GAIA_LOGIN = 0, - // A login attempt succeeded. Depending on initial conditions, this may - // cause a transition to DONE, or to wait for an explicit transition (via - // Step) to the next state. - GAIA_SUCCESS, - // The user needs to accept a merge and sync warning to proceed. - MERGE_AND_SYNC, - // The panic switch. Something went terribly wrong during setup and we - // can't recover. - FATAL_ERROR, - // A final state for when setup completes and it is possible it is the - // user's first time (globally speaking) as the cloud doesn't have any - // bookmarks. We show additional info in this case to explain setting up - // more computers. - DONE_FIRST_TIME, - // A catch-all done case for any setup process. - DONE - }; - - explicit SyncSetupWizard(ProfileSyncService* service); - ~SyncSetupWizard(); - - // Advances the wizard to the specified state if possible, or opens a - // new dialog starting at |advance_state|. If the wizard has never ran - // through to completion, it will always attempt to do so. Otherwise, e.g - // for a transient auth failure, it will just run as far as is necessary - // based on |advance_state| (so for auth failure, up to GAIA_SUCCESS). - void Step(State advance_state); - - // Whether or not a dialog is currently showing. Useful to determine - // if various buttons in the UI should be enabled or disabled. - bool IsVisible() const; - -#if defined(OS_LINUX) - void SetVisible(bool visible) { visible_ = visible; } -#endif - - private: - // If we just need to pop open an individual dialog, say to collect - // gaia credentials in the event of a steady-state auth failure, this is - // a "discrete" run (as in not a continuous wizard flow). This returns - // the end state to pass to Run for a given |start_state|. - static State GetEndStateForDiscreteRun(State start_state); - - // Helper to return whether |state| warrants starting a new flow. - static bool IsTerminalState(State state); - - ProfileSyncService* service_; - -#if defined(OS_LINUX) - bool visible_; -#else - SyncSetupFlowContainer* flow_container_; -#endif - - DISALLOW_COPY_AND_ASSIGN(SyncSetupWizard); -}; - -#endif // CHROME_BROWSER_SYNC_SYNC_SETUP_WIZARD_H_ - diff --git a/chrome/browser/sync/sync_setup_wizard_unittest.cc b/chrome/browser/sync/sync_setup_wizard_unittest.cc deleted file mode 100644 index 3a04746..0000000 --- a/chrome/browser/sync/sync_setup_wizard_unittest.cc +++ /dev/null @@ -1,376 +0,0 @@ -// 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 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 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(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 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 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( - profile()->GetProfileSyncService()); - wizard_.reset(new SyncSetupWizard(service_)); - } - - virtual void TearDown() { - test_window_ = NULL; - service_ = NULL; - wizard_.reset(); - } - - TestBrowserWindowForWizardTest* test_window_; - scoped_ptr 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(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(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 diff --git a/chrome/browser/sync/util/character_set_converters.h b/chrome/browser/sync/util/character_set_converters.h index 6a833ee..1db32c7 100644 --- a/chrome/browser/sync/util/character_set_converters.h +++ b/chrome/browser/sync/util/character_set_converters.h @@ -136,21 +136,6 @@ inline void AppendPathStringToUTF8(const PathString& wide, return AppendPathStringToUTF8(wide.data(), wide.length(), output_string); } -// Versions of UTF8ToPathString/PathStringToUTF8 that return the converted -// string directly. Any errors encountered will CHECK(). These functions are -// intended to be used only for testing. - -inline PathString UTF8ToPathStringQuick(const std::string &utf8) { - PathString wide; - CHECK(UTF8ToPathString(utf8.data(), utf8.size(), &wide)); - return wide; -} - -inline std::string PathStringToUTF8Quick(const PathString& wide) { - std::string utf8; - PathStringToUTF8(wide.data(), wide.size(), &utf8); - return utf8; -} inline bool Append(const PathChar* wide, int size, std::string* output_string) { diff --git a/chrome/browser/sync/util/user_settings_unittest.cc b/chrome/browser/sync/util/user_settings_unittest.cc index 02f3fd8..952c86b 100644 --- a/chrome/browser/sync/util/user_settings_unittest.cc +++ b/chrome/browser/sync/util/user_settings_unittest.cc @@ -2,12 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE entry. -#include - #include "base/file_util.h" #include "base/test/test_file_util.h" #include "chrome/browser/sync/syncable/directory_manager.h" -#include "chrome/browser/sync/util/character_set_converters.h" #include "chrome/browser/sync/util/user_settings.h" #include "chrome/browser/sync/util/query_helpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -43,10 +40,15 @@ class UserSettingsTest : public testing::Test { ExecOrDie(primer_handle, "CREATE TABLE shares" " (email, share_name, file_name," " PRIMARY KEY(email, share_name) ON CONFLICT REPLACE)"); +#if OS_WIN + // Populate a share. + ExecOrDie(primer_handle, "INSERT INTO shares values ( ?, ?, ?)", + "foo@foo.com", "foo@foo.com", WideToUTF8(kOldStyleSyncDataDB)); +#elif OS_LINUX // Populate a share. ExecOrDie(primer_handle, "INSERT INTO shares values ( ?, ?, ?)", - "foo@foo.com", "foo@foo.com", - browser_sync::PathStringToUTF8Quick(kOldStyleSyncDataDB)); + "foo@foo.com", "foo@foo.com", kOldStyleSyncDataDB); +#endif sqlite3_close(primer_handle); } diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.mm b/chrome/browser/tab_contents/tab_contents_view_mac.mm index c966ee8..21b4970 100644 --- a/chrome/browser/tab_contents/tab_contents_view_mac.mm +++ b/chrome/browser/tab_contents/tab_contents_view_mac.mm @@ -16,7 +16,6 @@ #include "chrome/browser/cocoa/sad_tab_view.h" #import "chrome/browser/cocoa/web_drag_source.h" #import "chrome/browser/cocoa/web_drop_target.h" -#include "chrome/browser/renderer_host/render_view_host_factory.h" #include "chrome/browser/renderer_host/render_widget_host.h" #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" #include "chrome/browser/tab_contents/render_view_context_menu_mac.h" @@ -72,16 +71,7 @@ void TabContentsViewMac::CreateView(const gfx::Size& initial_size) { RenderWidgetHostView* TabContentsViewMac::CreateViewForWidget( RenderWidgetHost* render_widget_host) { - if (render_widget_host->view()) { - // During testing, the view will already be set up in most cases to the - // test view, so we don't want to clobber it with a real one. To verify that - // this actually is happening (and somebody isn't accidentally creating the - // view twice), we check for the RVH Factory, which will be set when we're - // making special ones (which go along with the special views). - DCHECK(RenderViewHostFactory::has_factory()); - return render_widget_host->view(); - } - + DCHECK(!render_widget_host->view()); RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(render_widget_host); diff --git a/chrome/browser/views/sync/sync_setup_flow.cc b/chrome/browser/views/sync/sync_setup_flow.cc new file mode 100644 index 0000000..01a5728 --- /dev/null +++ b/chrome/browser/views/sync/sync_setup_flow.cc @@ -0,0 +1,301 @@ +// Copyright (c) 2009 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. + +#ifdef CHROME_PERSONALIZATION + +#include "chrome/browser/views/sync/sync_setup_flow.h" + +#include "app/gfx/font.h" +#include "base/histogram.h" +#include "base/json_reader.h" +#include "base/json_writer.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/sync/auth_error_state.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/pref_names.h" +#include "grit/locale_settings.h" +#include "views/window/window.h" + +// XPath expression for finding specific iframes. +static const wchar_t* kLoginIFrameXPath = L"//iframe[@id='login']"; +static const wchar_t* kMergeIFrameXPath = L"//iframe[@id='merge']"; +static const wchar_t* kDoneIframeXPath = L"//iframe[@id='done']"; + +// Helper function to read the JSON string from the Value parameter. +static std::string GetJsonResponse(const Value* content) { + if (!content || !content->IsType(Value::TYPE_LIST)) { + NOTREACHED(); + return std::string(); + } + const ListValue* args = static_cast(content); + if (args->GetSize() != 1) { + NOTREACHED(); + return std::string(); + } + + std::string result; + Value* value = NULL; + if (!args->Get(0, &value) || !value->GetAsString(&result)) { + NOTREACHED(); + return std::string(); + } + + return result; +} + +void FlowHandler::RegisterMessages() { + dom_ui_->RegisterMessageCallback("SubmitAuth", + NewCallback(this, &FlowHandler::HandleSubmitAuth)); + dom_ui_->RegisterMessageCallback("SubmitMergeAndSync", + NewCallback(this, &FlowHandler::HandleSubmitMergeAndSync)); +} + +static bool GetUsernameAndPassword(const std::string& json, + std::string* username, std::string* password) { + scoped_ptr parsed_value(JSONReader::Read(json, false)); + if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) + return false; + + DictionaryValue* result = static_cast(parsed_value.get()); + if (!result->GetString(L"user", username) || + !result->GetString(L"pass", password)) { + return false; + } + return true; +} + +void FlowHandler::HandleSubmitAuth(const Value* value) { + std::string json(GetJsonResponse(value)); + std::string username, password; + if (json.empty()) + return; + + if (!GetUsernameAndPassword(json, &username, &password)) { + // The page sent us something that we didn't understand. + // This probably indicates a programming error. + NOTREACHED(); + return; + } + + if (flow_) + flow_->OnUserSubmittedAuth(username, password); +} + +void FlowHandler::HandleSubmitMergeAndSync(const Value* value) { + if (flow_) + flow_->OnUserAcceptedMergeAndSync(); +} + +// Called by SyncSetupFlow::Advance. +void FlowHandler::ShowGaiaLogin(const DictionaryValue& args) { + std::string json; + JSONWriter::Write(&args, false, &json); + std::wstring javascript = std::wstring(L"showGaiaLogin") + + L"(" + UTF8ToWide(json) + L");"; + ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); +} + +void FlowHandler::ShowGaiaSuccessAndClose() { + ExecuteJavascriptInIFrame(kLoginIFrameXPath, L"showGaiaSuccessAndClose();"); +} + +void FlowHandler::ShowGaiaSuccessAndSettingUp() { + ExecuteJavascriptInIFrame(kLoginIFrameXPath, + L"showGaiaSuccessAndSettingUp();"); +} + +void FlowHandler::ShowMergeAndSync() { + if (dom_ui_) // NULL during testing. + dom_ui_->CallJavascriptFunction(L"showMergeAndSync"); +} + +void FlowHandler::ShowSetupDone(const std::wstring& user) { + StringValue synced_to_string(WideToUTF8(l10n_util::GetStringF( + IDS_SYNC_NTP_SYNCED_TO, user))); + std::string json; + JSONWriter::Write(&synced_to_string, false, &json); + std::wstring javascript = std::wstring(L"setSyncedToUser") + + L"(" + UTF8ToWide(json) + L");"; + ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); + + if (dom_ui_) + dom_ui_->CallJavascriptFunction(L"showSetupDone", synced_to_string); +} + +void FlowHandler::ShowFirstTimeDone(const std::wstring& user) { + ExecuteJavascriptInIFrame(kDoneIframeXPath, + L"setShowFirstTimeSetupSummary();"); + ShowSetupDone(user); +} + +void FlowHandler::ShowMergeAndSyncError() { + ExecuteJavascriptInIFrame(kMergeIFrameXPath, L"showMergeAndSyncError();"); +} + +void FlowHandler::ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, + const std::wstring& js) { + if (dom_ui_) { + RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); + rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); + } +} + +SyncSetupFlow::~SyncSetupFlow() { + flow_handler_->set_flow(NULL); +} + +void SyncSetupFlow::GetDialogSize(gfx::Size* size) const { + PrefService* prefs = service_->profile()->GetPrefs(); + gfx::Font approximate_web_font = gfx::Font::CreateFont( + prefs->GetString(prefs::kWebKitSansSerifFontFamily), + prefs->GetInteger(prefs::kWebKitDefaultFontSize)); + + gfx::Size s = views::Window::GetLocalizedContentsSizeForFont( + IDS_SYNC_SETUP_WIZARD_WIDTH_CHARS, + IDS_SYNC_SETUP_WIZARD_HEIGHT_LINES, + approximate_web_font); + + size->set_width(s.width()); + size->set_height(s.height()); +} + +// A callback to notify the delegate that the dialog closed. +void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) { + DCHECK(json_retval.empty()); + container_->set_flow(NULL); // Sever ties from the wizard. + if (current_state_ == SyncSetupWizard::DONE || + current_state_ == SyncSetupWizard::DONE_FIRST_TIME) { + service_->SetSyncSetupCompleted(); + } + + // Record the state at which the user cancelled the signon dialog. + switch (current_state_) { + case SyncSetupWizard::GAIA_LOGIN: + ProfileSyncService::SyncEvent( + ProfileSyncService::CANCEL_FROM_SIGNON_WITHOUT_AUTH); + break; + case SyncSetupWizard::GAIA_SUCCESS: + ProfileSyncService::SyncEvent( + ProfileSyncService::CANCEL_DURING_SIGNON); + break; + case SyncSetupWizard::MERGE_AND_SYNC: + ProfileSyncService::SyncEvent( + ProfileSyncService::CANCEL_DURING_SIGNON_AFTER_MERGE); + break; + case SyncSetupWizard::DONE_FIRST_TIME: + case SyncSetupWizard::DONE: + UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime", + base::TimeTicks::Now() - login_start_time_); + break; + default: + break; + } + + service_->OnUserCancelledDialog(); + delete this; +} + +// static +void SyncSetupFlow::GetArgsForGaiaLogin(const ProfileSyncService* service, + DictionaryValue* args) { + AuthErrorState error(service->GetAuthErrorState()); + if (!service->last_attempted_user_email().empty()) { + args->SetString(L"user", service->last_attempted_user_email()); + args->SetInteger(L"error", error); + } else { + std::wstring user(UTF16ToWide(service->GetAuthenticatedUsername())); + args->SetString(L"user", user); + args->SetInteger(L"error", user.empty() ? 0 : error); + } +} + +void SyncSetupFlow::GetDOMMessageHandlers( + std::vector* handlers) const { + handlers->push_back(flow_handler_); +} + +bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) { + switch (state) { + case SyncSetupWizard::GAIA_LOGIN: + return current_state_ == SyncSetupWizard::GAIA_LOGIN; + case SyncSetupWizard::GAIA_SUCCESS: + return current_state_ == SyncSetupWizard::GAIA_LOGIN; + case SyncSetupWizard::MERGE_AND_SYNC: + return current_state_ == SyncSetupWizard::GAIA_SUCCESS; + case SyncSetupWizard::FATAL_ERROR: + return true; // You can always hit the panic button. + case SyncSetupWizard::DONE_FIRST_TIME: + case SyncSetupWizard::DONE: + return current_state_ == SyncSetupWizard::MERGE_AND_SYNC || + current_state_ == SyncSetupWizard::GAIA_SUCCESS; + default: + NOTREACHED() << "Unhandled State: " << state; + return false; + } +} + +void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) { + if (!ShouldAdvance(advance_state)) + return; + switch (advance_state) { + case SyncSetupWizard::GAIA_LOGIN: { + DictionaryValue args; + SyncSetupFlow::GetArgsForGaiaLogin(service_, &args); + flow_handler_->ShowGaiaLogin(args); + break; + } + case SyncSetupWizard::GAIA_SUCCESS: + if (end_state_ == SyncSetupWizard::GAIA_SUCCESS) + flow_handler_->ShowGaiaSuccessAndClose(); + else + flow_handler_->ShowGaiaSuccessAndSettingUp(); + break; + case SyncSetupWizard::MERGE_AND_SYNC: + flow_handler_->ShowMergeAndSync(); + break; + case SyncSetupWizard::FATAL_ERROR: + if (current_state_ == SyncSetupWizard::MERGE_AND_SYNC) + flow_handler_->ShowMergeAndSyncError(); + break; + case SyncSetupWizard::DONE_FIRST_TIME: + flow_handler_->ShowFirstTimeDone(service_->GetAuthenticatedUsername()); + break; + case SyncSetupWizard::DONE: + flow_handler_->ShowSetupDone(service_->GetAuthenticatedUsername()); + break; + default: + NOTREACHED() << "Invalid advance state: " << advance_state; + } + current_state_ = advance_state; +} + +// static +SyncSetupFlow* SyncSetupFlow::Run(ProfileSyncService* service, + SyncSetupFlowContainer* container, + SyncSetupWizard::State start, + SyncSetupWizard::State end) { + DictionaryValue args; + if (start == SyncSetupWizard::GAIA_LOGIN) + SyncSetupFlow::GetArgsForGaiaLogin(service, &args); + std::string json_args; + JSONWriter::Write(&args, false, &json_args); + + Browser* b = BrowserList::GetLastActive(); + if (!b) + return NULL; + + FlowHandler* handler = new FlowHandler(); + SyncSetupFlow* flow = new SyncSetupFlow(start, end, json_args, + container, handler, service); + handler->set_flow(flow); + b->BrowserShowHtmlDialog(flow, NULL); + return flow; +} + +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/views/sync/sync_setup_flow.h b/chrome/browser/views/sync/sync_setup_flow.h new file mode 100644 index 0000000..4bc7d60 --- /dev/null +++ b/chrome/browser/views/sync/sync_setup_flow.h @@ -0,0 +1,189 @@ +// Copyright (c) 2006-2008 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. + +#ifdef CHROME_PERSONALIZATION + +#ifndef CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_FLOW_H_ +#define CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_FLOW_H_ + +#include +#include + +#include "app/l10n_util.h" +#include "base/time.h" +#include "chrome/browser/dom_ui/html_dialog_ui.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/views/sync/sync_setup_wizard.h" +#include "grit/generated_resources.h" +#include "testing/gtest/include/gtest/gtest_prod.h" + +class FlowHandler; +class SyncSetupFlowContainer; + +// The state machine used by SyncSetupWizard, exposed in its own header +// to facilitate testing of SyncSetupWizard. This class is used to open and +// run the html dialog and deletes itself when the dialog closes. +class SyncSetupFlow : public HtmlDialogUIDelegate { + public: + virtual ~SyncSetupFlow(); + + // Runs a flow from |start| to |end|, and does the work of actually showing + // the HTML dialog. |container| is kept up-to-date with the lifetime of the + // flow (e.g it is emptied on dialog close). + static SyncSetupFlow* Run(ProfileSyncService* service, + SyncSetupFlowContainer* container, + SyncSetupWizard::State start, + SyncSetupWizard::State end); + + // Fills |args| with "user" and "error" arguments by querying |service|. + static void GetArgsForGaiaLogin( + const ProfileSyncService* service, + DictionaryValue* args); + + // Triggers a state machine transition to advance_state. + void Advance(SyncSetupWizard::State advance_state); + + // HtmlDialogUIDelegate implementation. + // Get the HTML file path for the content to load in the dialog. + virtual GURL GetDialogContentURL() const { + return GURL("chrome://syncresources/setup"); + } + + // HtmlDialogUIDelegate implementation. + virtual void GetDOMMessageHandlers( + std::vector* handlers) const; + + // HtmlDialogUIDelegate implementation. + // Get the size of the dialog. + virtual void GetDialogSize(gfx::Size* size) const; + + // HtmlDialogUIDelegate implementation. + // Gets the JSON string input to use when opening the dialog. + virtual std::string GetDialogArgs() const { + return dialog_start_args_; + } + + // HtmlDialogUIDelegate implementation. + // A callback to notify the delegate that the dialog closed. + virtual void OnDialogClosed(const std::string& json_retval); + + // HtmlDialogUIDelegate implementation. + virtual std::wstring GetDialogTitle() const { + return l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL); + } + + // HtmlDialogUIDelegate implementation. + virtual bool IsDialogModal() const { + return false; + } + + void OnUserSubmittedAuth(const std::string& username, + const std::string& password) { + service_->OnUserSubmittedAuth(username, password); + } + + void OnUserAcceptedMergeAndSync() { + service_->OnUserAcceptedMergeAndSync(); + } + + private: + FRIEND_TEST(SyncSetupWizardTest, InitialStepLogin); + FRIEND_TEST(SyncSetupWizardTest, InitialStepMergeAndSync); + FRIEND_TEST(SyncSetupWizardTest, DialogCancelled); + FRIEND_TEST(SyncSetupWizardTest, InvalidTransitions); + FRIEND_TEST(SyncSetupWizardTest, FullSuccessfulRunSetsPref); + FRIEND_TEST(SyncSetupWizardTest, DiscreteRun); + + // Use static Run method to get an instance. + SyncSetupFlow(SyncSetupWizard::State start_state, + SyncSetupWizard::State end_state, + const std::string& args, SyncSetupFlowContainer* container, + FlowHandler* handler, ProfileSyncService* service) + : container_(container), + dialog_start_args_(args), + current_state_(start_state), + end_state_(end_state), + login_start_time_(base::TimeTicks::Now()), + flow_handler_(handler), + service_(service) { + } + + // Returns true if |this| should transition its state machine to |state| + // based on |current_state_|, or false if that would be nonsense or is + // a no-op. + bool ShouldAdvance(SyncSetupWizard::State state); + + SyncSetupFlowContainer* container_; // Our container. Don't own this. + std::string dialog_start_args_; // The args to pass to the initial page. + + SyncSetupWizard::State current_state_; + SyncSetupWizard::State end_state_; // The goal. + + // Time that the GAIA_LOGIN step was received. + base::TimeTicks login_start_time_; + + // The handler needed for the entire flow. We don't own this. + FlowHandler* flow_handler_; + + // We need this to write the sentinel "setup completed" pref. + ProfileSyncService* service_; + + DISALLOW_COPY_AND_ASSIGN(SyncSetupFlow); +}; + +// A really simple wrapper for a SyncSetupFlow so that we don't have to +// add any public methods to the public SyncSetupWizard interface to notify it +// when the dialog closes. +class SyncSetupFlowContainer { + public: + SyncSetupFlowContainer() : flow_(NULL) { } + void set_flow(SyncSetupFlow* flow) { + DCHECK(!flow_ || !flow); + flow_ = flow; + } + + SyncSetupFlow* get_flow() { return flow_; } + private: + SyncSetupFlow* flow_; + + DISALLOW_COPY_AND_ASSIGN(SyncSetupFlowContainer); +}; + +// The FlowHandler connects the state machine to the dialog backing HTML and +// JS namespace by implementing DOMMessageHandler and being invoked by the +// SyncSetupFlow. Exposed here to facilitate testing. +class FlowHandler : public DOMMessageHandler { + public: + FlowHandler() {} + virtual ~FlowHandler() {} + + // DOMMessageHandler implementation. + virtual void RegisterMessages(); + + // Callbacks from the page. + void HandleSubmitAuth(const Value* value); + void HandleSubmitMergeAndSync(const Value* value); + + // These functions control which part of the HTML is visible. + void ShowGaiaLogin(const DictionaryValue& args); + void ShowGaiaSuccessAndClose(); + void ShowGaiaSuccessAndSettingUp(); + void ShowMergeAndSync(); + void ShowMergeAndSyncError(); + void ShowSetupDone(const std::wstring& user); + void ShowFirstTimeDone(const std::wstring& user); + + void set_flow(SyncSetupFlow* flow) { + flow_ = flow; + } + + private: + void ExecuteJavascriptInIFrame(const std::wstring& iframe_xpath, + const std::wstring& js); + SyncSetupFlow* flow_; + DISALLOW_COPY_AND_ASSIGN(FlowHandler); +}; + +#endif // CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_FLOW_H_ +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/views/sync/sync_setup_wizard.cc b/chrome/browser/views/sync/sync_setup_wizard.cc new file mode 100644 index 0000000..31afcea --- /dev/null +++ b/chrome/browser/views/sync/sync_setup_wizard.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2006-2008 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. + +#ifdef CHROME_PERSONALIZATION + +#include "chrome/browser/views/sync/sync_setup_wizard.h" + +#include "app/resource_bundle.h" +#include "base/message_loop.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/views/sync/sync_setup_flow.h" +#include "chrome/common/jstemplate_builder.h" +#include "chrome/common/url_constants.h" +#include "grit/app_resources.h" +#include "grit/browser_resources.h" + +class SyncResourcesSource : public ChromeURLDataManager::DataSource { + public: + SyncResourcesSource() + : DataSource(chrome::kSyncResourcesHost, MessageLoop::current()) { + } + virtual ~SyncResourcesSource() { } + + virtual void StartDataRequest(const std::string& path, int request_id); + + virtual std::string GetMimeType(const std::string& path) const { + if (path == chrome::kSyncThrobberPath) + return "image/png"; + else + return "text/html"; + } + private: + DISALLOW_COPY_AND_ASSIGN(SyncResourcesSource); +}; + +void SyncResourcesSource::StartDataRequest(const std::string& path_raw, + int request_id) { + scoped_refptr html_bytes(new RefCountedBytes); + if (path_raw == chrome::kSyncThrobberPath) { + ResourceBundle::GetSharedInstance().LoadImageResourceBytes(IDR_THROBBER, + &html_bytes->data); + SendResponse(request_id, html_bytes); + return; + } + + std::string response; + if (path_raw == chrome::kSyncGaiaLoginPath) { + DictionaryValue localized_strings; + localized_strings.SetString(L"settingupsync", + l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP_SYNC)); + localized_strings.SetString(L"introduction", + l10n_util::GetString(IDS_SYNC_LOGIN_INTRODUCTION)); + localized_strings.SetString(L"signinprefix", + l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_PREFIX)); + localized_strings.SetString(L"signinsuffix", + l10n_util::GetString(IDS_SYNC_LOGIN_SIGNIN_SUFFIX)); + localized_strings.SetString(L"cannotbeblank", + l10n_util::GetString(IDS_SYNC_CANNOT_BE_BLANK)); + localized_strings.SetString(L"emaillabel", + l10n_util::GetString(IDS_SYNC_LOGIN_EMAIL)); + localized_strings.SetString(L"passwordlabel", + l10n_util::GetString(IDS_SYNC_LOGIN_PASSWORD)); + localized_strings.SetString(L"invalidcredentials", + l10n_util::GetString(IDS_SYNC_INVALID_USER_CREDENTIALS)); + localized_strings.SetString(L"signin", + l10n_util::GetString(IDS_SYNC_SIGNIN)); + localized_strings.SetString(L"couldnotconnect", + l10n_util::GetString(IDS_SYNC_LOGIN_COULD_NOT_CONNECT)); + localized_strings.SetString(L"cannotaccessaccount", + l10n_util::GetString(IDS_SYNC_CANNOT_ACCESS_ACCOUNT)); + localized_strings.SetString(L"createaccount", + l10n_util::GetString(IDS_SYNC_CREATE_ACCOUNT)); + localized_strings.SetString(L"cancel", + l10n_util::GetString(IDS_CANCEL)); + localized_strings.SetString(L"settingup", + l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP)); + localized_strings.SetString(L"success", + l10n_util::GetString(IDS_SYNC_SUCCESS)); + localized_strings.SetString(L"errorsigningin", + l10n_util::GetString(IDS_SYNC_ERROR_SIGNING_IN)); + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_GAIA_LOGIN_HTML)); + SetFontAndTextDirection(&localized_strings); + response = jstemplate_builder::GetI18nTemplateHtml( + html, &localized_strings); + } else if (path_raw == chrome::kSyncMergeAndSyncPath) { + DictionaryValue localized_strings; + localized_strings.SetString(L"introduction", + l10n_util::GetString(IDS_SYNC_MERGE_INTRODUCTION)); + localized_strings.SetString(L"mergeandsynclabel", + l10n_util::GetString(IDS_SYNC_MERGE_AND_SYNC_LABEL)); + localized_strings.SetString(L"abortlabel", + l10n_util::GetString(IDS_ABORT)); + localized_strings.SetString(L"closelabel", + l10n_util::GetString(IDS_CLOSE)); + localized_strings.SetString(L"mergeandsyncwarning", + l10n_util::GetString(IDS_SYNC_MERGE_WARNING)); + localized_strings.SetString(L"setuperror", + l10n_util::GetString(IDS_SYNC_SETUP_ERROR)); + + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_MERGE_AND_SYNC_HTML)); + SetFontAndTextDirection(&localized_strings); + response = jstemplate_builder::GetI18nTemplateHtml( + html, &localized_strings); + } else if (path_raw == chrome::kSyncSetupDonePath) { + DictionaryValue localized_strings; + localized_strings.SetString(L"success", + l10n_util::GetString(IDS_SYNC_SUCCESS)); + localized_strings.SetString(L"setupsummary", + l10n_util::GetString(IDS_SYNC_SETUP_ALL_DONE)); + localized_strings.SetString(L"firsttimesetupsummary", + l10n_util::GetString(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE)); + localized_strings.SetString(L"okay", + l10n_util::GetString(IDS_SYNC_SETUP_OK_BUTTON_LABEL)); + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_SYNC_SETUP_DONE_HTML)); + SetFontAndTextDirection(&localized_strings); + response = jstemplate_builder::GetI18nTemplateHtml( + html, &localized_strings); + } else if (path_raw == chrome::kSyncSetupFlowPath) { + static const base::StringPiece html(ResourceBundle::GetSharedInstance() + .GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML)); + response = html.as_string(); + } + // Send the response. + html_bytes->data.resize(response.size()); + std::copy(response.begin(), response.end(), html_bytes->data.begin()); + SendResponse(request_id, html_bytes); +} + +SyncSetupWizard::SyncSetupWizard(ProfileSyncService* service) + : service_(service), + flow_container_(new SyncSetupFlowContainer()) { + // Register data sources for HTML content we require. + // g_browser_process and/or io_thread may not exist during testing. + if (g_browser_process && g_browser_process->io_thread()) { + // Add our network layer data source for 'cloudy' URLs. + g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(&chrome_url_data_manager, + &ChromeURLDataManager::AddDataSource, + new SyncResourcesSource())); + } +} + +SyncSetupWizard::~SyncSetupWizard() { + delete flow_container_; +} + +void SyncSetupWizard::Step(State advance_state) { + SyncSetupFlow* flow = flow_container_->get_flow(); + if (flow) { + // A setup flow is in progress and dialog is currently showing. + flow->Advance(advance_state); + } else if (!service_->profile()->GetPrefs()->GetBoolean( + prefs::kSyncHasSetupCompleted)) { + if (IsTerminalState(advance_state)) + return; + // No flow is in progress, and we have never escorted the user all the + // way through the wizard flow. + flow_container_->set_flow( + SyncSetupFlow::Run(service_, flow_container_, advance_state, DONE)); + } else { + // No flow in in progress, but we've finished the wizard flow once before. + // This is just a discrete run. + if (IsTerminalState(advance_state)) + return; // Nothing to do. + flow_container_->set_flow(SyncSetupFlow::Run(service_, flow_container_, + advance_state, GetEndStateForDiscreteRun(advance_state))); + } +} + +// static +bool SyncSetupWizard::IsTerminalState(State advance_state) { + return advance_state == GAIA_SUCCESS || + advance_state == DONE || + advance_state == DONE_FIRST_TIME || + advance_state == FATAL_ERROR; +} + +bool SyncSetupWizard::IsVisible() const { + return flow_container_->get_flow() != NULL; +} + +// static +SyncSetupWizard::State SyncSetupWizard::GetEndStateForDiscreteRun( + State start_state) { + State result = start_state == GAIA_LOGIN ? GAIA_SUCCESS : DONE; + DCHECK_NE(DONE, result) << + "Invalid start state for discrete run: " << start_state; + return result; +} + +#endif // CHROME_PERSONALIZATION diff --git a/chrome/browser/views/sync/sync_setup_wizard.h b/chrome/browser/views/sync/sync_setup_wizard.h new file mode 100644 index 0000000..1d36f61 --- /dev/null +++ b/chrome/browser/views/sync/sync_setup_wizard.h @@ -0,0 +1,81 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_WIZARD_H_ +#define CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_WIZARD_H_ + +#include "base/basictypes.h" + +#if defined(OS_WIN) +class SyncSetupFlowContainer; +#elif defined(OS_LINUX) +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWindow GtkWindow; +#endif + +class ProfileSyncService; + +class SyncSetupWizard { + public: + enum State { + // Show the Google Account login UI. + GAIA_LOGIN = 0, + // A login attempt succeeded. Depending on initial conditions, this may + // cause a transition to DONE, or to wait for an explicit transition (via + // Step) to the next state. + GAIA_SUCCESS, + // The user needs to accept a merge and sync warning to proceed. + MERGE_AND_SYNC, + // The panic switch. Something went terribly wrong during setup and we + // can't recover. + FATAL_ERROR, + // A final state for when setup completes and it is possible it is the + // user's first time (globally speaking) as the cloud doesn't have any + // bookmarks. We show additional info in this case to explain setting up + // more computers. + DONE_FIRST_TIME, + // A catch-all done case for any setup process. + DONE + }; + + explicit SyncSetupWizard(ProfileSyncService* service); + ~SyncSetupWizard(); + + // Advances the wizard to the specified state if possible, or opens a + // new dialog starting at |advance_state|. If the wizard has never ran + // through to completion, it will always attempt to do so. Otherwise, e.g + // for a transient auth failure, it will just run as far as is necessary + // based on |advance_state| (so for auth failure, up to GAIA_SUCCESS). + void Step(State advance_state); + + // Whether or not a dialog is currently showing. Useful to determine + // if various buttons in the UI should be enabled or disabled. + bool IsVisible() const; + +#if defined(OS_LINUX) + void SetVisible(bool visible) { visible_ = visible; } +#endif + + private: + // If we just need to pop open an individual dialog, say to collect + // gaia credentials in the event of a steady-state auth failure, this is + // a "discrete" run (as in not a continuous wizard flow). This returns + // the end state to pass to Run for a given |start_state|. + static State GetEndStateForDiscreteRun(State start_state); + + // Helper to return whether |state| warrants starting a new flow. + static bool IsTerminalState(State state); + + ProfileSyncService* service_; + +#if defined(OS_WIN) + SyncSetupFlowContainer* flow_container_; +#elif defined(OS_LINUX) + bool visible_; +#endif + + DISALLOW_COPY_AND_ASSIGN(SyncSetupWizard); +}; + +#endif // CHROME_BROWSER_VIEWS_SYNC_SYNC_SETUP_WIZARD_H_ diff --git a/chrome/browser/views/sync/sync_setup_wizard_unittest.cc b/chrome/browser/views/sync/sync_setup_wizard_unittest.cc new file mode 100644 index 0000000..fec7ef3 --- /dev/null +++ b/chrome/browser/views/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/views/sync/sync_setup_flow.h" +#include "chrome/browser/views/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 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 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(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 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 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( + profile()->GetProfileSyncService()); + wizard_.reset(new SyncSetupWizard(service_)); + } + + virtual void TearDown() { + test_window_ = NULL; + service_ = NULL; + wizard_.reset(); + } + + TestBrowserWindowForWizardTest* test_window_; + scoped_ptr 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(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(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 -- cgit v1.1