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

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

Issue 2923663002: ExtensionStorageMonitor: use smaller, self-registering StorageObservers (Closed)
Patch Set: Remove lame comment. 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 auto dir = base::MakeUnique<TestExtensionDir>();
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 const char* script = R"(
211 HostedAppWriteData(%s, %d)
212 .then(() => domAutomationController.send('write_done'))
213 .catch(e => domAutomationController.send('write_error: ' + e));
214 )";
215 ASSERT_TRUE(ExecuteScriptAndExtractString(
216 web_contents, base::StringPrintf(script, filesystem.c_str(), num_bytes),
217 &result));
218 ASSERT_EQ("write_done", result);
219 }
220
221 // Write bytes for the extension loaded from:
222 // //chrome/test/data/extensions/storage_monitor/write_data
223 void WriteBytesForExtension(const Extension* extension, int num_bytes) {
224 ExtensionTestMessageListener launched_listener("launched", true);
225 ExtensionTestMessageListener write_complete_listener("write_complete",
226 false);
227
228 OpenApplication(AppLaunchParams(profile(), extension, LAUNCH_CONTAINER_NONE,
229 WindowOpenDisposition::NEW_WINDOW,
230 extensions::SOURCE_TEST));
231
232 ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
233
234 // Instruct the app to write |num_bytes| of data.
235 launched_listener.Reply(base::IntToString(num_bytes));
236 ASSERT_TRUE(write_complete_listener.WaitUntilSatisfied());
237 }
238
152 // Write a number of bytes to persistent storage. 239 // Write a number of bytes to persistent storage.
153 void WriteBytes(const Extension* extension, 240 void WriteBytes(const Extension* extension,
154 int num_bytes, 241 int num_bytes,
242 const std::string& filesystem,
155 bool expected_notification) { 243 bool expected_notification) {
156 ExtensionTestMessageListener launched_listener("launched", true);
157 ExtensionTestMessageListener write_complete_listener(
158 "write_complete", false);
159 NotificationObserver notification_observer( 244 NotificationObserver notification_observer(
160 GetNotificationId(extension->id())); 245 GetNotificationId(extension->id()));
161 246
162 OpenApplication(AppLaunchParams(profile(), extension, LAUNCH_CONTAINER_NONE, 247 if (extension->is_hosted_app()) {
163 WindowOpenDisposition::NEW_WINDOW, 248 WriteBytesForHostedApp(extension, num_bytes, filesystem);
164 extensions::SOURCE_TEST)); 249 } else {
165 ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); 250 ASSERT_EQ("PERSISTENT", filesystem) << "Not implemented in the js code.";
166 251 WriteBytesForExtension(extension, num_bytes);
167 // Instruct the app to write |num_bytes| of data. 252 }
168 launched_listener.Reply(base::IntToString(num_bytes));
169 ASSERT_TRUE(write_complete_listener.WaitUntilSatisfied());
170 253
171 if (expected_notification) { 254 if (expected_notification) {
172 EXPECT_TRUE(notification_observer.WaitForNotification()); 255 ASSERT_TRUE(notification_observer.WaitForNotification());
173 } else { 256 } else {
174 base::RunLoop().RunUntilIdle(); 257 base::RunLoop().RunUntilIdle();
175 EXPECT_FALSE(notification_observer.HasReceivedNotification()); 258 ASSERT_FALSE(notification_observer.HasReceivedNotification());
176 } 259 }
177 } 260 }
178 261
179 ExtensionStorageMonitor* storage_monitor_; 262 ExtensionStorageMonitor* storage_monitor_;
263 std::vector<std::unique_ptr<TestExtensionDir>> temp_dirs_;
180 }; 264 };
181 265
182 // Control - No notifications should be shown if usage remains under the 266 // Control - No notifications should be shown if usage remains under the
183 // threshold. 267 // threshold.
184 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UnderThreshold) { 268 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, UnderThreshold) {
185 const Extension* extension = InitWriteDataApp(); 269 const Extension* extension = InitWriteDataApp();
186 ASSERT_TRUE(extension); 270 ASSERT_TRUE(extension);
187 WriteBytesNotExpectingNotification(extension, 1); 271 WriteBytesNotExpectingNotification(extension, 1);
188 } 272 }
189 273
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 // is eventually enabled for all extensions. 330 // is eventually enabled for all extensions.
247 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, 331 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
248 DisableForInstalledExtensions) { 332 DisableForInstalledExtensions) {
249 DisableForInstalledExtensions(); 333 DisableForInstalledExtensions();
250 334
251 const Extension* extension = InitWriteDataApp(); 335 const Extension* extension = InitWriteDataApp();
252 ASSERT_TRUE(extension); 336 ASSERT_TRUE(extension);
253 WriteBytesNotExpectingNotification(extension, GetInitialExtensionThreshold()); 337 WriteBytesNotExpectingNotification(extension, GetInitialExtensionThreshold());
254 } 338 }
255 339
340 // Regression test for https://crbug.com/716426
341 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
342 HostedAppTemporaryFilesystem) {
343 ASSERT_TRUE(embedded_test_server()->Start());
344
345 GURL url = embedded_test_server()->GetURL(
346 "chromium.org", "/extensions/storage_monitor/hosted_apps/one/index.html");
347 const Extension* app =
348 CreateHostedApp("Hosted App", url, {"unlimitedStorage"});
349
350 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
351 app, GetInitialExtensionThreshold(), "TEMPORARY"));
352 EXPECT_NO_FATAL_FAILURE(WriteBytesNotExpectingNotification(
353 app, GetInitialExtensionThreshold(), "PERSISTENT"));
354 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
355 app, GetInitialExtensionThreshold(), "TEMPORARY"));
356
357 // Bug 716426 was a shutdown crash due to not removing a
358 // storage::StorageObserver registration before deleting the observer. To
359 // recreate that scenario, first disable the app (which leaks the observer
360 // registration), then simulate the step of profile exit where we delete the
361 // StorageObserver.
362 DisableExtension(app->id());
363 SimulateProfileShutdown();
364
365 // Now generate more storage activity for the hosted app's temporary
366 // filesystem. Note that it's not a hosted app anymore -- it's just a webpage.
367 // Bug 716426 caused this to crash the browser.
368 EXPECT_NO_FATAL_FAILURE(WriteBytesNotExpectingNotification(
369 app, GetInitialExtensionThreshold(), "TEMPORARY"));
370 }
371
372 // Exercises the case where two hosted apps are same-origin but have non-
373 // overlapping extents. Disabling one should not suppress storage monitoring for
374 // the other.
375 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, TwoHostedAppsInSameOrigin) {
376 ASSERT_TRUE(embedded_test_server()->Start());
377
378 GURL url1 = embedded_test_server()->GetURL(
379 "chromium.org", "/extensions/storage_monitor/hosted_apps/one/index.html");
380 const Extension* app1 = CreateHostedApp("App 1", url1, {"unlimitedStorage"});
381
382 GURL url2 = embedded_test_server()->GetURL(
383 "chromium.org", "/extensions/storage_monitor/hosted_apps/two/index.html");
384 const Extension* app2 = CreateHostedApp("App 2", url2, {"unlimitedStorage"});
385
386 EXPECT_EQ(url1.GetOrigin(), url2.GetOrigin());
387
388 EXPECT_NO_FATAL_FAILURE(
389 WriteBytesExpectingNotification(app1, GetInitialExtensionThreshold()));
390 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
391 app2, GetInitialExtensionThreshold() * 2));
392
393 // Disable app2. We should still be monitoring the origin on behalf of app1.
394 DisableExtension(app2->id());
395
396 // Writing a bunch of data in app1 should trigger the warning.
397 EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
398 app1, GetInitialExtensionThreshold() * 4));
399 }
400
256 // Verify that notifications are disabled when the user clicks the action button 401 // Verify that notifications are disabled when the user clicks the action button
257 // in the notification. 402 // in the notification.
258 // Flaky: https://crbug.com/617801 403 // Flaky: https://crbug.com/617801
259 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, 404 IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
260 DISABLED_UninstallExtension) { 405 DISABLED_UninstallExtension) {
261 const Extension* extension = InitWriteDataApp(); 406 const Extension* extension = InitWriteDataApp();
262 ASSERT_TRUE(extension); 407 ASSERT_TRUE(extension);
263 WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold()); 408 WriteBytesExpectingNotification(extension, GetInitialExtensionThreshold());
264 409
265 // Fake clicking the notification button to uninstall and accepting the 410 // Fake clicking the notification button to uninstall and accepting the
266 // uninstall. 411 // uninstall.
267 ScopedTestDialogAutoConfirm scoped_autoconfirm( 412 ScopedTestDialogAutoConfirm scoped_autoconfirm(
268 ScopedTestDialogAutoConfirm::ACCEPT); 413 ScopedTestDialogAutoConfirm::ACCEPT);
269 TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()), 414 TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()),
270 extension->id()); 415 extension->id());
271 message_center::MessageCenter::Get()->ClickOnNotificationButton( 416 message_center::MessageCenter::Get()->ClickOnNotificationButton(
272 GetNotificationId(extension->id()), 417 GetNotificationId(extension->id()),
273 ExtensionStorageMonitor::BUTTON_UNINSTALL); 418 ExtensionStorageMonitor::BUTTON_UNINSTALL);
274 observer.WaitForExtensionUninstalled(); 419 observer.WaitForExtensionUninstalled();
275 } 420 }
276 421
277 } // namespace extensions 422 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698