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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_storage_monitor_browsertest.cc
diff --git a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
index b9671a8945d6d1e405271ba4c42003ae989915d1..c70d5253e128097d2e3016c9bb534ecee057f5c5 100644
--- a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
+++ b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
@@ -5,14 +5,18 @@
#include <stdint.h>
#include <set>
+#include <string>
+#include <vector>
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_storage_monitor.h"
+#include "chrome/browser/extensions/test_extension_dir.h"
#include "chrome/browser/ui/extensions/app_launch_params.h"
#include "chrome/browser/ui/extensions/application_launch.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_dialog_auto_confirm.h"
#include "extensions/browser/extension_prefs.h"
@@ -20,7 +24,9 @@
#include "extensions/browser/extension_system.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/common/constants.h"
+#include "extensions/common/value_builder.h"
#include "extensions/test/extension_test_message_listener.h"
+#include "net/dns/mock_host_resolver.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_observer.h"
@@ -86,6 +92,8 @@ class ExtensionStorageMonitorTest : public ExtensionBrowserTest {
void SetUpOnMainThread() override {
ExtensionBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+
InitStorageMonitor();
}
@@ -111,6 +119,40 @@ class ExtensionStorageMonitorTest : public ExtensionBrowserTest {
return extension;
}
+ const Extension* CreateHostedApp(const std::string& name,
+ GURL app_url,
+ std::vector<std::string> permissions) {
+ auto dir = base::MakeUnique<TestExtensionDir>();
+
+ url::Replacements<char> clear_port;
+ clear_port.ClearPort();
+
+ DictionaryBuilder manifest;
+ manifest.Set("name", name)
+ .Set("version", "1.0")
+ .Set("manifest_version", 2)
+ .Set(
+ "app",
+ DictionaryBuilder()
+ .Set("urls",
+ ListBuilder()
+ .Append(app_url.ReplaceComponents(clear_port).spec())
+ .Build())
+ .Set("launch",
+ DictionaryBuilder().Set("web_url", app_url.spec()).Build())
+ .Build());
+ ListBuilder permissions_builder;
+ for (const std::string& permission : permissions)
+ permissions_builder.Append(permission);
+ manifest.Set("permissions", permissions_builder.Build());
+ dir->WriteManifest(manifest.ToJSON());
+
+ const Extension* extension = LoadExtension(dir->UnpackedPath());
+ EXPECT_TRUE(extension);
+ temp_dirs_.push_back(std::move(dir));
+ return extension;
+ }
+
std::string GetNotificationId(const std::string& extension_id) {
return monitor()->GetNotificationId(extension_id);
}
@@ -124,17 +166,22 @@ class ExtensionStorageMonitorTest : public ExtensionBrowserTest {
}
void WriteBytesExpectingNotification(const Extension* extension,
- int num_bytes) {
+ int num_bytes,
+ const char* filesystem = "PERSISTENT") {
int64_t previous_threshold = GetNextStorageThreshold(extension->id());
- WriteBytes(extension, num_bytes, true);
- EXPECT_GT(GetNextStorageThreshold(extension->id()), previous_threshold);
+ WriteBytes(extension, num_bytes, filesystem, true);
+ ASSERT_GT(GetNextStorageThreshold(extension->id()), previous_threshold);
}
- void WriteBytesNotExpectingNotification(const Extension* extension,
- int num_bytes) {
- WriteBytes(extension, num_bytes, false);
+ void WriteBytesNotExpectingNotification(
+ const Extension* extension,
+ int num_bytes,
+ const char* filesystem = "PERSISTENT") {
+ WriteBytes(extension, num_bytes, filesystem, false);
}
+ void SimulateProfileShutdown() { storage_monitor_->StopMonitoringAll(); }
+
private:
void InitStorageMonitor() {
storage_monitor_ = ExtensionStorageMonitor::Get(profile());
@@ -149,34 +196,71 @@ class ExtensionStorageMonitorTest : public ExtensionBrowserTest {
storage_monitor_->observer_rate_ = base::TimeDelta();
}
- // Write a number of bytes to persistent storage.
- void WriteBytes(const Extension* extension,
- int num_bytes,
- bool expected_notification) {
+ // Write bytes for a hosted app page that's loaded the script:
+ // //chrome/test/data/extensions/storage_monitor/hosted_apps/common.js
+ void WriteBytesForHostedApp(const Extension* extension,
+ int num_bytes,
+ const std::string& filesystem) {
+ content::WebContents* web_contents = OpenApplication(AppLaunchParams(
+ profile(), extension, LAUNCH_CONTAINER_TAB,
+ WindowOpenDisposition::SINGLETON_TAB, extensions::SOURCE_TEST));
+
+ ASSERT_TRUE(WaitForLoadStop(web_contents));
+ std::string result;
+ const char* script = R"(
+ HostedAppWriteData(%s, %d)
+ .then(() => domAutomationController.send('write_done'))
+ .catch(e => domAutomationController.send('write_error: ' + e));
+ )";
+ ASSERT_TRUE(ExecuteScriptAndExtractString(
+ web_contents, base::StringPrintf(script, filesystem.c_str(), num_bytes),
+ &result));
+ ASSERT_EQ("write_done", result);
+ }
+
+ // Write bytes for the extension loaded from:
+ // //chrome/test/data/extensions/storage_monitor/write_data
+ void WriteBytesForExtension(const Extension* extension, int num_bytes) {
ExtensionTestMessageListener launched_listener("launched", true);
- ExtensionTestMessageListener write_complete_listener(
- "write_complete", false);
- NotificationObserver notification_observer(
- GetNotificationId(extension->id()));
+ ExtensionTestMessageListener write_complete_listener("write_complete",
+ false);
OpenApplication(AppLaunchParams(profile(), extension, LAUNCH_CONTAINER_NONE,
WindowOpenDisposition::NEW_WINDOW,
extensions::SOURCE_TEST));
+
ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
// Instruct the app to write |num_bytes| of data.
launched_listener.Reply(base::IntToString(num_bytes));
ASSERT_TRUE(write_complete_listener.WaitUntilSatisfied());
+ }
+
+ // Write a number of bytes to persistent storage.
+ void WriteBytes(const Extension* extension,
+ int num_bytes,
+ const std::string& filesystem,
+ bool expected_notification) {
+ NotificationObserver notification_observer(
+ GetNotificationId(extension->id()));
+
+ if (extension->is_hosted_app()) {
+ WriteBytesForHostedApp(extension, num_bytes, filesystem);
+ } else {
+ ASSERT_EQ("PERSISTENT", filesystem) << "Not implemented in the js code.";
+ WriteBytesForExtension(extension, num_bytes);
+ }
if (expected_notification) {
- EXPECT_TRUE(notification_observer.WaitForNotification());
+ ASSERT_TRUE(notification_observer.WaitForNotification());
} else {
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(notification_observer.HasReceivedNotification());
+ ASSERT_FALSE(notification_observer.HasReceivedNotification());
}
}
ExtensionStorageMonitor* storage_monitor_;
+ std::vector<std::unique_ptr<TestExtensionDir>> temp_dirs_;
};
// Control - No notifications should be shown if usage remains under the
@@ -253,6 +337,67 @@ IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
WriteBytesNotExpectingNotification(extension, GetInitialExtensionThreshold());
}
+// Regression test for https://crbug.com/716426
+IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest,
+ HostedAppTemporaryFilesystem) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL url = embedded_test_server()->GetURL(
+ "chromium.org", "/extensions/storage_monitor/hosted_apps/one/index.html");
+ const Extension* app =
+ CreateHostedApp("Hosted App", url, {"unlimitedStorage"});
+
+ EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
+ app, GetInitialExtensionThreshold(), "TEMPORARY"));
+ EXPECT_NO_FATAL_FAILURE(WriteBytesNotExpectingNotification(
+ app, GetInitialExtensionThreshold(), "PERSISTENT"));
+ EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
+ app, GetInitialExtensionThreshold(), "TEMPORARY"));
+
+ // Bug 716426 was a shutdown crash due to not removing a
+ // storage::StorageObserver registration before deleting the observer. To
+ // recreate that scenario, first disable the app (which leaks the observer
+ // registration), then simulate the step of profile exit where we delete the
+ // StorageObserver.
+ DisableExtension(app->id());
+ SimulateProfileShutdown();
+
+ // Now generate more storage activity for the hosted app's temporary
+ // filesystem. Note that it's not a hosted app anymore -- it's just a webpage.
+ // Bug 716426 caused this to crash the browser.
+ EXPECT_NO_FATAL_FAILURE(WriteBytesNotExpectingNotification(
+ app, GetInitialExtensionThreshold(), "TEMPORARY"));
+}
+
+// Exercises the case where two hosted apps are same-origin but have non-
+// overlapping extents. Disabling one should not suppress storage monitoring for
+// the other.
+IN_PROC_BROWSER_TEST_F(ExtensionStorageMonitorTest, TwoHostedAppsInSameOrigin) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ GURL url1 = embedded_test_server()->GetURL(
+ "chromium.org", "/extensions/storage_monitor/hosted_apps/one/index.html");
+ const Extension* app1 = CreateHostedApp("App 1", url1, {"unlimitedStorage"});
+
+ GURL url2 = embedded_test_server()->GetURL(
+ "chromium.org", "/extensions/storage_monitor/hosted_apps/two/index.html");
+ const Extension* app2 = CreateHostedApp("App 2", url2, {"unlimitedStorage"});
+
+ EXPECT_EQ(url1.GetOrigin(), url2.GetOrigin());
+
+ EXPECT_NO_FATAL_FAILURE(
+ WriteBytesExpectingNotification(app1, GetInitialExtensionThreshold()));
+ EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
+ app2, GetInitialExtensionThreshold() * 2));
+
+ // Disable app2. We should still be monitoring the origin on behalf of app1.
+ DisableExtension(app2->id());
+
+ // Writing a bunch of data in app1 should trigger the warning.
+ EXPECT_NO_FATAL_FAILURE(WriteBytesExpectingNotification(
+ app1, GetInitialExtensionThreshold() * 4));
+}
+
// Verify that notifications are disabled when the user clicks the action button
// in the notification.
// Flaky: https://crbug.com/617801

Powered by Google App Engine
This is Rietveld 408576698