Chromium Code Reviews| Index: chrome/browser/chromeos/power/extension_event_observer_unittest.cc |
| diff --git a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..77c583c43855a7ed55f74172424b0818acf5c615 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc |
| @@ -0,0 +1,308 @@ |
| +// Copyright 2015 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. |
| + |
| +#include "chrome/browser/chromeos/power/extension_event_observer.h" |
| + |
| +#include <string> |
| + |
| +#include "base/macros.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "base/run_loop.h" |
| +#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" |
| +#include "chrome/browser/chromeos/settings/cros_settings.h" |
| +#include "chrome/browser/chromeos/settings/device_settings_service.h" |
| +#include "chrome/common/extensions/api/gcm.h" |
| +#include "chrome/test/base/testing_browser_process.h" |
| +#include "chrome/test/base/testing_profile.h" |
| +#include "chrome/test/base/testing_profile_manager.h" |
| +#include "chromeos/dbus/dbus_thread_manager.h" |
| +#include "chromeos/dbus/fake_power_manager_client.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "content/public/test/test_renderer_host.h" |
| +#include "extensions/browser/extension_host.h" |
| +#include "extensions/browser/process_manager.h" |
| +#include "extensions/common/extension.h" |
| +#include "extensions/common/extension_builder.h" |
| +#include "extensions/common/manifest_handlers/background_info.h" |
| +#include "extensions/common/value_builder.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace chromeos { |
| + |
| +class ExtensionEventObserverTest : public ::testing::Test { |
| + public: |
| + ExtensionEventObserverTest() |
| + : power_manager_client_(new FakePowerManagerClient()) { |
| + DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient( |
| + make_scoped_ptr(power_manager_client_)); |
| + |
| + profile_manager_.reset( |
| + new TestingProfileManager(TestingBrowserProcess::GetGlobal())); |
| + |
| + extension_event_observer_.reset(new ExtensionEventObserver()); |
| + test_api_ = extension_event_observer_->GetApiForTesting(); |
| + } |
| + |
| + ~ExtensionEventObserverTest() { |
|
Daniel Erat
2015/01/13 23:49:10
override
Chirantan Ekbote
2015/01/15 05:06:36
Done.
|
| + extension_event_observer_.reset(); |
| + profile_manager_.reset(); |
| + DBusThreadManager::Shutdown(); |
| + } |
| + |
| + // ::testing::Test overrides. |
| + void SetUp() override { |
| + ::testing::Test::SetUp(); |
| + |
| + // Must be called from ::testing::Test::SetUp. |
| + ASSERT_TRUE(profile_manager_->SetUp()); |
| + |
| + profile_ = profile_manager_->CreateTestingProfile("Profile 1"); |
| + } |
| + void TearDown() override { |
| + profile_ = NULL; |
| + profile_manager_->DeleteAllTestingProfiles(); |
| + |
| + ::testing::Test::TearDown(); |
| + } |
| + |
| + protected: |
| + scoped_refptr<extensions::Extension> CreateApp(const std::string& name, |
| + bool uses_gcm) { |
| + scoped_refptr<extensions::Extension> app = |
| + extensions::ExtensionBuilder() |
| + .SetManifest( |
| + extensions::DictionaryBuilder() |
| + .Set("name", name) |
| + .Set("version", "1.0.0") |
| + .Set("manifest_version", 2) |
| + .Set("app", |
| + extensions::DictionaryBuilder().Set( |
| + "background", |
| + extensions::DictionaryBuilder().Set( |
| + "scripts", extensions::ListBuilder().Append( |
| + "background.js")))) |
| + .Set("permissions", extensions::ListBuilder().Append( |
| + uses_gcm ? "gcm" : ""))) |
| + .Build(); |
| + |
| + created_apps_.push_back(app); |
| + |
| + return app; |
| + } |
| + |
| + extensions::ExtensionHost* CreateHostForApp(Profile* profile, |
| + extensions::Extension* app) { |
| + extensions::ProcessManager::Get(profile)->CreateBackgroundHost( |
| + app, extensions::BackgroundInfo::GetBackgroundURL(app)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + return extensions::ProcessManager::Get(profile) |
| + ->GetBackgroundHostForExtension(app->id()); |
| + } |
| + |
| + // Owned by DBusThreadManager. |
| + FakePowerManagerClient* power_manager_client_; |
| + |
| + scoped_ptr<ExtensionEventObserver> extension_event_observer_; |
| + scoped_ptr<ExtensionEventObserver::TestApi> test_api_; |
| + |
| + // Owned by |profile_manager_|. |
| + TestingProfile* profile_; |
| + scoped_ptr<TestingProfileManager> profile_manager_; |
| + |
| + private: |
| + content::TestBrowserThreadBundle browser_thread_bundle_; |
| + |
| + // Needed to ensure we don't end up creating actual RenderViewHosts |
| + // and RenderProcessHosts. |
| + content::RenderViewHostTestEnabler render_view_host_test_enabler_; |
| + |
| + // Chrome OS needs extra services to run in the following order. |
| + chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; |
| + chromeos::ScopedTestCrosSettings test_cros_settings_; |
| + chromeos::ScopedTestUserManager test_user_manager_; |
| + |
| + std::vector<scoped_refptr<extensions::Extension>> created_apps_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ExtensionEventObserverTest); |
| +}; |
| + |
| +// Tests that the ExtensionEventObserver reports readiness for suspend when |
| +// there is nothing interesting going on. |
| +TEST_F(ExtensionEventObserverTest, BasicSuspendAndDarkSuspend) { |
| + power_manager_client_->SendSuspendImminent(); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
|
Daniel Erat
2015/01/13 23:49:10
here and elsewhere in the file: should be EXPECT_E
Chirantan Ekbote
2015/01/15 05:06:36
Done.
|
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| + |
| + power_manager_client_->SendDarkSuspendImminent(); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| +} |
| + |
| +// Tests that the ExtensionEventObserver properly handles a canceled suspend |
| +// attempt. |
| +TEST_F(ExtensionEventObserverTest, CanceledSuspend) { |
| + power_manager_client_->SendSuspendImminent(); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + power_manager_client_->SendSuspendDone(); |
| + EXPECT_FALSE(test_api_->MaybeRunSuspendReadinessCallback()); |
| +} |
| + |
| +// Tests that the ExtensionEventObserver delays suspends and dark suspends while |
| +// there is a push message pending for an app that uses GCM. |
| +TEST_F(ExtensionEventObserverTest, PushMessagesDelaySuspend) { |
| + scoped_refptr<extensions::Extension> gcm_app = |
| + CreateApp("DelaysSuspendForPushMessages", true /* uses_gcm */); |
| + extensions::ExtensionHost* host = CreateHostForApp(profile_, gcm_app.get()); |
| + ASSERT_TRUE(host); |
| + EXPECT_TRUE(test_api_->WillDelaySuspendForExtensionHost(host)); |
| + |
| + // Test that a push message received before a suspend attempt delays the |
| + // attempt. |
| + const int kSuspendPushId = 23874; |
| + extension_event_observer_->OnExtensionMessageDispatched( |
| + host, extensions::api::gcm::OnMessage::kEventName, kSuspendPushId); |
| + power_manager_client_->SendSuspendImminent(); |
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + extension_event_observer_->OnExtensionMessageAcked(host, kSuspendPushId); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| + |
| + // Now test receiving the suspend attempt before the push message. |
| + const int kDarkSuspendPushId = 56674; |
| + power_manager_client_->SendDarkSuspendImminent(); |
| + extension_event_observer_->OnExtensionMessageDispatched( |
| + host, extensions::api::gcm::OnMessage::kEventName, kDarkSuspendPushId); |
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + extension_event_observer_->OnExtensionMessageAcked(host, kDarkSuspendPushId); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| + |
| + // Test that non-push messages do not delay the suspend. |
| + const int kNonPushId = 5687; |
| + power_manager_client_->SendDarkSuspendImminent(); |
| + extension_event_observer_->OnExtensionMessageDispatched(host, "FakeMessage", |
| + kNonPushId); |
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| +} |
| + |
| +// Tests that messages sent for apps that don't use GCM are ignored. |
| +TEST_F(ExtensionEventObserverTest, IgnoresNonGCMApps) { |
| + scoped_refptr<extensions::Extension> app = CreateApp("Non-GCM", false); |
| + extensions::ExtensionHost* host = CreateHostForApp(profile_, app.get()); |
| + ASSERT_TRUE(host); |
| + |
| + EXPECT_FALSE(test_api_->WillDelaySuspendForExtensionHost(host)); |
| + |
| + power_manager_client_->SendSuspendImminent(); |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| +} |
| + |
| +// Tests that network requests started by an app while it is processing a push |
| +// message delay any suspend attempt. |
| +TEST_F(ExtensionEventObserverTest, NetworkRequestsMayDelaySuspend) { |
| + scoped_refptr<extensions::Extension> app = CreateApp("NetworkRequests", true); |
| + extensions::ExtensionHost* host = CreateHostForApp(profile_, app.get()); |
| + ASSERT_TRUE(host); |
| + EXPECT_TRUE(test_api_->WillDelaySuspendForExtensionHost(host)); |
| + |
| + // Test that network requests started while there is no pending push message |
| + // are ignored. |
| + const uint64 kNonPushRequestId = 5170725; |
| + extension_event_observer_->OnNetworkRequestStarted(host, kNonPushRequestId); |
| + power_manager_client_->SendSuspendImminent(); |
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| + |
| + // Test that network requests started while a push message is pending delay |
| + // the suspend even after the push message has been acked. |
| + const int kPushMessageId = 178674; |
| + const uint64 kNetworkRequestId = 78917089; |
| + power_manager_client_->SendDarkSuspendImminent(); |
| + extension_event_observer_->OnExtensionMessageDispatched( |
| + host, extensions::api::gcm::OnMessage::kEventName, kPushMessageId); |
| + |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + extension_event_observer_->OnNetworkRequestStarted(host, kNetworkRequestId); |
| + extension_event_observer_->OnExtensionMessageAcked(host, kPushMessageId); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + extension_event_observer_->OnNetworkRequestDone(host, kNetworkRequestId); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| +} |
| + |
| +// Tests that any outstanding push messages or network requests for an |
| +// ExtensionHost that is destroyed do not end up blocking system suspend. |
| +TEST_F(ExtensionEventObserverTest, DeletedExtensionHostDoesNotBlockSuspend) { |
| + scoped_refptr<extensions::Extension> app = |
| + CreateApp("DeletedExtensionHost", true); |
| + |
| + // The easiest way to delete an extension host is to delete the Profile it is |
| + // associated with so we create a new Profile here. |
| + const char kProfileName[] = "DeletedExtensionHostProfile"; |
| + Profile* new_profile = profile_manager_->CreateTestingProfile(kProfileName); |
| + |
| + extensions::ExtensionHost* host = CreateHostForApp(new_profile, app.get()); |
| + ASSERT_TRUE(host); |
| + EXPECT_TRUE(test_api_->WillDelaySuspendForExtensionHost(host)); |
| + |
| + const int kPushId = 156178; |
| + const uint64 kNetworkId = 791605; |
| + extension_event_observer_->OnExtensionMessageDispatched( |
| + host, extensions::api::gcm::OnMessage::kEventName, kPushId); |
| + extension_event_observer_->OnNetworkRequestStarted(host, kNetworkId); |
| + |
| + // Now delete the Profile. This has the side-effect of also deleting all the |
| + // ExtensionHosts. |
| + profile_manager_->DeleteTestingProfile(kProfileName); |
| + |
| + power_manager_client_->SendSuspendImminent(); |
| + EXPECT_TRUE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| +} |
| + |
| +// Tests that the ExtensionEventObserver does not delay suspend attempts when it |
| +// is disabled. |
| +TEST_F(ExtensionEventObserverTest, DoesNotDelaySuspendWhenDisabled) { |
| + scoped_refptr<extensions::Extension> app = |
| + CreateApp("NoDelayWhenDisabled", true); |
| + extensions::ExtensionHost* host = CreateHostForApp(profile_, app.get()); |
| + ASSERT_TRUE(host); |
| + EXPECT_TRUE(test_api_->WillDelaySuspendForExtensionHost(host)); |
| + |
| + // Test that disabling the suspend delay while a suspend is pending will cause |
| + // the ExtensionEventObserver to immediately report readiness. |
| + const int kPushId = 416753; |
| + extension_event_observer_->OnExtensionMessageDispatched( |
| + host, extensions::api::gcm::OnMessage::kEventName, kPushId); |
| + power_manager_client_->SendSuspendImminent(); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 1); |
| + |
| + extension_event_observer_->ShouldDelaySuspend(false); |
| + EXPECT_FALSE(test_api_->MaybeRunSuspendReadinessCallback()); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| + |
| + // Test that the ExtensionEventObserver does not delay suspend attempts when |
| + // it is disabled. |
| + power_manager_client_->SendDarkSuspendImminent(); |
| + EXPECT_EQ(power_manager_client_->GetNumPendingSuspendReadinessCallbacks(), 0); |
| +} |
| + |
| +} // namespace chromeos |