When uninstalling a hosted app, delete data for its launch_url's origin, as
long as no other apps are installed on that origin.

(cloned from matt's OCL http://codereview.chromium.org/7747025/)

TBR=mpcomplete
BUG=87258
Review URL: http://codereview.chromium.org/7807002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99288 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index a374f1a..3ded8b68 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -464,6 +464,13 @@
                              autoupdate_enabled);
 }
 
+void ExtensionServiceTestBase::InitializeRequestContext() {
+  ASSERT_TRUE(profile_.get());
+  ExtensionTestingProfile* profile =
+      static_cast<ExtensionTestingProfile*>(profile_.get());
+  profile->CreateRequestContext();
+}
+
 // static
 void ExtensionServiceTestBase::SetUpTestCase() {
   ExtensionErrorReporter::Init(false);  // no noisy errors
@@ -1792,6 +1799,7 @@
 
 TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
   InitializeEmptyExtensionService();
+  InitializeRequestContext();
   EXPECT_TRUE(service_->extensions()->empty());
 
   int pref_count = 0;
@@ -1843,6 +1851,7 @@
 
 TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) {
   InitializeEmptyExtensionService();
+  InitializeRequestContext();
   EXPECT_TRUE(service_->extensions()->empty());
 
   int pref_count = 0;
@@ -2702,7 +2711,7 @@
   ScopedRunnableMethodFactory<MessageLoop> message_loop_factory_;
 };
 
-// Verifies extension state is removed upon uninstall
+// Verifies extension state is removed upon uninstall.
 TEST_F(ExtensionServiceTest, ClearExtensionData) {
   InitializeEmptyExtensionService();
   ExtensionCookieCallback callback;
@@ -2790,6 +2799,133 @@
   EXPECT_FALSE(file_util::DirectoryExists(idb_path));
 }
 
+// Verifies app state is removed upon uninstall.
+TEST_F(ExtensionServiceTest, ClearAppData) {
+  InitializeEmptyExtensionService();
+  InitializeRequestContext();
+  ExtensionCookieCallback callback;
+
+  int pref_count = 0;
+
+  // Install app1 with unlimited storage.
+  PackAndInstallCrx(data_dir_.AppendASCII("app1"), true);
+  ValidatePrefKeyCount(++pref_count);
+  ASSERT_EQ(1u, service_->extensions()->size());
+  const Extension* extension = service_->extensions()->at(0);
+  const std::string id1 = extension->id();
+  EXPECT_TRUE(extension->HasAPIPermission(
+      ExtensionAPIPermission::kUnlimitedStorage));
+  const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
+  EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()->
+      IsStorageUnlimited(origin1));
+  string16 origin_id =
+      webkit_database::DatabaseUtil::GetOriginIdentifier(origin1);
+
+  // Install app2 from the same origin with unlimited storage.
+  PackAndInstallCrx(data_dir_.AppendASCII("app2"), true);
+  ValidatePrefKeyCount(++pref_count);
+  ASSERT_EQ(2u, service_->extensions()->size());
+  extension = service_->extensions()->at(1);
+  const std::string id2 = extension->id();
+  EXPECT_TRUE(extension->HasAPIPermission(
+      ExtensionAPIPermission::kUnlimitedStorage));
+  EXPECT_TRUE(extension->web_extent().MatchesURL(
+                  extension->GetFullLaunchURL()));
+  const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
+  EXPECT_EQ(origin1, origin2);
+  EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()->
+      IsStorageUnlimited(origin2));
+
+  // Set a cookie for the extension.
+  net::CookieMonster* cookie_monster =
+      profile_->GetRequestContext()->GetURLRequestContext()->
+      cookie_store()->GetCookieMonster();
+  ASSERT_TRUE(cookie_monster);
+  net::CookieOptions options;
+  cookie_monster->SetCookieWithOptionsAsync(
+       origin1, "dummy=value", options,
+       base::Bind(&ExtensionCookieCallback::SetCookieCallback,
+                  base::Unretained(&callback)));
+  loop_.RunAllPending();
+  EXPECT_TRUE(callback.result_);
+
+  cookie_monster->GetAllCookiesForURLAsync(
+      origin1,
+      base::Bind(&ExtensionCookieCallback::GetAllCookiesCallback,
+                 base::Unretained(&callback)));
+  loop_.RunAllPending();
+  EXPECT_EQ(1U, callback.list_.size());
+
+  // Open a database.
+  webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
+  string16 db_name = UTF8ToUTF16("db");
+  string16 description = UTF8ToUTF16("db_description");
+  int64 size;
+  db_tracker->DatabaseOpened(origin_id, db_name, description, 1, &size);
+  db_tracker->DatabaseClosed(origin_id, db_name);
+  std::vector<webkit_database::OriginInfo> origins;
+  db_tracker->GetAllOriginsInfo(&origins);
+  EXPECT_EQ(1U, origins.size());
+  EXPECT_EQ(origin_id, origins[0].GetOrigin());
+
+  // Create local storage. We only simulate this by creating the backing file
+  // since webkit is not initialized.
+  DOMStorageContext* context =
+      profile_->GetWebKitContext()->dom_storage_context();
+  FilePath lso_path = context->GetLocalStorageFilePath(origin_id);
+  EXPECT_TRUE(file_util::CreateDirectory(lso_path.DirName()));
+  EXPECT_EQ(0, file_util::WriteFile(lso_path, NULL, 0));
+  EXPECT_TRUE(file_util::PathExists(lso_path));
+
+  // Create indexed db. Similarly, it is enough to only simulate this by
+  // creating the directory on the disk.
+  IndexedDBContext* idb_context =
+      profile_->GetWebKitContext()->indexed_db_context();
+  FilePath idb_path = idb_context->GetIndexedDBFilePath(origin_id);
+  EXPECT_TRUE(file_util::CreateDirectory(idb_path));
+  EXPECT_TRUE(file_util::DirectoryExists(idb_path));
+
+  // Uninstall one of them, unlimited storage should still be granted
+  // to the origin.
+  UninstallExtension(id1, false);
+  EXPECT_EQ(1u, service_->extensions()->size());
+  EXPECT_TRUE(profile_->GetExtensionSpecialStoragePolicy()->
+      IsStorageUnlimited(origin1));
+
+  // Check that the cookie is still there.
+  cookie_monster->GetAllCookiesForURLAsync(
+       origin1,
+       base::Bind(&ExtensionCookieCallback::GetAllCookiesCallback,
+                  base::Unretained(&callback)));
+  loop_.RunAllPending();
+  EXPECT_EQ(1U, callback.list_.size());
+
+  // Now uninstall the other. Storage should be cleared for the apps.
+  UninstallExtension(id2, false);
+  EXPECT_EQ(0u, service_->extensions()->size());
+  EXPECT_FALSE(profile_->GetExtensionSpecialStoragePolicy()->
+      IsStorageUnlimited(origin1));
+
+  // Check that the cookie is gone.
+  cookie_monster->GetAllCookiesForURLAsync(
+       origin1,
+       base::Bind(&ExtensionCookieCallback::GetAllCookiesCallback,
+                  base::Unretained(&callback)));
+  loop_.RunAllPending();
+  EXPECT_EQ(0U, callback.list_.size());
+
+  // The database should have vanished as well.
+  origins.clear();
+  db_tracker->GetAllOriginsInfo(&origins);
+  EXPECT_EQ(0U, origins.size());
+
+  // Check that the LSO file has been removed.
+  EXPECT_FALSE(file_util::PathExists(lso_path));
+
+  // Check if the indexed db has disappeared too.
+  EXPECT_FALSE(file_util::DirectoryExists(idb_path));
+}
+
 // Tests loading single extensions (like --load-extension)
 TEST_F(ExtensionServiceTest, LoadExtension) {
   InitializeEmptyExtensionService();