diff options
author | vabr@chromium.org <vabr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-14 10:04:22 +0000 |
---|---|---|
committer | vabr@chromium.org <vabr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-14 10:04:22 +0000 |
commit | 7e1ffcfe761f3ac9e0d34612e3c23f5a41229206 (patch) | |
tree | 1f85578782f6ad9e7c6097833846e40e3b3a3c4d | |
parent | 0c0a0365581443aefc3bb51e25fc5e37bd021772 (diff) | |
download | chromium_src-7e1ffcfe761f3ac9e0d34612e3c23f5a41229206.zip chromium_src-7e1ffcfe761f3ac9e0d34612e3c23f5a41229206.tar.gz chromium_src-7e1ffcfe761f3ac9e0d34612e3c23f5a41229206.tar.bz2 |
Password manager internals page service 2: wiring it in
Start using the PasswordManagerInternalsService introduced in https://codereview.chromium.org/262583007/.
This CL breaks the fragile direct link between PasswordManagerClient and the UI contoller of the internals page, inserting the service between.
Design doc: https://docs.google.com/document/d/1ArDhTo0w-8tOPiTwqM1gG6ZGqODo8UTpXlJjjnCNK4s/edit?usp=sharing#heading=h.cqh4wuj8j4yl
BUG=347927
Review URL: https://codereview.chromium.org/269513003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270372 0039d316-1c4b-4281-b951-d872f2087c98
10 files changed, 208 insertions, 167 deletions
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index ecb7aa3..cddf254 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc @@ -21,8 +21,10 @@ #include "components/autofill/content/common/autofill_messages.h" #include "components/autofill/core/browser/password_generator.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/content/browser/password_manager_internals_service_factory.h" #include "components/password_manager/core/browser/password_form_manager.h" #include "components/password_manager/core/browser/password_manager.h" +#include "components/password_manager/core/browser/password_manager_internals_service.h" #include "components/password_manager/core/browser/password_manager_logger.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/common/password_manager_switches.h" @@ -33,6 +35,9 @@ #include "chrome/browser/android/password_authentication_manager.h" #endif // OS_ANDROID +using password_manager::PasswordManagerInternalsService; +using password_manager::PasswordManagerInternalsServiceFactory; + namespace { bool IsTheHotNewBubbleUIEnabled() { @@ -71,12 +76,23 @@ ChromePasswordManagerClient::ChromePasswordManagerClient( content::WebContents* web_contents, autofill::AutofillManagerDelegate* autofill_manager_delegate) : content::WebContentsObserver(web_contents), + profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), driver_(web_contents, this, autofill_manager_delegate), observer_(NULL), weak_factory_(this), - logger_(NULL) {} + can_use_log_router_(false) { + PasswordManagerInternalsService* service = + PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); + if (service) + can_use_log_router_ = service->RegisterClient(this); +} -ChromePasswordManagerClient::~ChromePasswordManagerClient() {} +ChromePasswordManagerClient::~ChromePasswordManagerClient() { + PasswordManagerInternalsService* service = + PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); + if (service) + service->UnregisterClient(this); +} bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const { return CommandLine::ForCurrentProcess()->HasSwitch( @@ -136,17 +152,13 @@ void ChromePasswordManagerClient::AuthenticateAutofillAndFillForm( #endif // OS_ANDROID } -Profile* ChromePasswordManagerClient::GetProfile() { - return Profile::FromBrowserContext(web_contents()->GetBrowserContext()); -} - void ChromePasswordManagerClient::HidePasswordGenerationPopup() { if (popup_controller_) popup_controller_->HideAndDestroy(); } PrefService* ChromePasswordManagerClient::GetPrefs() { - return GetProfile()->GetPrefs(); + return profile_->GetPrefs(); } password_manager::PasswordStore* @@ -154,8 +166,8 @@ ChromePasswordManagerClient::GetPasswordStore() { // Always use EXPLICIT_ACCESS as the password manager checks IsOffTheRecord // itself when it shouldn't access the PasswordStore. // TODO(gcasto): Is is safe to change this to Profile::IMPLICIT_ACCESS? - return PasswordStoreFactory::GetForProfile(GetProfile(), - Profile::EXPLICIT_ACCESS).get(); + return PasswordStoreFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS) + .get(); } password_manager::PasswordManagerDriver* @@ -183,7 +195,7 @@ ChromePasswordManagerClient::GetProbabilityForExperiment( bool ChromePasswordManagerClient::IsPasswordSyncEnabled() { ProfileSyncService* sync_service = - ProfileSyncServiceFactory::GetForProfile(GetProfile()); + ProfileSyncServiceFactory::GetForProfile(profile_); // Don't consider sync enabled if the user has a custom passphrase. See // crbug.com/358998 for more details. if (sync_service && @@ -195,29 +207,35 @@ bool ChromePasswordManagerClient::IsPasswordSyncEnabled() { return false; } -void ChromePasswordManagerClient::SetLogger( - password_manager::PasswordManagerLogger* logger) { - // We should never be replacing one logger with a different one, because that - // will leave the first without further updates, and the user likely confused. - // TODO(vabr): For the reason above, before moving the internals page from - // behind the flag, make sure to restrict the number of internals page - // instances to 1 in normal profiles, and 0 in incognito. - DCHECK(!logger || !logger_); - logger_ = logger; +void ChromePasswordManagerClient::OnLogRouterAvailabilityChanged( + bool router_can_be_used) { + if (can_use_log_router_ == router_can_be_used) + return; + can_use_log_router_ = router_can_be_used; + + if (!web_contents()) + return; // Also inform the renderer process to start or stop logging. web_contents()->GetRenderViewHost()->Send(new AutofillMsg_ChangeLoggingState( - web_contents()->GetRenderViewHost()->GetRoutingID(), logger != NULL)); + web_contents()->GetRenderViewHost()->GetRoutingID(), + can_use_log_router_)); } void ChromePasswordManagerClient::LogSavePasswordProgress( const std::string& text) { - if (IsLoggingActive()) - logger_->LogSavePasswordProgress(text); + if (!IsLoggingActive()) + return; + PasswordManagerInternalsService* service = + PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); + if (service) + service->ProcessLog(text); } bool ChromePasswordManagerClient::IsLoggingActive() const { - return logger_ != NULL; + // WebUI tabs do not need to log password saving progress. In particular, the + // internals page itself should not send any logs. + return can_use_log_router_ && !web_contents()->GetWebUI(); } // static diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h index f57fc3b..4fad507 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.h +++ b/chrome/browser/password_manager/chrome_password_manager_client.h @@ -53,8 +53,7 @@ class ChromePasswordManagerClient virtual base::FieldTrial::Probability GetProbabilityForExperiment( const std::string& experiment_name) OVERRIDE; virtual bool IsPasswordSyncEnabled() OVERRIDE; - virtual void SetLogger(password_manager::PasswordManagerLogger* logger) - OVERRIDE; + virtual void OnLogRouterAvailabilityChanged(bool router_can_be_used) OVERRIDE; virtual void LogSavePasswordProgress(const std::string& text) OVERRIDE; virtual bool IsLoggingActive() const OVERRIDE; @@ -107,7 +106,7 @@ class ChromePasswordManagerClient void ShowPasswordEditingPopup( const gfx::RectF& bounds, const autofill::PasswordForm& form); - Profile* GetProfile(); + Profile* const profile_; password_manager::ContentPasswordManagerDriver driver_; @@ -121,10 +120,8 @@ class ChromePasswordManagerClient // Allows authentication callbacks to be destroyed when this client is gone. base::WeakPtrFactory<ChromePasswordManagerClient> weak_factory_; - // Points to an active logger instance to use for, e.g., reporting progress on - // saving passwords. If there is no active logger (most of the time), the - // pointer will be NULL. - password_manager::PasswordManagerLogger* logger_; + // True if |this| is registered with some LogRouter which can accept logs. + bool can_use_log_router_; DISALLOW_COPY_AND_ASSIGN(ChromePasswordManagerClient); }; diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc index 304975d..e96af45 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc @@ -8,7 +8,10 @@ #include "chrome/common/chrome_version_info.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" #include "components/autofill/content/common/autofill_messages.h" +#include "components/password_manager/content/browser/password_manager_internals_service_factory.h" +#include "components/password_manager/core/browser/password_manager_internals_service.h" #include "components/password_manager/core/browser/password_manager_logger.h" #include "components/password_manager/core/common/password_manager_switches.h" #include "content/public/browser/browser_context.h" @@ -24,11 +27,8 @@ namespace { const char kTestText[] = "abcd1234"; -class MockPasswordManagerLogger - : public password_manager::PasswordManagerLogger { +class MockLogReceiver : public password_manager::PasswordManagerLogger { public: - MockPasswordManagerLogger() {} - MOCK_METHOD1(LogSavePasswordProgress, void(const std::string&)); }; @@ -36,6 +36,8 @@ class MockPasswordManagerLogger class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness { public: + ChromePasswordManagerClientTest(); + virtual void SetUp() OVERRIDE; protected: @@ -46,13 +48,22 @@ class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness { // returns false. bool WasLoggingActivationMessageSent(bool* activation_flag); - testing::StrictMock<MockPasswordManagerLogger> logger_; + password_manager::PasswordManagerInternalsService* service_; + + testing::StrictMock<MockLogReceiver> receiver_; }; +ChromePasswordManagerClientTest::ChromePasswordManagerClientTest() + : service_(NULL) { +} + void ChromePasswordManagerClientTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); ChromePasswordManagerClient::CreateForWebContentsWithAutofillManagerDelegate( web_contents(), NULL); + service_ = password_manager::PasswordManagerInternalsServiceFactory:: + GetForBrowserContext(profile()); + ASSERT_TRUE(service_); } ChromePasswordManagerClient* ChromePasswordManagerClientTest::GetClient() { @@ -73,34 +84,39 @@ bool ChromePasswordManagerClientTest::WasLoggingActivationMessageSent( return true; } -TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNoLogger) { +TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNoReceiver) { ChromePasswordManagerClient* client = GetClient(); - EXPECT_CALL(logger_, LogSavePasswordProgress(kTestText)).Times(0); - // Before attaching the logger, no text should be passed. + EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0); + // Before attaching the receiver, no text should be passed. client->LogSavePasswordProgress(kTestText); EXPECT_FALSE(client->IsLoggingActive()); } -TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressAttachLogger) { +TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressAttachReceiver) { ChromePasswordManagerClient* client = GetClient(); + EXPECT_FALSE(client->IsLoggingActive()); // After attaching the logger, text should be passed. - client->SetLogger(&logger_); - EXPECT_CALL(logger_, LogSavePasswordProgress(kTestText)).Times(1); - client->LogSavePasswordProgress(kTestText); + service_->RegisterReceiver(&receiver_); EXPECT_TRUE(client->IsLoggingActive()); + EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1); + client->LogSavePasswordProgress(kTestText); + service_->UnregisterReceiver(&receiver_); + EXPECT_FALSE(client->IsLoggingActive()); } -TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressDetachLogger) { +TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressDetachReceiver) { ChromePasswordManagerClient* client = GetClient(); - client->SetLogger(&logger_); + service_->RegisterReceiver(&receiver_); + EXPECT_TRUE(client->IsLoggingActive()); + service_->UnregisterReceiver(&receiver_); + EXPECT_FALSE(client->IsLoggingActive()); + // After detaching the logger, no text should be passed. - client->SetLogger(NULL); - EXPECT_CALL(logger_, LogSavePasswordProgress(kTestText)).Times(0); + EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0); client->LogSavePasswordProgress(kTestText); - EXPECT_FALSE(client->IsLoggingActive()); } TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNotifyRenderer) { @@ -110,11 +126,13 @@ TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNotifyRenderer) { // Initially, the logging should be off, so no IPC messages. EXPECT_FALSE(WasLoggingActivationMessageSent(&logging_active)); - client->SetLogger(&logger_); + service_->RegisterReceiver(&receiver_); + EXPECT_TRUE(client->IsLoggingActive()); EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); EXPECT_TRUE(logging_active); - client->SetLogger(NULL); + service_->UnregisterReceiver(&receiver_); + EXPECT_FALSE(client->IsLoggingActive()); EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); EXPECT_FALSE(logging_active); } @@ -133,3 +151,15 @@ TEST_F(ChromePasswordManagerClientTest, else EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled()); } + +TEST_F(ChromePasswordManagerClientTest, LogToAReceiver) { + ChromePasswordManagerClient* client = GetClient(); + service_->RegisterReceiver(&receiver_); + EXPECT_TRUE(client->IsLoggingActive()); + + EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1); + client->LogSavePasswordProgress(kTestText); + + service_->UnregisterReceiver(&receiver_); + EXPECT_FALSE(client->IsLoggingActive()); +} diff --git a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc index 34d4611..9096347 100644 --- a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc +++ b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.cc @@ -7,26 +7,18 @@ #include <algorithm> #include <set> -#include "base/strings/string16.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" #include "base/values.h" -#include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/android/tab_model/tab_model.h" -#include "chrome/browser/ui/android/tab_model/tab_model_list.h" -#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" #include "chrome/common/url_constants.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" +#include "components/password_manager/content/browser/password_manager_internals_service_factory.h" +#include "components/password_manager/core/browser/password_manager_internals_service.h" #include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" #include "grit/password_manager_internals_resources.h" #include "net/base/escape.h" -using content::BrowserContext; -using content::WebContents; +using password_manager::PasswordManagerInternalsService; +using password_manager::PasswordManagerInternalsServiceFactory; namespace { @@ -42,92 +34,46 @@ content::WebUIDataSource* CreatePasswordManagerInternalsHTMLSource() { return source; } -void InsertWebContentsIfProfileMatches( - WebContents* web_contents, - const Profile* profile_to_match, - std::set<WebContents*>* set_of_web_contents) { - if (static_cast<const BrowserContext*>(profile_to_match) == - web_contents->GetBrowserContext()) { - set_of_web_contents->insert(web_contents); - } -} - } // namespace PasswordManagerInternalsUI::PasswordManagerInternalsUI(content::WebUI* web_ui) : WebUIController(web_ui), WebContentsObserver(web_ui->GetWebContents()), - did_stop_loading_(false) { + registered_with_logging_service_(false) { // Set up the chrome://password-manager-internals/ source. content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), CreatePasswordManagerInternalsHTMLSource()); - NotifyAllPasswordManagerClients(PAGE_OPENED); } PasswordManagerInternalsUI::~PasswordManagerInternalsUI() { - NotifyAllPasswordManagerClients(PAGE_CLOSED); + if (!registered_with_logging_service_) + return; + PasswordManagerInternalsService* service = + PasswordManagerInternalsServiceFactory::GetForBrowserContext( + Profile::FromWebUI(web_ui())); + if (service) + service->UnregisterReceiver(this); } void PasswordManagerInternalsUI::DidStopLoading( content::RenderViewHost* /* render_view_host */) { - did_stop_loading_ = true; - if (log_buffer_.empty()) - return; - LogInternal(log_buffer_); - log_buffer_.clear(); + PasswordManagerInternalsService* service = + PasswordManagerInternalsServiceFactory::GetForBrowserContext( + Profile::FromWebUI(web_ui())); + if (service) { + registered_with_logging_service_ = true; + std::string past_logs(service->RegisterReceiver(this)); + LogSavePasswordProgress(past_logs); + } } void PasswordManagerInternalsUI::LogSavePasswordProgress( const std::string& text) { - if (did_stop_loading_) - LogInternal(text); - else - log_buffer_.append(text); -} - -void PasswordManagerInternalsUI::LogInternal(const std::string& text) { + if (!registered_with_logging_service_) + return; std::string no_quotes(text); std::replace(no_quotes.begin(), no_quotes.end(), '"', ' '); base::StringValue text_string_value(net::EscapeForHTML(no_quotes)); web_ui()->CallJavascriptFunction("addSavePasswordProgressLog", text_string_value); } - -void PasswordManagerInternalsUI::NotifyAllPasswordManagerClients( - ClientNotificationType notification_type) { - // First, find all the WebContents objects of the current profile. - Profile* current_profile = Profile::FromWebUI(web_ui()); - std::set<WebContents*> profile_web_contents; -#if defined(OS_ANDROID) - for (TabModelList::const_iterator iter = TabModelList::begin(); - iter != TabModelList::end(); - ++iter) { - TabModel* model = *iter; - for (int i = 0; i < model->GetTabCount(); ++i) { - InsertWebContentsIfProfileMatches( - model->GetWebContentsAt(i), current_profile, &profile_web_contents); - } - } -#else - for (TabContentsIterator iter; !iter.done(); iter.Next()) { - InsertWebContentsIfProfileMatches( - *iter, current_profile, &profile_web_contents); - } -#endif - - // Now get the corresponding PasswordManagerClients, and attach/detach |this|. - for (std::set<WebContents*>::iterator it = profile_web_contents.begin(); - it != profile_web_contents.end(); - ++it) { - ChromePasswordManagerClient* client = - ChromePasswordManagerClient::FromWebContents(*it); - switch (notification_type) { - case PAGE_OPENED: - client->SetLogger(this); - break; - case PAGE_CLOSED: - client->SetLogger(NULL); - break; - } - } -} diff --git a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h index c73486a..3265301 100644 --- a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h +++ b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h @@ -25,30 +25,9 @@ class PasswordManagerInternalsUI virtual void LogSavePasswordProgress(const std::string& text) OVERRIDE; private: - // These types describe which kinds of notifications - // PasswordManagerInternalsUI can send to PasswordManagerClient. - enum ClientNotificationType { - PAGE_OPENED, // Send when the page gets opened. - PAGE_CLOSED // Send when the page gets closed. - }; - - // This acts on all PasswordManagerClient instances of the current profile - // based on |notification_type|: - // PAGE_OPENED -- |this| is set as clients' PasswordManagerLogger - // PAGE_CLOSED -- PasswordManagerLogger is reset for clients - void NotifyAllPasswordManagerClients( - ClientNotificationType notification_type); - - // Helper used by LogSavePasswordProgress, actually sends |text| to the - // internals page. - void LogInternal(const std::string& text); - - // Whether the observed WebContents did stop loading. - bool did_stop_loading_; - - // Stores the logs here until |did_stop_loading_| becomes true. At that point - // all stored logs are displayed and any new are displayed directly. - std::string log_buffer_; + // Whether |this| registered as a log receiver with the + // PasswordManagerInternalsService. + bool registered_with_logging_service_; DISALLOW_COPY_AND_ASSIGN(PasswordManagerInternalsUI); }; diff --git a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc index 817866b..16697a2 100644 --- a/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc +++ b/chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc @@ -3,12 +3,15 @@ // found in the LICENSE file. #include "base/command_line.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/web_ui_browsertest.h" +#include "components/password_manager/content/browser/password_manager_internals_service_factory.h" +#include "components/password_manager/core/browser/password_manager_internals_service.h" #include "components/password_manager/core/common/password_manager_switches.h" #include "content/public/browser/web_contents.h" @@ -27,10 +30,6 @@ class PasswordManagerInternalsWebUIBrowserTest : public WebUIBrowserTest { // the corresponding UI controller to |controller_|. void OpenNewTabWithTheInternalsPage(); - PasswordManagerInternalsUI* controller() { - return controller_; - }; - private: PasswordManagerInternalsUI* controller_; }; @@ -75,7 +74,11 @@ PasswordManagerInternalsWebUIBrowserTest::OpenNewTabWithTheInternalsPage() { IN_PROC_BROWSER_TEST_F(PasswordManagerInternalsWebUIBrowserTest, LogSavePasswordProgress) { - controller()->LogSavePasswordProgress("<script> text for testing"); + password_manager::PasswordManagerInternalsService* service = + password_manager::PasswordManagerInternalsServiceFactory:: + GetForBrowserContext(browser()->profile()); + ASSERT_TRUE(service); + service->ProcessLog("<script> text for testing"); ASSERT_TRUE(RunJavascriptTest("testLogText")); } @@ -84,12 +87,14 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerInternalsWebUIBrowserTest, // logs created before the second tab was opened, and also that the second tab // waits with displaying until the internals page is ready (trying to display // the old logs just on construction time would fail). -// TODO(vabr): Disabled until multiple tabs with the internals page can exist -// without crashing. IN_PROC_BROWSER_TEST_F(PasswordManagerInternalsWebUIBrowserTest, - DISABLED_LogSavePasswordProgress_MultipleTabsIdentical) { + LogSavePasswordProgress_MultipleTabsIdentical) { // First, open one tab with the internals page, and log something. - controller()->LogSavePasswordProgress("<script> text for testing"); + password_manager::PasswordManagerInternalsService* service = + password_manager::PasswordManagerInternalsServiceFactory:: + GetForBrowserContext(browser()->profile()); + ASSERT_TRUE(service); + service->ProcessLog("<script> text for testing"); ASSERT_TRUE(RunJavascriptTest("testLogText")); // Now open a second tab with the internals page, but do not log anything. OpenNewTabWithTheInternalsPage(); diff --git a/components/password_manager/core/browser/log_router.cc b/components/password_manager/core/browser/log_router.cc index c8719a8..7aee715 100644 --- a/components/password_manager/core/browser/log_router.cc +++ b/components/password_manager/core/browser/log_router.cc @@ -40,8 +40,10 @@ std::string LogRouter::RegisterReceiver(PasswordManagerLogger* receiver) { DCHECK(receiver); DCHECK(accumulated_logs_.empty() || receivers_.might_have_observers()); - // TODO(vabr): Once the clients provide API for that, notify them if the - // number of receivers went from 0 to 1. + if (!receivers_.might_have_observers()) { + FOR_EACH_OBSERVER( + PasswordManagerClient, clients_, OnLogRouterAvailabilityChanged(true)); + } receivers_.AddObserver(receiver); return accumulated_logs_; } @@ -51,8 +53,8 @@ void LogRouter::UnregisterReceiver(PasswordManagerLogger* receiver) { receivers_.RemoveObserver(receiver); if (!receivers_.might_have_observers()) { accumulated_logs_.clear(); - // TODO(vabr): Once the clients provide API for that, notify them that the - // number of receivers went from 1 to 0. + FOR_EACH_OBSERVER( + PasswordManagerClient, clients_, OnLogRouterAvailabilityChanged(false)); } } diff --git a/components/password_manager/core/browser/log_router_unittest.cc b/components/password_manager/core/browser/log_router_unittest.cc index b890998..6c02dae 100644 --- a/components/password_manager/core/browser/log_router_unittest.cc +++ b/components/password_manager/core/browser/log_router_unittest.cc @@ -24,12 +24,18 @@ class MockLogReceiver : public PasswordManagerLogger { MOCK_METHOD1(LogSavePasswordProgress, void(const std::string&)); }; +class MockClient : public StubPasswordManagerClient { + public: + MOCK_METHOD1(OnLogRouterAvailabilityChanged, void(bool)); +}; + } // namespace class LogRouterTest : public testing::Test { protected: testing::StrictMock<MockLogReceiver> receiver_; testing::StrictMock<MockLogReceiver> receiver2_; + testing::StrictMock<MockClient> client_; }; TEST_F(LogRouterTest, ProcessLog_NoReceiver) { @@ -93,4 +99,59 @@ TEST_F(LogRouterTest, ProcessLog_TwoReceiversNoUpdateAfterUnregistering) { router.UnregisterReceiver(&receiver2_); } +TEST_F(LogRouterTest, RegisterClient_NoReceivers) { + LogRouter router; + EXPECT_FALSE(router.RegisterClient(&client_)); + router.UnregisterClient(&client_); +} + +TEST_F(LogRouterTest, RegisterClient_OneReceiverBeforeClient) { + LogRouter router; + // First register a receiver. + EXPECT_EQ(std::string(), router.RegisterReceiver(&receiver_)); + // The client should be told the LogRouter has some receivers. + EXPECT_TRUE(router.RegisterClient(&client_)); + // Now unregister the reciever. The client should be told the LogRouter has no + // receivers. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(false)).Times(1); + router.UnregisterReceiver(&receiver_); + router.UnregisterClient(&client_); +} + +TEST_F(LogRouterTest, RegisterClient_OneClientBeforeReceiver) { + LogRouter router; + // First register a client; the client should be told the LogRouter has no + // receivers. + EXPECT_FALSE(router.RegisterClient(&client_)); + // Now register the receiver. The client should be notified. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(true)).Times(1); + EXPECT_EQ(std::string(), router.RegisterReceiver(&receiver_)); + // Now unregister the client. + router.UnregisterClient(&client_); + // Now unregister the reciever. The client should not hear about it. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(_)).Times(0); + router.UnregisterReceiver(&receiver_); +} + +TEST_F(LogRouterTest, RegisterClient_OneClientTwoReceivers) { + LogRouter router; + // First register a client; the client should be told the LogRouter has no + // receivers. + EXPECT_FALSE(router.RegisterClient(&client_)); + // Now register the 1st receiver. The client should be notified. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(true)).Times(1); + EXPECT_EQ(std::string(), router.RegisterReceiver(&receiver_)); + // Now register the 2nd receiver. The client should not be notified. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(true)).Times(0); + EXPECT_EQ(std::string(), router.RegisterReceiver(&receiver2_)); + // Now unregister the 1st reciever. The client should not hear about it. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(false)).Times(0); + router.UnregisterReceiver(&receiver_); + // Now unregister the 2nd reciever. The client should hear about it. + EXPECT_CALL(client_, OnLogRouterAvailabilityChanged(false)).Times(1); + router.UnregisterReceiver(&receiver2_); + // Now unregister the client. + router.UnregisterClient(&client_); +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc index 1ff2f50..ddadd2d 100644 --- a/components/password_manager/core/browser/password_manager_client.cc +++ b/components/password_manager/core/browser/password_manager_client.cc @@ -18,7 +18,8 @@ PasswordManagerClient::GetProbabilityForExperiment( bool PasswordManagerClient::IsPasswordSyncEnabled() { return false; } -void PasswordManagerClient::SetLogger(PasswordManagerLogger* logger) { +void PasswordManagerClient::OnLogRouterAvailabilityChanged( + bool router_can_be_used) { } void PasswordManagerClient::LogSavePasswordProgress(const std::string& text) { diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h index 3793865..e1c765e 100644 --- a/components/password_manager/core/browser/password_manager_client.h +++ b/components/password_manager/core/browser/password_manager_client.h @@ -16,7 +16,6 @@ namespace password_manager { class PasswordFormManager; class PasswordManagerDriver; class PasswordStore; -class PasswordManagerLogger; // An abstraction of operations that depend on the embedders (e.g. Chrome) // environment. @@ -73,10 +72,13 @@ class PasswordManagerClient { // implementation returns false. virtual bool IsPasswordSyncEnabled(); - // Attach or detach (setting NULL) a logger for this client. - virtual void SetLogger(PasswordManagerLogger* logger); + // Only for clients which registered with a LogRouter: If called with + // |router_can_be_used| set to false, the client may no longer use the + // LogRouter. If |router_can_be_used| is true, the LogRouter can be used after + // the return from OnLogRouterAvailabilityChanged. + virtual void OnLogRouterAvailabilityChanged(bool router_can_be_used); - // Send |text| to the logger. + // Forward |text| for display to the LogRouter (if registered with one). virtual void LogSavePasswordProgress(const std::string& text); // Returns true if logs recorded via LogSavePasswordProgress will be |