blob: 88c812a756176670d01ff2cb9e87248d9baa465d [file] [log] [blame]
[email protected]a7789f22014-03-12 16:10:381// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dchengc963c7142016-04-08 03:55:225#include "chrome/browser/extensions/extension_web_ui.h"
6
[email protected]a7789f22014-03-12 16:10:387#include "base/command_line.h"
dchengc963c7142016-04-08 03:55:228#include "base/memory/ptr_util.h"
fdoraycb32419d2016-06-23 15:52:559#include "base/run_loop.h"
avia2f4804a2015-12-24 23:11:1310#include "build/build_config.h"
[email protected]a7789f22014-03-12 16:10:3811#include "chrome/browser/extensions/extension_service.h"
rdevlin.cronin5fafa5a2015-12-30 03:42:0212#include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
[email protected]a7789f22014-03-12 16:10:3813#include "chrome/browser/extensions/test_extension_system.h"
14#include "chrome/test/base/testing_profile.h"
fdoray2ce6dc222017-04-27 14:39:3915#include "content/public/test/test_browser_thread_bundle.h"
[email protected]03d25812014-06-22 19:41:5516#include "extensions/browser/extension_system.h"
[email protected]a7789f22014-03-12 16:10:3817#include "extensions/common/extension.h"
18#include "extensions/common/extension_builder.h"
19#include "extensions/common/manifest_constants.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22#if defined(OS_CHROMEOS)
[email protected]4d390782014-08-15 09:22:5823#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
[email protected]a7789f22014-03-12 16:10:3824#include "chrome/browser/chromeos/settings/cros_settings.h"
25#include "chrome/browser/chromeos/settings/device_settings_service.h"
26#endif
27
28namespace extensions {
29
rdevlin.cronin5fafa5a2015-12-30 03:42:0230namespace {
31
dchengc963c7142016-04-08 03:55:2232std::unique_ptr<KeyedService> BuildOverrideRegistrar(
rdevlin.cronin5fafa5a2015-12-30 03:42:0233 content::BrowserContext* context) {
ricea91d6fc122016-08-30 08:47:1434 return base::MakeUnique<ExtensionWebUIOverrideRegistrar>(context);
rdevlin.cronin5fafa5a2015-12-30 03:42:0235}
36
37} // namespace
38
[email protected]a7789f22014-03-12 16:10:3839class ExtensionWebUITest : public testing::Test {
40 public:
fdoray2ce6dc222017-04-27 14:39:3941 ExtensionWebUITest() = default;
[email protected]a7789f22014-03-12 16:10:3842
43 protected:
dcheng72191812014-10-28 20:49:5644 void SetUp() override {
[email protected]a7789f22014-03-12 16:10:3845 profile_.reset(new TestingProfile());
46 TestExtensionSystem* system =
47 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_.get()));
48 extension_service_ = system->CreateExtensionService(
avi3ef9ec9e2014-12-22 22:50:1749 base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
rdevlin.cronin5fafa5a2015-12-30 03:42:0250 ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->SetTestingFactory(
51 profile_.get(), &BuildOverrideRegistrar);
52 ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->Get(profile_.get());
[email protected]a7789f22014-03-12 16:10:3853 }
54
dcheng72191812014-10-28 20:49:5655 void TearDown() override {
[email protected]a7789f22014-03-12 16:10:3856 profile_.reset();
fdoraycb32419d2016-06-23 15:52:5557 base::RunLoop().RunUntilIdle();
[email protected]a7789f22014-03-12 16:10:3858 }
59
dchengc963c7142016-04-08 03:55:2260 std::unique_ptr<TestingProfile> profile_;
[email protected]a7789f22014-03-12 16:10:3861 ExtensionService* extension_service_;
fdoray2ce6dc222017-04-27 14:39:3962 content::TestBrowserThreadBundle test_browser_thread_bundle_;
[email protected]a7789f22014-03-12 16:10:3863
64#if defined OS_CHROMEOS
65 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
66 chromeos::ScopedTestCrosSettings test_cros_settings_;
67 chromeos::ScopedTestUserManager test_user_manager_;
68#endif
69};
70
71// Test that component extension url overrides have lower priority than
72// non-component extension url overrides.
73TEST_F(ExtensionWebUITest, ExtensionURLOverride) {
rdevlin.cronin2b7cf6a2016-01-27 18:23:5274 const char kOverrideResource[] = "1.html";
[email protected]6584f472014-03-18 17:42:2475 // Register a non-component extension.
[email protected]03d25812014-06-22 19:41:5576 DictionaryBuilder manifest;
[email protected]a7789f22014-03-12 16:10:3877 manifest.Set(manifest_keys::kName, "ext1")
78 .Set(manifest_keys::kVersion, "0.1")
79 .Set(std::string(manifest_keys::kChromeURLOverrides),
dcheng794d2bd2016-02-27 03:51:3280 DictionaryBuilder().Set("bookmarks", kOverrideResource).Build());
[email protected]6584f472014-03-18 17:42:2481 scoped_refptr<Extension> ext_unpacked(
[email protected]03d25812014-06-22 19:41:5582 ExtensionBuilder()
dcheng794d2bd2016-02-27 03:51:3283 .SetManifest(manifest.Build())
[email protected]6584f472014-03-18 17:42:2484 .SetLocation(Manifest::UNPACKED)
[email protected]a7789f22014-03-12 16:10:3885 .SetID("abcdefghijabcdefghijabcdefghijaa")
86 .Build());
[email protected]03d25812014-06-22 19:41:5587 extension_service_->AddExtension(ext_unpacked.get());
[email protected]a7789f22014-03-12 16:10:3888
rdevlin.cronin2b7cf6a2016-01-27 18:23:5289 const GURL kExpectedUnpackedOverrideUrl =
90 ext_unpacked->GetResourceURL(kOverrideResource);
91 const GURL kBookmarksUrl("chrome://bookmarks");
92 GURL changed_url = kBookmarksUrl;
93 EXPECT_TRUE(
94 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
95 EXPECT_EQ(kExpectedUnpackedOverrideUrl, changed_url);
96 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
97 profile_.get()));
98 EXPECT_EQ(kBookmarksUrl, changed_url);
99
100 GURL url_plus_fragment = kBookmarksUrl.Resolve("#1");
101 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverride(&url_plus_fragment,
102 profile_.get()));
103 EXPECT_EQ(kExpectedUnpackedOverrideUrl.Resolve("#1"),
104 url_plus_fragment);
105 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&url_plus_fragment,
106 profile_.get()));
107 EXPECT_EQ(kBookmarksUrl.Resolve("#1"), url_plus_fragment);
[email protected]6584f472014-03-18 17:42:24108
109 // Register a component extension
rdevlin.cronin2b7cf6a2016-01-27 18:23:52110 const char kOverrideResource2[] = "2.html";
[email protected]03d25812014-06-22 19:41:55111 DictionaryBuilder manifest2;
[email protected]a7789f22014-03-12 16:10:38112 manifest2.Set(manifest_keys::kName, "ext2")
113 .Set(manifest_keys::kVersion, "0.1")
114 .Set(std::string(manifest_keys::kChromeURLOverrides),
dcheng794d2bd2016-02-27 03:51:32115 DictionaryBuilder().Set("bookmarks", kOverrideResource2).Build());
[email protected]6584f472014-03-18 17:42:24116 scoped_refptr<Extension> ext_component(
[email protected]03d25812014-06-22 19:41:55117 ExtensionBuilder()
dcheng794d2bd2016-02-27 03:51:32118 .SetManifest(manifest2.Build())
[email protected]6584f472014-03-18 17:42:24119 .SetLocation(Manifest::COMPONENT)
[email protected]a7789f22014-03-12 16:10:38120 .SetID("bbabcdefghijabcdefghijabcdefghij")
121 .Build());
[email protected]03d25812014-06-22 19:41:55122 extension_service_->AddComponentExtension(ext_component.get());
[email protected]a7789f22014-03-12 16:10:38123
[email protected]6584f472014-03-18 17:42:24124 // Despite being registered more recently, the component extension should
[email protected]3b09cec52014-05-15 00:33:41125 // not take precedence over the non-component extension.
rdevlin.cronin2b7cf6a2016-01-27 18:23:52126 changed_url = kBookmarksUrl;
127 EXPECT_TRUE(
128 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
129 EXPECT_EQ(kExpectedUnpackedOverrideUrl, changed_url);
130 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
131 profile_.get()));
132 EXPECT_EQ(kBookmarksUrl, changed_url);
[email protected]a7789f22014-03-12 16:10:38133
rdevlin.cronin2b7cf6a2016-01-27 18:23:52134 GURL kExpectedComponentOverrideUrl =
135 ext_component->GetResourceURL(kOverrideResource2);
[email protected]6584f472014-03-18 17:42:24136
[email protected]a7789f22014-03-12 16:10:38137 // Unregister non-component extension. Only component extension remaining.
138 ExtensionWebUI::UnregisterChromeURLOverrides(
139 profile_.get(), URLOverrides::GetChromeURLOverrides(ext_unpacked.get()));
rdevlin.cronin2b7cf6a2016-01-27 18:23:52140 changed_url = kBookmarksUrl;
141 EXPECT_TRUE(
142 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
143 EXPECT_EQ(kExpectedComponentOverrideUrl, changed_url);
144 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
145 profile_.get()));
146 EXPECT_EQ(kBookmarksUrl, changed_url);
[email protected]a7789f22014-03-12 16:10:38147
[email protected]6584f472014-03-18 17:42:24148 // This time the non-component extension was registered more recently and
149 // should still take precedence.
rdevlin.cronin5fafa5a2015-12-30 03:42:02150 ExtensionWebUI::RegisterOrActivateChromeURLOverrides(
[email protected]a7789f22014-03-12 16:10:38151 profile_.get(), URLOverrides::GetChromeURLOverrides(ext_unpacked.get()));
rdevlin.cronin2b7cf6a2016-01-27 18:23:52152 changed_url = kBookmarksUrl;
153 EXPECT_TRUE(
154 ExtensionWebUI::HandleChromeURLOverride(&changed_url, profile_.get()));
155 EXPECT_EQ(kExpectedUnpackedOverrideUrl, changed_url);
156 EXPECT_TRUE(ExtensionWebUI::HandleChromeURLOverrideReverse(&changed_url,
157 profile_.get()));
158 EXPECT_EQ(kBookmarksUrl, changed_url);
[email protected]a7789f22014-03-12 16:10:38159}
160
Devlin Cronin313da2812017-11-10 17:40:40161TEST_F(ExtensionWebUITest, TestRemovingDuplicateEntriesForHosts) {
162 // Test that duplicate entries for a single extension are removed. This could
163 // happen because of https://crbug.com/782959.
164 std::unique_ptr<base::DictionaryValue> manifest_overrides =
165 DictionaryBuilder().Set("newtab", "newtab.html").Build();
166 scoped_refptr<const Extension> extension =
167 ExtensionBuilder("extension")
168 .MergeManifest(
169 DictionaryBuilder()
170 .Set("chrome_url_overrides", std::move(manifest_overrides))
171 .Build())
172 .Build();
173
174 const GURL newtab_url = extension->GetResourceURL("newtab.html");
175
176 PrefService* prefs = profile_->GetPrefs();
177 {
178 // Add multiple entries for the same extension.
179 DictionaryPrefUpdate update(prefs, ExtensionWebUI::kExtensionURLOverrides);
180 base::DictionaryValue* all_overrides = update.Get();
181 base::Value newtab_list(base::Value::Type::LIST);
182 {
183 base::Value newtab(base::Value::Type::DICTIONARY);
184 newtab.SetKey("entry", base::Value(newtab_url.spec()));
185 newtab.SetKey("active", base::Value(true));
186 newtab_list.GetList().push_back(std::move(newtab));
187 }
188 {
189 base::Value newtab(base::Value::Type::DICTIONARY);
190 newtab.SetKey(
191 "entry",
192 base::Value(extension->GetResourceURL("oldtab.html").spec()));
193 newtab.SetKey("active", base::Value(true));
194 newtab_list.GetList().push_back(std::move(newtab));
195 }
196
197 all_overrides->SetKey("newtab", std::move(newtab_list));
198 }
199
200 extension_service_->AddExtension(extension.get());
201 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile_.get()))
202 ->SetReady();
203 base::RunLoop().RunUntilIdle();
204
205 // Duplicates should be removed (in response to ExtensionSystem::ready()).
206 // Only a single entry should remain.
207 const base::DictionaryValue* overrides =
208 prefs->GetDictionary(ExtensionWebUI::kExtensionURLOverrides);
209 ASSERT_TRUE(overrides);
210 const base::Value* newtab_overrides =
211 overrides->FindKeyOfType("newtab", base::Value::Type::LIST);
212 ASSERT_TRUE(newtab_overrides);
213 ASSERT_EQ(1u, newtab_overrides->GetList().size());
214 const base::Value& override_dict = newtab_overrides->GetList()[0];
215 EXPECT_EQ(newtab_url.spec(), override_dict.FindKey("entry")->GetString());
216 EXPECT_TRUE(override_dict.FindKey("active")->GetBool());
217}
218
[email protected]a7789f22014-03-12 16:10:38219} // namespace extensions