blob: 188e3212f74bda5cfadc9013e93a04cf86e62074 [file] [log] [blame]
[email protected]a61890e2012-07-27 22:27:111// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]398206c2010-06-21 01:46:082// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dcheng4af48582016-04-19 00:29:355#include "chrome/browser/background/background_contents_service.h"
6
7#include <memory>
[email protected]0bc24b52011-01-11 01:19:478#include <string>
[email protected]398206c2010-06-21 01:46:089
[email protected]398206c2010-06-21 01:46:0810#include "base/command_line.h"
avie4d7b6f2015-12-26 00:59:1811#include "base/macros.h"
[email protected]5190a292014-02-26 15:50:3212#include "base/run_loop.h"
avie4d7b6f2015-12-26 00:59:1813#include "build/build_config.h"
avi71d0f762014-12-15 16:08:4714#include "chrome/browser/background/background_contents.h"
[email protected]a42f2e22011-10-10 22:28:1715#include "chrome/browser/background/background_contents_service_factory.h"
[email protected]fdf40f3e2013-07-11 23:55:4616#include "chrome/browser/chrome_notification_types.h"
Evan Stade7af71992018-01-20 02:03:0617#include "chrome/browser/notifications/notification_display_service_tester.h"
[email protected]71b73f02011-04-06 15:57:2918#include "chrome/browser/ui/browser_list.h"
[email protected]84695f22014-02-18 02:29:3219#include "chrome/common/extensions/extension_test_util.h"
[email protected]398206c2010-06-21 01:46:0820#include "chrome/common/pref_names.h"
[email protected]84695f22014-02-18 02:29:3221#include "chrome/test/base/browser_with_test_window_test.h"
[email protected]bf9257742011-08-11 21:01:1522#include "chrome/test/base/testing_browser_process.h"
[email protected]a4ff9eae2011-08-01 19:58:1623#include "chrome/test/base/testing_profile.h"
brettwb1fc1b82016-02-02 00:19:0824#include "components/prefs/pref_service.h"
25#include "components/prefs/scoped_user_pref_update.h"
[email protected]ad50def52011-10-19 23:17:0726#include "content/public/browser/notification_service.h"
[email protected]84695f22014-02-18 02:29:3227#include "content/public/test/test_browser_thread.h"
Gabriel Charetteb69fcd42019-08-23 02:13:2928#include "content/public/test/test_browser_thread_bundle.h"
[email protected]84695f22014-02-18 02:29:3229#include "extensions/common/extension.h"
[email protected]398206c2010-06-21 01:46:0830#include "testing/gtest/include/gtest/gtest.h"
31#include "testing/platform_test.h"
Evan Stade889ce4712018-01-28 15:26:2632#include "ui/message_center/public/cpp/notification.h"
brettw1f92eed2016-12-07 01:12:5833#include "url/gurl.h"
[email protected]84695f22014-02-18 02:29:3234
[email protected]583844c2011-08-27 00:38:3535class BackgroundContentsServiceTest : public testing::Test {
[email protected]33ad6ce92013-08-27 14:39:0836 public:
37 BackgroundContentsServiceTest() {}
dchenge1bc7982014-10-30 00:32:4038 ~BackgroundContentsServiceTest() override {}
39 void SetUp() override {
avi3ef9ec9e2014-12-22 22:50:1740 command_line_.reset(new base::CommandLine(base::CommandLine::NO_PROGRAM));
skyostil0becb332015-04-27 17:59:3741 BackgroundContentsService::DisableCloseBalloonForTesting(true);
42 }
43
44 void TearDown() override {
45 BackgroundContentsService::DisableCloseBalloonForTesting(false);
[email protected]398206c2010-06-21 01:46:0846 }
47
[email protected]5bcdd99d2013-12-23 18:28:3048 const base::DictionaryValue* GetPrefs(Profile* profile) {
[email protected]f33bee52011-03-31 09:18:4349 return profile->GetPrefs()->GetDictionary(
[email protected]398206c2010-06-21 01:46:0850 prefs::kRegisteredBackgroundContents);
51 }
52
53 // Returns the stored pref URL for the passed app id.
Evan Stade092530b2017-11-21 17:17:0554 std::string GetPrefURLForApp(Profile* profile, const std::string& appid) {
[email protected]5bcdd99d2013-12-23 18:28:3055 const base::DictionaryValue* pref = GetPrefs(profile);
Evan Stade092530b2017-11-21 17:17:0556 EXPECT_TRUE(pref->HasKey(appid));
[email protected]5bcdd99d2013-12-23 18:28:3057 const base::DictionaryValue* value;
Evan Stade092530b2017-11-21 17:17:0558 pref->GetDictionaryWithoutPathExpansion(appid, &value);
[email protected]398206c2010-06-21 01:46:0859 std::string url;
[email protected]90018542010-08-14 01:49:1460 value->GetString("url", &url);
[email protected]398206c2010-06-21 01:46:0861 return url;
62 }
63
Gabriel Charette798fde72019-08-20 22:24:0464 content::BrowserTaskEnvironment task_environment_;
dcheng4af48582016-04-19 00:29:3565 std::unique_ptr<base::CommandLine> command_line_;
[email protected]398206c2010-06-21 01:46:0866};
67
68class MockBackgroundContents : public BackgroundContents {
69 public:
Evan Stade6670c332019-06-18 20:56:1270 MockBackgroundContents(BackgroundContentsService* service,
71 Profile* profile,
72 const std::string& id)
73 : service_(service), appid_(id), profile_(profile) {}
74 MockBackgroundContents(BackgroundContentsService* service, Profile* profile)
75 : MockBackgroundContents(service, profile, "app_id") {}
[email protected]398206c2010-06-21 01:46:0876
Evan Stade6670c332019-06-18 20:56:1277 void SendOpenedNotification() {
Nigel Tao28338b82018-11-27 21:40:3778 BackgroundContentsOpenedDetails details = {this, "background", appid_};
Evan Stade6670c332019-06-18 20:56:1279 service_->BackgroundContentsOpened(&details, profile_);
[email protected]398206c2010-06-21 01:46:0880 }
81
Evan Stade6670c332019-06-18 20:56:1282 void Navigate(GURL url) {
[email protected]398206c2010-06-21 01:46:0883 url_ = url;
Evan Stade6670c332019-06-18 20:56:1284 service_->OnBackgroundContentsNavigated(this);
[email protected]398206c2010-06-21 01:46:0885 }
Daniel Chenga542fca2014-10-21 09:51:2986 const GURL& GetURL() const override { return url_; }
[email protected]398206c2010-06-21 01:46:0887
88 void MockClose(Profile* profile) {
Evan Stade6670c332019-06-18 20:56:1289 service_->OnBackgroundContentsClosed(this);
[email protected]398206c2010-06-21 01:46:0890 delete this;
91 }
92
Daniel Chenga542fca2014-10-21 09:51:2993 ~MockBackgroundContents() override {
Evan Stade6670c332019-06-18 20:56:1294 service_->OnBackgroundContentsDeleted(this);
[email protected]398206c2010-06-21 01:46:0895 }
96
Evan Stade092530b2017-11-21 17:17:0597 const std::string& appid() { return appid_; }
[email protected]398206c2010-06-21 01:46:0898
99 private:
100 GURL url_;
101
Evan Stade6670c332019-06-18 20:56:12102 BackgroundContentsService* service_;
103
[email protected]33ad6ce92013-08-27 14:39:08104 // The ID of our parent application
Evan Stade092530b2017-11-21 17:17:05105 std::string appid_;
[email protected]398206c2010-06-21 01:46:08106
[email protected]33ad6ce92013-08-27 14:39:08107 // Parent profile
[email protected]398206c2010-06-21 01:46:08108 Profile* profile_;
Evan Stade6670c332019-06-18 20:56:12109
110 DISALLOW_COPY_AND_ASSIGN(MockBackgroundContents);
[email protected]398206c2010-06-21 01:46:08111};
112
[email protected]84695f22014-02-18 02:29:32113class BackgroundContentsServiceNotificationTest
114 : public BrowserWithTestWindowTest {
115 public:
[email protected]5190a292014-02-26 15:50:32116 BackgroundContentsServiceNotificationTest() {}
dchenge1bc7982014-10-30 00:32:40117 ~BackgroundContentsServiceNotificationTest() override {}
[email protected]84695f22014-02-18 02:29:32118
119 // Overridden from testing::Test
dchenge1bc7982014-10-30 00:32:40120 void SetUp() override {
Evan Stadeef1543f2017-11-17 20:20:13121 BrowserWithTestWindowTest::SetUp();
Evan Stade7af71992018-01-20 02:03:06122 display_service_ =
123 std::make_unique<NotificationDisplayServiceTester>(profile());
[email protected]84695f22014-02-18 02:29:32124 }
125
126 protected:
[email protected]84695f22014-02-18 02:29:32127 // Creates crash notification for the specified extension and returns
128 // the created one.
Evan Stade7af71992018-01-20 02:03:06129 const message_center::Notification CreateCrashNotification(
[email protected]84695f22014-02-18 02:29:32130 scoped_refptr<extensions::Extension> extension) {
juyik048931af2014-10-06 17:56:30131 std::string notification_id = BackgroundContentsService::
132 GetNotificationDelegateIdForExtensionForTesting(extension->id());
Nigel Tao28338b82018-11-27 21:40:37133 BackgroundContentsService::ShowBalloonForTesting(extension.get(),
134 profile());
Evan Stade7af71992018-01-20 02:03:06135 base::RunLoop run_loop;
136 display_service_->SetNotificationAddedClosure(run_loop.QuitClosure());
137 run_loop.Run();
138 display_service_->SetNotificationAddedClosure(base::RepeatingClosure());
139 return *display_service_->GetNotification(notification_id);
[email protected]84695f22014-02-18 02:29:32140 }
141
Evan Stade7af71992018-01-20 02:03:06142 std::unique_ptr<NotificationDisplayServiceTester> display_service_;
143
[email protected]84695f22014-02-18 02:29:32144 private:
[email protected]84695f22014-02-18 02:29:32145 DISALLOW_COPY_AND_ASSIGN(BackgroundContentsServiceNotificationTest);
146};
[email protected]84695f22014-02-18 02:29:32147
[email protected]398206c2010-06-21 01:46:08148TEST_F(BackgroundContentsServiceTest, Create) {
[email protected]33ad6ce92013-08-27 14:39:08149 // Check for creation and leaks.
150 TestingProfile profile;
151 BackgroundContentsService service(&profile, command_line_.get());
[email protected]398206c2010-06-21 01:46:08152}
153
154TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
[email protected]33ad6ce92013-08-27 14:39:08155 TestingProfile profile;
156 BackgroundContentsService service(&profile, command_line_.get());
Evan Stade6670c332019-06-18 20:56:12157 MockBackgroundContents* contents =
158 new MockBackgroundContents(&service, &profile);
[email protected]33ad6ce92013-08-27 14:39:08159 EXPECT_FALSE(service.IsTracked(contents));
Evan Stade6670c332019-06-18 20:56:12160 contents->SendOpenedNotification();
[email protected]33ad6ce92013-08-27 14:39:08161 EXPECT_TRUE(service.IsTracked(contents));
[email protected]398206c2010-06-21 01:46:08162 delete contents;
[email protected]33ad6ce92013-08-27 14:39:08163 EXPECT_FALSE(service.IsTracked(contents));
[email protected]398206c2010-06-21 01:46:08164}
165
166TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) {
[email protected]33ad6ce92013-08-27 14:39:08167 TestingProfile profile;
168 BackgroundContentsService service(&profile, command_line_.get());
Sylvain Defresne94a3752c2019-02-15 18:53:54169
[email protected]398206c2010-06-21 01:46:08170 GURL orig_url;
171 GURL url("http://a/");
172 GURL url2("http://a/");
173 {
dcheng4af48582016-04-19 00:29:35174 std::unique_ptr<MockBackgroundContents> contents(
Evan Stade6670c332019-06-18 20:56:12175 new MockBackgroundContents(&service, &profile));
[email protected]33ad6ce92013-08-27 14:39:08176 EXPECT_EQ(0U, GetPrefs(&profile)->size());
Evan Stade6670c332019-06-18 20:56:12177 contents->SendOpenedNotification();
[email protected]398206c2010-06-21 01:46:08178
179 contents->Navigate(url);
[email protected]33ad6ce92013-08-27 14:39:08180 EXPECT_EQ(1U, GetPrefs(&profile)->size());
181 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
[email protected]398206c2010-06-21 01:46:08182
183 // Navigate the contents to a new url, should not change url.
184 contents->Navigate(url2);
[email protected]33ad6ce92013-08-27 14:39:08185 EXPECT_EQ(1U, GetPrefs(&profile)->size());
186 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
[email protected]398206c2010-06-21 01:46:08187 }
188 // Contents are deleted, url should persist.
[email protected]33ad6ce92013-08-27 14:39:08189 EXPECT_EQ(1U, GetPrefs(&profile)->size());
[email protected]398206c2010-06-21 01:46:08190}
191
192TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAddedAndClosed) {
[email protected]33ad6ce92013-08-27 14:39:08193 TestingProfile profile;
194 BackgroundContentsService service(&profile, command_line_.get());
[email protected]33ad6ce92013-08-27 14:39:08195
[email protected]398206c2010-06-21 01:46:08196 GURL url("http://a/");
Evan Stade6670c332019-06-18 20:56:12197 MockBackgroundContents* contents =
198 new MockBackgroundContents(&service, &profile);
[email protected]33ad6ce92013-08-27 14:39:08199 EXPECT_EQ(0U, GetPrefs(&profile)->size());
Evan Stade6670c332019-06-18 20:56:12200 contents->SendOpenedNotification();
[email protected]398206c2010-06-21 01:46:08201 contents->Navigate(url);
[email protected]33ad6ce92013-08-27 14:39:08202 EXPECT_EQ(1U, GetPrefs(&profile)->size());
203 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
[email protected]398206c2010-06-21 01:46:08204
205 // Fake a window closed by script.
[email protected]33ad6ce92013-08-27 14:39:08206 contents->MockClose(&profile);
207 EXPECT_EQ(0U, GetPrefs(&profile)->size());
[email protected]398206c2010-06-21 01:46:08208}
209
210// Test what happens if a BackgroundContents shuts down (say, due to a renderer
211// crash) then is restarted. Should not persist URL twice.
212TEST_F(BackgroundContentsServiceTest, RestartBackgroundContents) {
[email protected]33ad6ce92013-08-27 14:39:08213 TestingProfile profile;
214 BackgroundContentsService service(&profile, command_line_.get());
[email protected]33ad6ce92013-08-27 14:39:08215
[email protected]398206c2010-06-21 01:46:08216 GURL url("http://a/");
217 {
dcheng4af48582016-04-19 00:29:35218 std::unique_ptr<MockBackgroundContents> contents(
Evan Stade6670c332019-06-18 20:56:12219 new MockBackgroundContents(&service, &profile, "appid"));
220 contents->SendOpenedNotification();
[email protected]398206c2010-06-21 01:46:08221 contents->Navigate(url);
[email protected]33ad6ce92013-08-27 14:39:08222 EXPECT_EQ(1U, GetPrefs(&profile)->size());
223 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
[email protected]398206c2010-06-21 01:46:08224 }
225 // Contents deleted, url should be persisted.
[email protected]33ad6ce92013-08-27 14:39:08226 EXPECT_EQ(1U, GetPrefs(&profile)->size());
[email protected]398206c2010-06-21 01:46:08227
228 {
229 // Reopen the BackgroundContents to the same URL, we should not register the
230 // URL again.
dcheng4af48582016-04-19 00:29:35231 std::unique_ptr<MockBackgroundContents> contents(
Evan Stade6670c332019-06-18 20:56:12232 new MockBackgroundContents(&service, &profile, "appid"));
233 contents->SendOpenedNotification();
[email protected]398206c2010-06-21 01:46:08234 contents->Navigate(url);
[email protected]33ad6ce92013-08-27 14:39:08235 EXPECT_EQ(1U, GetPrefs(&profile)->size());
[email protected]398206c2010-06-21 01:46:08236 }
237}
238
239// Ensures that BackgroundContentsService properly tracks the association
240// between a BackgroundContents and its parent extension, including
241// unregistering the BC when the extension is uninstalled.
242TEST_F(BackgroundContentsServiceTest, TestApplicationIDLinkage) {
[email protected]33ad6ce92013-08-27 14:39:08243 TestingProfile profile;
244 BackgroundContentsService service(&profile, command_line_.get());
[email protected]33ad6ce92013-08-27 14:39:08245
Evan Stade092530b2017-11-21 17:17:05246 EXPECT_EQ(NULL, service.GetAppBackgroundContents("appid"));
Nigel Tao28338b82018-11-27 21:40:37247 MockBackgroundContents* contents =
Evan Stade6670c332019-06-18 20:56:12248 new MockBackgroundContents(&service, &profile, "appid");
dcheng4af48582016-04-19 00:29:35249 std::unique_ptr<MockBackgroundContents> contents2(
Evan Stade6670c332019-06-18 20:56:12250 new MockBackgroundContents(&service, &profile, "appid2"));
251 contents->SendOpenedNotification();
[email protected]33ad6ce92013-08-27 14:39:08252 EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid()));
Evan Stade6670c332019-06-18 20:56:12253 contents2->SendOpenedNotification();
Nigel Tao28338b82018-11-27 21:40:37254 EXPECT_EQ(contents2.get(),
255 service.GetAppBackgroundContents(contents2->appid()));
[email protected]33ad6ce92013-08-27 14:39:08256 EXPECT_EQ(0U, GetPrefs(&profile)->size());
[email protected]398206c2010-06-21 01:46:08257
258 // Navigate the contents, then make sure the one associated with the extension
259 // is unregistered.
260 GURL url("http://a/");
261 GURL url2("http://b/");
262 contents->Navigate(url);
[email protected]33ad6ce92013-08-27 14:39:08263 EXPECT_EQ(1U, GetPrefs(&profile)->size());
[email protected]398206c2010-06-21 01:46:08264 contents2->Navigate(url2);
[email protected]33ad6ce92013-08-27 14:39:08265 EXPECT_EQ(2U, GetPrefs(&profile)->size());
Evan Stade092530b2017-11-21 17:17:05266 service.ShutdownAssociatedBackgroundContents("appid");
[email protected]33ad6ce92013-08-27 14:39:08267 EXPECT_FALSE(service.IsTracked(contents));
Evan Stade092530b2017-11-21 17:17:05268 EXPECT_EQ(NULL, service.GetAppBackgroundContents("appid"));
[email protected]33ad6ce92013-08-27 14:39:08269 EXPECT_EQ(1U, GetPrefs(&profile)->size());
270 EXPECT_EQ(url2.spec(), GetPrefURLForApp(&profile, contents2->appid()));
[email protected]398206c2010-06-21 01:46:08271}
[email protected]84695f22014-02-18 02:29:32272
[email protected]44aae2f72014-02-28 14:40:09273TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloon) {
[email protected]84695f22014-02-18 02:29:32274 scoped_refptr<extensions::Extension> extension =
275 extension_test_util::LoadManifest("image_loading_tracker", "app.json");
276 ASSERT_TRUE(extension.get());
277 ASSERT_TRUE(extension->GetManifestData("icons"));
278
Evan Stade7af71992018-01-20 02:03:06279 const message_center::Notification notification =
Evan Stade4755cf22017-10-17 18:35:43280 CreateCrashNotification(extension);
Evan Stade7af71992018-01-20 02:03:06281 EXPECT_FALSE(notification.icon().IsEmpty());
[email protected]84695f22014-02-18 02:29:32282}
283
dgn49f1ca92016-05-26 20:02:36284TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloonShutdown) {
285 scoped_refptr<extensions::Extension> extension =
286 extension_test_util::LoadManifest("image_loading_tracker", "app.json");
287 ASSERT_TRUE(extension.get());
288 ASSERT_TRUE(extension->GetManifestData("icons"));
289
290 std::string notification_id = BackgroundContentsService::
291 GetNotificationDelegateIdForExtensionForTesting(extension->id());
292
293 static_cast<TestingBrowserProcess*>(g_browser_process)->SetShuttingDown(true);
294 BackgroundContentsService::ShowBalloonForTesting(extension.get(), profile());
295 base::RunLoop().RunUntilIdle();
296 static_cast<TestingBrowserProcess*>(g_browser_process)
297 ->SetShuttingDown(false);
298
Evan Stade7af71992018-01-20 02:03:06299 EXPECT_FALSE(display_service_->GetNotification(notification_id));
dgn49f1ca92016-05-26 20:02:36300}
301
[email protected]84695f22014-02-18 02:29:32302// Verify if a test notification can show the default extension icon for
303// a crash notification for an extension without icon.
[email protected]44aae2f72014-02-28 14:40:09304TEST_F(BackgroundContentsServiceNotificationTest, TestShowBalloonNoIcon) {
[email protected]84695f22014-02-18 02:29:32305 // Extension manifest file with no 'icon' field.
306 scoped_refptr<extensions::Extension> extension =
307 extension_test_util::LoadManifest("app", "manifest.json");
308 ASSERT_TRUE(extension.get());
309 ASSERT_FALSE(extension->GetManifestData("icons"));
310
Evan Stade7af71992018-01-20 02:03:06311 const message_center::Notification notification =
Evan Stade4755cf22017-10-17 18:35:43312 CreateCrashNotification(extension);
Evan Stade7af71992018-01-20 02:03:06313 EXPECT_FALSE(notification.icon().IsEmpty());
[email protected]84695f22014-02-18 02:29:32314}
[email protected]05d6118652014-05-21 23:14:05315
316TEST_F(BackgroundContentsServiceNotificationTest, TestShowTwoBalloons) {
317 TestingProfile profile;
318 scoped_refptr<extensions::Extension> extension =
319 extension_test_util::LoadManifest("app", "manifest.json");
320 ASSERT_TRUE(extension.get());
321 CreateCrashNotification(extension);
322 CreateCrashNotification(extension);
323
Evan Stade7af71992018-01-20 02:03:06324 ASSERT_EQ(1u, display_service_
325 ->GetDisplayedNotificationsForType(
326 NotificationHandler::Type::TRANSIENT)
327 .size());
[email protected]05d6118652014-05-21 23:14:05328}