Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: chrome/browser/extensions/extension_storage_monitor_browsertest.cc

Issue 2923663002: ExtensionStorageMonitor: use smaller, self-registering StorageObservers (Closed)
Patch Set: Fiddling. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdint.h> 5 #include <stdint.h>
6 6
7 #include <set> 7 #include <set>
8 #include <string>
9 #include <vector>
8 10
9 #include "base/run_loop.h" 11 #include "base/run_loop.h"
10 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
11 #include "chrome/browser/extensions/extension_browsertest.h" 13 #include "chrome/browser/extensions/extension_browsertest.h"
12 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/extension_storage_monitor.h" 15 #include "chrome/browser/extensions/extension_storage_monitor.h"
16 #include "chrome/browser/extensions/test_extension_dir.h"
14 #include "chrome/browser/ui/extensions/app_launch_params.h" 17 #include "chrome/browser/ui/extensions/app_launch_params.h"
15 #include "chrome/browser/ui/extensions/application_launch.h" 18 #include "chrome/browser/ui/extensions/application_launch.h"
19 #include "content/public/test/browser_test_utils.h"
16 #include "content/public/test/test_utils.h" 20 #include "content/public/test/test_utils.h"
17 #include "extensions/browser/extension_dialog_auto_confirm.h" 21 #include "extensions/browser/extension_dialog_auto_confirm.h"
18 #include "extensions/browser/extension_prefs.h" 22 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_registry.h" 23 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h" 24 #include "extensions/browser/extension_system.h"
21 #include "extensions/browser/test_extension_registry_observer.h" 25 #include "extensions/browser/test_extension_registry_observer.h"
22 #include "extensions/common/constants.h" 26 #include "extensions/common/constants.h"
27 #include "extensions/common/value_builder.h"
23 #include "extensions/test/extension_test_message_listener.h" 28 #include "extensions/test/extension_test_message_listener.h"
29 #include "net/dns/mock_host_resolver.h"
24 #include "ui/message_center/message_center.h" 30 #include "ui/message_center/message_center.h"
25 #include "ui/message_center/message_center_observer.h" 31 #include "ui/message_center/message_center_observer.h"
26 32
27 namespace extensions { 33 namespace extensions {
28 34
29 namespace { 35 namespace {
30 36
31 const int kInitialUsageThreshold = 500; 37 const int kInitialUsageThreshold = 500;
32 38
33 const char kWriteDataApp[] = "storage_monitor/write_data"; 39 const char kWriteDataApp[] = "storage_monitor/write_data";
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 85
80 class ExtensionStorageMonitorTest : public ExtensionBrowserTest { 86 class ExtensionStorageMonitorTest : public ExtensionBrowserTest {
81 public: 87 public:
82 ExtensionStorageMonitorTest() : storage_monitor_(NULL) {} 88 ExtensionStorageMonitorTest() : storage_monitor_(NULL) {}
83 89
84 protected: 90 protected:
85 // ExtensionBrowserTest overrides: 91 // ExtensionBrowserTest overrides:
86 void SetUpOnMainThread() override { 92 void SetUpOnMainThread() override {
87 ExtensionBrowserTest::SetUpOnMainThread(); 93 ExtensionBrowserTest::SetUpOnMainThread();
88 94
95 host_resolver()->AddRule("*", "127.0.0.1");
96
89 InitStorageMonitor(); 97 InitStorageMonitor();
90 } 98 }
91 99
92 ExtensionStorageMonitor* monitor() { 100 ExtensionStorageMonitor* monitor() {
93 CHECK(storage_monitor_); 101 CHECK(storage_monitor_);
94 return storage_monitor_; 102 return storage_monitor_;
95 } 103 }
96 104
97 int64_t GetInitialExtensionThreshold() { 105 int64_t GetInitialExtensionThreshold() {
98 CHECK(storage_monitor_); 106 CHECK(storage_monitor_);
99 return storage_monitor_->initial_extension_threshold_; 107 return storage_monitor_->initial_extension_threshold_;
100 } 108 }
101 109
102 void DisableForInstalledExtensions() { 110 void DisableForInstalledExtensions() {
103 CHECK(storage_monitor_); 111 CHECK(storage_monitor_);
104 storage_monitor_->enable_for_all_extensions_ = false; 112 storage_monitor_->enable_for_all_extensions_ = false;
105 } 113 }
106 114
107 const Extension* InitWriteDataApp() { 115 const Extension* InitWriteDataApp() {
108 base::FilePath path = test_data_dir_.AppendASCII(kWriteDataApp); 116 base::FilePath path = test_data_dir_.AppendASCII(kWriteDataApp);
109 const Extension* extension = InstallExtension(path, 1); 117 const Extension* extension = InstallExtension(path, 1);
110 EXPECT_TRUE(extension); 118 EXPECT_TRUE(extension);
111 return extension; 119 return extension;
112 } 120 }
113 121
122 const Extension* CreateHostedApp(const std::string& name,
123 GURL app_url,
124 std::vector<std::string> permissions) {
125 std::unique_ptr<TestExtensionDir> dir(new TestExtensionDir);
Devlin 2017/06/12 20:15:05 prefer auto dir = base::MakeUnique<TestExtensionDi
ncarter (slow) 2017/06/12 22:52:07 Done.
126
127 url::Replacements<char> clear_port;
128 clear_port.ClearPort();
129
130 DictionaryBuilder manifest;
131 manifest.Set("name", name)
132 .Set("version", "1.0")
133 .Set("manifest_version", 2)
134 .Set(
135 "app",
136 DictionaryBuilder()
137 .Set("urls",
138 ListBuilder()
139 .Append(app_url.ReplaceComponents(clear_port).spec())
140 .Build())
141 .Set("launch",
142 DictionaryBuilder().Set("web_url", app_url.spec()).Build())
143 .Build());
144 ListBuilder permissions_builder;
145 for (const std::string& permission : permissions)
146 permissions_builder.Append(permission);
147 manifest.Set("permissions", permissions_builder.Build());
148 dir->WriteManifest(manifest.ToJSON());
149
150 const Extension* extension = LoadExtension(dir->UnpackedPath());
151 EXPECT_TRUE(extension);
152 temp_dirs_.push_back(std::move(dir));
153 return extension;
154 }
155
114 std::string GetNotificationId(const std::string& extension_id) { 156 std::string GetNotificationId(const std::string& extension_id) {
115 return monitor()->GetNotificationId(extension_id); 157 return monitor()->GetNotificationId(extension_id);
116 } 158 }
117 159
118 bool IsStorageNotificationEnabled(const std::string& extension_id) { 160 bool IsStorageNotificationEnabled(const std::string& extension_id) {
119 return monitor()->IsStorageNotificationEnabled(extension_id); 161 return monitor()->IsStorageNotificationEnabled(extension_id);
120 } 162 }
121 163
122 int64_t GetNextStorageThreshold(const std::string& extension_id) { 164 int64_t GetNextStorageThreshold(const std::string& extension_id) {
123 return monitor()->GetNextStorageThreshold(extension_id); 165 return monitor()->GetNextStorageThreshold(extension_id);
124 } 166 }
125 167
126 void WriteBytesExpectingNotification(const Extension* extension, 168 void WriteBytesExpectingNotification(const Extension* extension,
127 int num_bytes) { 169 int num_bytes,
170 const char* filesystem = "PERSISTENT") {
128 int64_t previous_threshold = GetNextStorageThreshold(extension->id()); 171 int64_t previous_threshold = GetNextStorageThreshold(extension->id());
129 WriteBytes(extension, num_bytes, true); 172 WriteBytes(extension, num_bytes, filesystem, true);
130 EXPECT_GT(GetNextStorageThreshold(extension->id()), previous_threshold); 173 ASSERT_GT(GetNextStorageThreshold(extension->id()), previous_threshold);
131 } 174 }
132 175
133 void WriteBytesNotExpectingNotification(const Extension* extension, 176 void WriteBytesNotExpectingNotification(
134 int num_bytes) { 177 const Extension* extension,
135 WriteBytes(extension, num_bytes, false); 178 int num_bytes,
179 const char* filesystem = "PERSISTENT") {
180 WriteBytes(extension, num_bytes, filesystem, false);
136 } 181 }
137 182
183 void SimulateProfileShutdown() { storage_monitor_->StopMonitoringAll(); }
184
138 private: 185 private:
139 void InitStorageMonitor() { 186 void InitStorageMonitor() {
140 storage_monitor_ = ExtensionStorageMonitor::Get(profile()); 187 storage_monitor_ = ExtensionStorageMonitor::Get(profile());
141 ASSERT_TRUE(storage_monitor_); 188 ASSERT_TRUE(storage_monitor_);
142 189
143 // Override thresholds so that we don't have to write a huge amount of data 190 // Override thresholds so that we don't have to write a huge amount of data
144 // to trigger notifications in these tests. 191 // to trigger notifications in these tests.
145 storage_monitor_->enable_for_all_extensions_ = true; 192 storage_monitor_->enable_for_all_extensions_ = true;
146 storage_monitor_->initial_extension_threshold_ = kInitialUsageThreshold; 193 storage_monitor_->initial_extension_threshold_ = kInitialUsageThreshold;
147 194
148 // To ensure storage events are dispatched from QuotaManager immediately. 195 // To ensure storage events are dispatched from QuotaManager immediately.
149 storage_monitor_->observer_rate_ = base::TimeDelta(); 196 storage_monitor_->observer_rate_ = base::TimeDelta();
150 } 197 }
151 198
199 // Write bytes for a hosted app page that's loaded the script:
200 // //chrome/test/data/extensions/storage_monitor/hosted_apps/common.js
201 void WriteBytesForHostedApp(const Extension* extension,
202 int num_bytes,
203 const std::string& filesystem) {
204 content::WebContents* web_contents = OpenApplication(AppLaunchParams(
205 profile(), extension, LAUNCH_CONTAINER_TAB,
206 WindowOpenDisposition::SINGLETON_TAB, extensions::SOURCE_TEST));
207
208 ASSERT_TRUE(WaitForLoadStop(web_contents));
209 std::string result;
210 ASSERT_TRUE(ExecuteScriptAndExtractString(
211 web_contents,
212 base::StringPrintf(R"(
213 HostedAppWriteData(%s, %d)
214 .then(() => domAutomationController.send('write_done'))
215 .catch(e => domAutomationController.send('write_error: ' + e));
216 )",
217 filesystem.c_str(), num_bytes),
Devlin 2017/06/12 20:15:05 ... this formatting's a bit odd. Was this git cl
ncarter (slow) 2017/06/12 22:52:07 Fixed by extracting the literal to a local variabl
218 &result));
219
220 ASSERT_EQ("write_done", result);
221 }
222
223 // Write bytes for the extension loaded from:
224 // //chrome/test/data/extensions/storage_monitor/write_data
225 void WriteBytesForExtension(const Extension* extension, int num_bytes) {
226 ExtensionTestMessageListener launched_listener("launched", true);
227 ExtensionTestMessageListener write_complete_listener("write_complete",
228 false);
229
230 OpenApplication(AppLaunchParams(profile(), extension, LAUNCH_CONTAINER_NONE,
231 WindowOpenDisposition::NEW_WINDOW,
232 extensions::SOURCE_TEST));
233
234 ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
235
236 // Instruct the app to write |num_bytes| of data.
237 launched_listener.Reply(base::IntToString(num_bytes));
238 ASSERT_TRUE(write_complete_listener.WaitUntilSatisfied());
239 }
240
152 // Write a number of bytes to persistent storage. 241 // Write a number of bytes to persistent storage.
153 void WriteBytes(const Extension* extension, 242 void WriteBytes(const Extension* extension,
154 int num_bytes, 243 int num_bytes,
244 const std::string& filesystem,
155 bool expected_notification) { 245 bool expected_notification) {
156 ExtensionTestMessageListener launched_listener("launched", true);
157 ExtensionTestMessageListener write_complete_listener(
158 "write_complete", false);
159 NotificationObserver notification_observer( 246 NotificationObserver notification_observer(
160 GetNotificationId(extension->id())); 247 GetNotificationId(extension->id()));
161 248
162 OpenApplication(AppLaunchParams(profile(), extension, LAUNCH_CONTAINER_NONE, 249 if (extension->is_hosted_app()) {
163 WindowOpenDisposition::NEW_WINDOW, 250 WriteBytesForHostedApp(extension, num_bytes, filesystem);
164 extensions::SOURCE_TEST)); 251 } else {
165 ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); 252 ASSERT_EQ("PERSISTENT", filesystem) << "Not implemented in the js code.";
166 253 WriteBytesForExtension(extension, num_bytes);
167 // Instruct the app to write |num_bytes| of data. 254 }
168 launched_listener.Reply(base::IntToString(num_bytes));
169 ASSERT_TRUE(write_complete_listener.WaitUntilSatisfied());
170 255
171 if (expected_notification) { 256 if (expected_notification) {
172 EXPECT_TRUE(notification_observer.WaitForNotification()); 257 ASSERT_TRUE(notification_observer.WaitForNotification());
173 } else { 258 } else {
174 base::RunLoop().RunUntilIdle(); 259 base::RunLoop().RunUntilIdle();
175 EXPECT_FALSE(notification_observer.HasReceivedNotification()); 260 ASSERT_FALSE(notification_observer.HasReceivedNotification());
176 } 261 }
177 } 262 }
178 263
179 ExtensionStorageMonitor* storage_monitor_; 264 ExtensionStorageMonitor* storage_monitor_;
265 std::vector<std::unique_ptr<TestExtensionDir>> temp_dirs_;
180 }; 266 };
181 267
182 // Control - No notifications should be shown if usage remains under the 268 // Control - No notifications should be shown if usage remains under the
183 // threshold. 269 // threshold.
184 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UnderThreshold) { 270 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UnderThreshold) {
185 const Extension* extension = InitWriteDataApp(); 271 const Extension* extension = InitWriteDataApp();
186 ASSERT_TRUE(extension); 272 ASSERT_TRUE(extension);
187 WriteBytesNotExpectingNotification(extension, 1); 273 WriteBytesNotExpectingNotification(extension, 1);
188 } 274 }
189 275
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 // is eventually enabled for all extensions. 332 // is eventually enabled for all extensions.
247 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, 333 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
248 DisableForInstalledExtensions) { 334 DisableForInstalledExtensions) {
249 DisableForInstalledExtensions(); 335 DisableForInstalledExtensions();
250 336
251 const Extension* extension = InitWriteDataApp(); 337 const Extension* extension = InitWriteDataApp();
252 ASSERT_TRUE(extension); 338 ASSERT_TRUE(extension);
253 WriteBytesNotExpectingNotification(extension, GetInitialExtensionThreshold()); 339 WriteBytesNotExpectingNotification(extension, GetInitialExtensionThreshold());
254 } 340 }
255 341
342 // Regression test for https://crbug.com/716426
343 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
344 HostedAppTemporaryFilesystem) {
345 ASSERT_TRUE(embedded_test_server()->Start());
346
347 GURL url = embedded_test_server()->GetURL(
348 "chromium.org", "/extensions/storage_monitor/hosted_apps/one/index.html");
349 const Extension* app =
350 CreateHostedApp("Hosted App", url, {"unlimitedStorage"});
351
352 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
353 app, GetInitialExtensionThreshold(), "TEMPORARY"));
354 EXPECT_NO_FATAL_FAILURE(WriteBytesNotExpectingNotification(
355 app, GetInitialExtensionThreshold(), "PERSISTENT"));
356 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
357 app, GetInitialExtensionThreshold(), "TEMPORARY"));
358
359 // Bug 716426 was a shutdown crash due to not removing a
360 // storage::StorageObserver registration before deleting the observer. To
361 // recreate that scenario, first disable the app (which leaks the observer
362 // registration), then simulate the step of profile exit where we delete the
363 // StorageObserver.
364 DisableExtension(app->id());
365 SimulateProfileShutdown();
366
367 // Now generate more storage activity for the hosted app's temporary
368 // filesystem. Note that it's not a hosted app anymore -- it's just a webpage.
369 // Bug 716426 caused this to crash the browser.
370 EXPECT_NO_FATAL_FAILURE(WriteBytesNotExpectingNotification(
371 app, GetInitialExtensionThreshold(), "TEMPORARY"));
372 }
373
374 // Exercises the case where two hosted apps are same-origin but have non-
375 // overlapping extents. Disabling one should not suppress storage monitoring for
376 // the other.
377 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, TwoHostedAppsInSameOrigin) {
378 ASSERT_TRUE(embedded_test_server()->Start());
379
380 GURL url1 = embedded_test_server()->GetURL(
381 "chromium.org", "/extensions/storage_monitor/hosted_apps/one/index.html");
382 const Extension* app1 = CreateHostedApp("App 1", url1, {"unlimitedStorage"});
383
384 GURL url2 = embedded_test_server()->GetURL(
385 "chromium.org", "/extensions/storage_monitor/hosted_apps/two/index.html");
386 const Extension* app2 = CreateHostedApp("App 2", url2, {"unlimitedStorage"});
387
388 EXPECT_EQ(url1.GetOrigin(), url2.GetOrigin());
389
390 EXPECT_NO_FATAL_FAILURE(
391 WriteBytesExpectingNotification(app1, GetInitialExtensionThreshold()));
392 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
393 app2, GetInitialExtensionThreshold() * 2));
394
395 // Disable app2. We should still be monitoring the origin on behalf of app1.
396 DisableExtension(app2->id());
397
398 // Writing a bunch of data in app1 should trigger the warning.
399 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
400 app1, GetInitialExtensionThreshold() * 4));
401 }
402
256 // Verify that notifications are disabled when the user clicks the action button 403 // Verify that notifications are disabled when the user clicks the action button
257 // in the notification. 404 // in the notification.
258 // Flaky: https://crbug.com/617801 405 // Flaky: https://crbug.com/617801
259 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, 406 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
260 DISABLED_UninstallExtension) { 407 DISABLED_UninstallExtension) {
261 const Extension* extension = InitWriteDataApp(); 408 const Extension* extension = InitWriteDataApp();
262 ASSERT_TRUE(extension); 409 ASSERT_TRUE(extension);
263 WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold()); 410 WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
264 411
265 // Fake clicking the notification button to uninstall and accepting the 412 // Fake clicking the notification button to uninstall and accepting the
266 // uninstall. 413 // uninstall.
267 ScopedTestDialogAutoConfirm scoped_autoconfirm( 414 ScopedTestDialogAutoConfirm scoped_autoconfirm(
268 ScopedTestDialogAutoConfirm::ACCEPT); 415 ScopedTestDialogAutoConfirm::ACCEPT);
269 TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()), 416 TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()),
270 extension->id()); 417 extension->id());
271 message_center::MessageCenter::Get()->ClickOnNotificationButton( 418 message_center::MessageCenter::Get()->ClickOnNotificationButton(
272 GetNotificationId(extension->id()), 419 GetNotificationId(extension->id()),
273 ExtensionStorageMonitor::BUTTON_UNINSTALL); 420 ExtensionStorageMonitor::BUTTON_UNINSTALL);
274 observer.WaitForExtensionUninstalled(); 421 observer.WaitForExtensionUninstalled();
275 } 422 }
276 423
277 } // namespace extensions 424 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698