Home | History | Annotate | Download | only in database
      1 // Copyright (c) 2012 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 
      5 #include "base/file_util.h"
      6 #include "base/files/file_path.h"
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/platform_file.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/time/time.h"
     14 #include "net/base/net_errors.h"
     15 #include "net/base/test_completion_callback.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 #include "third_party/sqlite/sqlite3.h"
     18 #include "webkit/browser/database/database_tracker.h"
     19 #include "webkit/browser/quota/mock_special_storage_policy.h"
     20 #include "webkit/browser/quota/quota_manager.h"
     21 #include "webkit/common/database/database_identifier.h"
     22 
     23 namespace {
     24 
     25 const char kOrigin1Url[] = "http://origin1";
     26 const char kOrigin2Url[] = "http://protected_origin2";
     27 
     28 class TestObserver : public webkit_database::DatabaseTracker::Observer {
     29  public:
     30   TestObserver()
     31       : new_notification_received_(false),
     32         observe_size_changes_(true),
     33         observe_scheduled_deletions_(true) {
     34   }
     35   TestObserver(bool observe_size_changes, bool observe_scheduled_deletions)
     36       : new_notification_received_(false),
     37         observe_size_changes_(observe_size_changes),
     38         observe_scheduled_deletions_(observe_scheduled_deletions) {
     39   }
     40 
     41   virtual ~TestObserver() {}
     42   virtual void OnDatabaseSizeChanged(const std::string& origin_identifier,
     43                                      const base::string16& database_name,
     44                                      int64 database_size) OVERRIDE {
     45     if (!observe_size_changes_)
     46       return;
     47     new_notification_received_ = true;
     48     origin_identifier_ = origin_identifier;
     49     database_name_ = database_name;
     50     database_size_ = database_size;
     51   }
     52   virtual void OnDatabaseScheduledForDeletion(
     53       const std::string& origin_identifier,
     54       const base::string16& database_name) OVERRIDE {
     55     if (!observe_scheduled_deletions_)
     56       return;
     57     new_notification_received_ = true;
     58     origin_identifier_ = origin_identifier;
     59     database_name_ = database_name;
     60   }
     61   bool DidReceiveNewNotification() {
     62     bool temp_new_notification_received = new_notification_received_;
     63     new_notification_received_ = false;
     64     return temp_new_notification_received;
     65   }
     66   std::string GetNotificationOriginIdentifier() {
     67     return origin_identifier_;
     68   }
     69   base::string16 GetNotificationDatabaseName() { return database_name_; }
     70   int64 GetNotificationDatabaseSize() { return database_size_; }
     71 
     72  private:
     73   bool new_notification_received_;
     74   bool observe_size_changes_;
     75   bool observe_scheduled_deletions_;
     76   std::string origin_identifier_;
     77   base::string16 database_name_;
     78   int64 database_size_;
     79 };
     80 
     81 void CheckNotificationReceived(TestObserver* observer,
     82                                const std::string& expected_origin_identifier,
     83                                const base::string16& expected_database_name,
     84                                int64 expected_database_size) {
     85   EXPECT_TRUE(observer->DidReceiveNewNotification());
     86   EXPECT_EQ(expected_origin_identifier,
     87             observer->GetNotificationOriginIdentifier());
     88   EXPECT_EQ(expected_database_name,
     89             observer->GetNotificationDatabaseName());
     90   EXPECT_EQ(expected_database_size,
     91             observer->GetNotificationDatabaseSize());
     92 }
     93 
     94 class TestQuotaManagerProxy : public quota::QuotaManagerProxy {
     95  public:
     96   TestQuotaManagerProxy()
     97       : QuotaManagerProxy(NULL, NULL),
     98         registered_client_(NULL) {
     99   }
    100 
    101   virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {
    102     EXPECT_FALSE(registered_client_);
    103     registered_client_ = client;
    104   }
    105 
    106   virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
    107                                      const GURL& origin,
    108                                      quota::StorageType type) OVERRIDE {
    109     EXPECT_EQ(quota::QuotaClient::kDatabase, client_id);
    110     EXPECT_EQ(quota::kStorageTypeTemporary, type);
    111     accesses_[origin] += 1;
    112   }
    113 
    114   virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
    115                                      const GURL& origin,
    116                                      quota::StorageType type,
    117                                      int64 delta) OVERRIDE {
    118     EXPECT_EQ(quota::QuotaClient::kDatabase, client_id);
    119     EXPECT_EQ(quota::kStorageTypeTemporary, type);
    120     modifications_[origin].first += 1;
    121     modifications_[origin].second += delta;
    122   }
    123 
    124   // Not needed for our tests.
    125   virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
    126   virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
    127 
    128   void SimulateQuotaManagerDestroyed() {
    129     if (registered_client_) {
    130       registered_client_->OnQuotaManagerDestroyed();
    131       registered_client_ = NULL;
    132     }
    133   }
    134 
    135   bool WasAccessNotified(const GURL& origin) {
    136     return accesses_[origin] != 0;
    137   }
    138 
    139   bool WasModificationNotified(const GURL& origin, int64 amount) {
    140     return modifications_[origin].first != 0 &&
    141            modifications_[origin].second == amount;
    142   }
    143 
    144   void reset() {
    145     accesses_.clear();
    146     modifications_.clear();
    147   }
    148 
    149   quota::QuotaClient* registered_client_;
    150 
    151   // Map from origin to count of access notifications.
    152   std::map<GURL, int> accesses_;
    153 
    154   // Map from origin to <count, sum of deltas>
    155   std::map<GURL, std::pair<int, int64> > modifications_;
    156 
    157  protected:
    158   virtual ~TestQuotaManagerProxy() {
    159     EXPECT_FALSE(registered_client_);
    160   }
    161 };
    162 
    163 
    164 bool EnsureFileOfSize(const base::FilePath& file_path, int64 length) {
    165   base::PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
    166   base::PlatformFile file =
    167       base::CreatePlatformFile(
    168           file_path,
    169           base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE,
    170           NULL,
    171           &error_code);
    172   if (error_code != base::PLATFORM_FILE_OK)
    173     return false;
    174   if (!base::TruncatePlatformFile(file, length))
    175     error_code = base::PLATFORM_FILE_ERROR_FAILED;
    176   base::ClosePlatformFile(file);
    177   return error_code == base::PLATFORM_FILE_OK;
    178 }
    179 
    180 }  // namespace
    181 
    182 namespace webkit_database {
    183 
    184 // We declare a helper class, and make it a friend of DatabaseTracker using
    185 // the FRIEND_TEST() macro, and we implement all tests we want to run as
    186 // static methods of this class. Then we make our TEST() targets call these
    187 // static functions. This allows us to run each test in normal mode and
    188 // incognito mode without writing the same code twice.
    189 class DatabaseTracker_TestHelper_Test {
    190  public:
    191   static void TestDeleteOpenDatabase(bool incognito_mode) {
    192     // Initialize the tracker database.
    193     base::ScopedTempDir temp_dir;
    194     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    195     scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
    196         new quota::MockSpecialStoragePolicy;
    197     special_storage_policy->AddProtected(GURL(kOrigin2Url));
    198     scoped_refptr<DatabaseTracker> tracker(
    199         new DatabaseTracker(temp_dir.path(),
    200                             incognito_mode,
    201                             special_storage_policy.get(),
    202                             NULL,
    203                             NULL));
    204 
    205     // Create and open three databases.
    206     int64 database_size = 0;
    207     const std::string kOrigin1 =
    208         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
    209     const std::string kOrigin2 =
    210         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
    211     const base::string16 kDB1 = ASCIIToUTF16("db1");
    212     const base::string16 kDB2 = ASCIIToUTF16("db2");
    213     const base::string16 kDB3 = ASCIIToUTF16("db3");
    214     const base::string16 kDescription = ASCIIToUTF16("database_description");
    215 
    216     tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    217                             &database_size);
    218     tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
    219                             &database_size);
    220     tracker->DatabaseOpened(kOrigin2, kDB3, kDescription, 0,
    221                             &database_size);
    222 
    223     EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
    224         base::FilePath::FromWStringHack(UTF16ToWide(
    225             tracker->GetOriginDirectory(kOrigin1))))));
    226     EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
    227         base::FilePath::FromWStringHack(UTF16ToWide(
    228             tracker->GetOriginDirectory(kOrigin2))))));
    229     EXPECT_EQ(1, file_util::WriteFile(
    230         tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
    231     EXPECT_EQ(2, file_util::WriteFile(
    232         tracker->GetFullDBFilePath(kOrigin2, kDB2), "aa", 2));
    233     EXPECT_EQ(3, file_util::WriteFile(
    234         tracker->GetFullDBFilePath(kOrigin2, kDB3), "aaa", 3));
    235     tracker->DatabaseModified(kOrigin1, kDB1);
    236     tracker->DatabaseModified(kOrigin2, kDB2);
    237     tracker->DatabaseModified(kOrigin2, kDB3);
    238 
    239     // Delete db1. Should also delete origin1.
    240     TestObserver observer;
    241     tracker->AddObserver(&observer);
    242     net::TestCompletionCallback callback;
    243     int result = tracker->DeleteDatabase(kOrigin1, kDB1, callback.callback());
    244     EXPECT_EQ(net::ERR_IO_PENDING, result);
    245     ASSERT_FALSE(callback.have_result());
    246     EXPECT_TRUE(observer.DidReceiveNewNotification());
    247     EXPECT_EQ(kOrigin1, observer.GetNotificationOriginIdentifier());
    248     EXPECT_EQ(kDB1, observer.GetNotificationDatabaseName());
    249     tracker->DatabaseClosed(kOrigin1, kDB1);
    250     result = callback.GetResult(result);
    251     EXPECT_EQ(net::OK, result);
    252     EXPECT_FALSE(base::PathExists(
    253           tracker->DatabaseDirectory().AppendASCII(kOrigin1)));
    254 
    255     // Recreate db1.
    256     tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    257                             &database_size);
    258     EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
    259         base::FilePath::FromWStringHack(UTF16ToWide(
    260             tracker->GetOriginDirectory(kOrigin1))))));
    261     EXPECT_EQ(1, file_util::WriteFile(
    262         tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
    263     tracker->DatabaseModified(kOrigin1, kDB1);
    264 
    265     // Setup file modification times.  db1 and db2 are modified now, db3 three
    266     // days ago.
    267     EXPECT_TRUE(file_util::SetLastModifiedTime(
    268         tracker->GetFullDBFilePath(kOrigin1, kDB1), base::Time::Now()));
    269     EXPECT_TRUE(file_util::SetLastModifiedTime(
    270         tracker->GetFullDBFilePath(kOrigin2, kDB2), base::Time::Now()));
    271     base::Time three_days_ago = base::Time::Now();
    272     three_days_ago -= base::TimeDelta::FromDays(3);
    273     EXPECT_TRUE(file_util::SetLastModifiedTime(
    274         tracker->GetFullDBFilePath(kOrigin2, kDB3), three_days_ago));
    275 
    276     // Delete databases modified since yesterday. db2 is whitelisted.
    277     base::Time yesterday = base::Time::Now();
    278     yesterday -= base::TimeDelta::FromDays(1);
    279     result = tracker->DeleteDataModifiedSince(
    280         yesterday, callback.callback());
    281     EXPECT_EQ(net::ERR_IO_PENDING, result);
    282     ASSERT_FALSE(callback.have_result());
    283     EXPECT_TRUE(observer.DidReceiveNewNotification());
    284     tracker->DatabaseClosed(kOrigin1, kDB1);
    285     tracker->DatabaseClosed(kOrigin2, kDB2);
    286     result = callback.GetResult(result);
    287     EXPECT_EQ(net::OK, result);
    288     EXPECT_FALSE(base::PathExists(
    289         tracker->DatabaseDirectory().AppendASCII(kOrigin1)));
    290     EXPECT_TRUE(
    291         base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
    292     EXPECT_TRUE(
    293         base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB3)));
    294 
    295     tracker->DatabaseClosed(kOrigin2, kDB3);
    296     tracker->RemoveObserver(&observer);
    297   }
    298 
    299   static void TestDatabaseTracker(bool incognito_mode) {
    300     // Initialize the tracker database.
    301     base::ScopedTempDir temp_dir;
    302     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    303     scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
    304         new quota::MockSpecialStoragePolicy;
    305     special_storage_policy->AddProtected(GURL(kOrigin2Url));
    306     scoped_refptr<DatabaseTracker> tracker(
    307         new DatabaseTracker(temp_dir.path(),
    308                             incognito_mode,
    309                             special_storage_policy.get(),
    310                             NULL,
    311                             NULL));
    312 
    313     // Add two observers.
    314     TestObserver observer1;
    315     TestObserver observer2;
    316     tracker->AddObserver(&observer1);
    317     tracker->AddObserver(&observer2);
    318 
    319     // Open three new databases.
    320     int64 database_size = 0;
    321     const std::string kOrigin1 =
    322         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
    323     const std::string kOrigin2 =
    324         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
    325     const base::string16 kDB1 = ASCIIToUTF16("db1");
    326     const base::string16 kDB2 = ASCIIToUTF16("db2");
    327     const base::string16 kDB3 = ASCIIToUTF16("db3");
    328     const base::string16 kDescription = ASCIIToUTF16("database_description");
    329 
    330     // Get the info for kOrigin1 and kOrigin2
    331     DatabaseTracker::CachedOriginInfo* origin1_info =
    332         tracker->GetCachedOriginInfo(kOrigin1);
    333     DatabaseTracker::CachedOriginInfo* origin2_info =
    334         tracker->GetCachedOriginInfo(kOrigin1);
    335     EXPECT_TRUE(origin1_info);
    336     EXPECT_TRUE(origin2_info);
    337 
    338 
    339     tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    340                             &database_size);
    341     EXPECT_EQ(0, database_size);
    342     tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
    343                             &database_size);
    344     EXPECT_EQ(0, database_size);
    345     tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
    346                             &database_size);
    347     EXPECT_EQ(0, database_size);
    348 
    349     // Write some data to each file and check that the listeners are
    350     // called with the appropriate values.
    351     EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
    352         base::FilePath::FromWStringHack(UTF16ToWide(
    353             tracker->GetOriginDirectory(kOrigin1))))));
    354     EXPECT_TRUE(file_util::CreateDirectory(tracker->DatabaseDirectory().Append(
    355         base::FilePath::FromWStringHack(UTF16ToWide(
    356             tracker->GetOriginDirectory(kOrigin2))))));
    357     EXPECT_EQ(1, file_util::WriteFile(
    358         tracker->GetFullDBFilePath(kOrigin1, kDB1), "a", 1));
    359     EXPECT_EQ(2, file_util::WriteFile(
    360         tracker->GetFullDBFilePath(kOrigin2, kDB2), "aa", 2));
    361     EXPECT_EQ(4, file_util::WriteFile(
    362         tracker->GetFullDBFilePath(kOrigin1, kDB3), "aaaa", 4));
    363     tracker->DatabaseModified(kOrigin1, kDB1);
    364     CheckNotificationReceived(&observer1, kOrigin1, kDB1, 1);
    365     CheckNotificationReceived(&observer2, kOrigin1, kDB1, 1);
    366     tracker->DatabaseModified(kOrigin2, kDB2);
    367     CheckNotificationReceived(&observer1, kOrigin2, kDB2, 2);
    368     CheckNotificationReceived(&observer2, kOrigin2, kDB2, 2);
    369     tracker->DatabaseModified(kOrigin1, kDB3);
    370     CheckNotificationReceived(&observer1, kOrigin1, kDB3, 4);
    371     CheckNotificationReceived(&observer2, kOrigin1, kDB3, 4);
    372 
    373     // Close all databases
    374     tracker->DatabaseClosed(kOrigin1, kDB1);
    375     tracker->DatabaseClosed(kOrigin2, kDB2);
    376     tracker->DatabaseClosed(kOrigin1, kDB3);
    377 
    378     // Open an existing database and check the reported size
    379     tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    380                             &database_size);
    381     EXPECT_EQ(1, database_size);
    382     tracker->DatabaseClosed(kOrigin1, kDB1);
    383 
    384     // Remove an observer; this should clear all caches.
    385     tracker->RemoveObserver(&observer2);
    386 
    387     // Close the tracker database and clear all caches.
    388     // Then make sure that DatabaseOpened() still returns the correct result.
    389     tracker->CloseTrackerDatabaseAndClearCaches();
    390     tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    391                             &database_size);
    392     EXPECT_EQ(1, database_size);
    393     tracker->DatabaseClosed(kOrigin1, kDB1);
    394 
    395     // Remove all observers.
    396     tracker->RemoveObserver(&observer1);
    397 
    398     // Trying to delete a database in use should fail
    399     tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
    400                             &database_size);
    401     EXPECT_FALSE(tracker->DeleteClosedDatabase(kOrigin1, kDB3));
    402     origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
    403     EXPECT_TRUE(origin1_info);
    404     EXPECT_EQ(4, origin1_info->GetDatabaseSize(kDB3));
    405     tracker->DatabaseClosed(kOrigin1, kDB3);
    406 
    407     // Delete a database and make sure the space used by that origin is updated
    408     EXPECT_TRUE(tracker->DeleteClosedDatabase(kOrigin1, kDB3));
    409     origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
    410     EXPECT_TRUE(origin1_info);
    411     EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1));
    412     EXPECT_EQ(0, origin1_info->GetDatabaseSize(kDB3));
    413 
    414     // Get all data for all origins
    415     std::vector<OriginInfo> origins_info;
    416     EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
    417     EXPECT_EQ(size_t(2), origins_info.size());
    418     EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier());
    419     EXPECT_EQ(1, origins_info[0].TotalSize());
    420     EXPECT_EQ(1, origins_info[0].GetDatabaseSize(kDB1));
    421     EXPECT_EQ(0, origins_info[0].GetDatabaseSize(kDB3));
    422 
    423     EXPECT_EQ(kOrigin2, origins_info[1].GetOriginIdentifier());
    424     EXPECT_EQ(2, origins_info[1].TotalSize());
    425 
    426     // Trying to delete an origin with databases in use should fail
    427     tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    428                             &database_size);
    429     EXPECT_FALSE(tracker->DeleteOrigin(kOrigin1, false));
    430     origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
    431     EXPECT_TRUE(origin1_info);
    432     EXPECT_EQ(1, origin1_info->GetDatabaseSize(kDB1));
    433     tracker->DatabaseClosed(kOrigin1, kDB1);
    434 
    435     // Delete an origin that doesn't have any database in use
    436     EXPECT_TRUE(tracker->DeleteOrigin(kOrigin1, false));
    437     origins_info.clear();
    438     EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
    439     EXPECT_EQ(size_t(1), origins_info.size());
    440     EXPECT_EQ(kOrigin2, origins_info[0].GetOriginIdentifier());
    441 
    442     origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
    443     EXPECT_TRUE(origin1_info);
    444     EXPECT_EQ(0, origin1_info->TotalSize());
    445   }
    446 
    447   static void DatabaseTrackerQuotaIntegration() {
    448     const GURL kOrigin(kOrigin1Url);
    449     const std::string kOriginId =
    450         webkit_database::GetIdentifierFromOrigin(kOrigin);
    451     const base::string16 kName = ASCIIToUTF16("name");
    452     const base::string16 kDescription = ASCIIToUTF16("description");
    453 
    454     base::ScopedTempDir temp_dir;
    455     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    456 
    457     // Initialize the tracker with a QuotaManagerProxy
    458     scoped_refptr<TestQuotaManagerProxy> test_quota_proxy(
    459         new TestQuotaManagerProxy);
    460     scoped_refptr<DatabaseTracker> tracker(
    461         new DatabaseTracker(temp_dir.path(),
    462                             false /* incognito */,
    463                             NULL,
    464                             test_quota_proxy.get(),
    465                             NULL));
    466     EXPECT_TRUE(test_quota_proxy->registered_client_);
    467 
    468     // Create a database and modify it a couple of times, close it,
    469     // then delete it. Observe the tracker notifies accordingly.
    470 
    471     int64 database_size = 0;
    472     tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
    473                             &database_size);
    474     EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
    475     test_quota_proxy->reset();
    476 
    477     base::FilePath db_file(tracker->GetFullDBFilePath(kOriginId, kName));
    478     EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    479     EXPECT_TRUE(EnsureFileOfSize(db_file, 10));
    480     tracker->DatabaseModified(kOriginId, kName);
    481     EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 10));
    482     test_quota_proxy->reset();
    483 
    484     EXPECT_TRUE(EnsureFileOfSize(db_file, 100));
    485     tracker->DatabaseModified(kOriginId, kName);
    486     EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 90));
    487     test_quota_proxy->reset();
    488 
    489     tracker->DatabaseClosed(kOriginId, kName);
    490     EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
    491     EXPECT_EQ(net::OK, tracker->DeleteDatabase(
    492         kOriginId, kName, net::CompletionCallback()));
    493     EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
    494     test_quota_proxy->reset();
    495 
    496     // Create a database and modify it, try to delete it while open,
    497     // then close it (at which time deletion will actually occur).
    498     // Observe the tracker notifies accordingly.
    499 
    500     tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
    501                             &database_size);
    502     EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
    503     test_quota_proxy->reset();
    504 
    505     db_file = tracker->GetFullDBFilePath(kOriginId, kName);
    506     EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    507     EXPECT_TRUE(EnsureFileOfSize(db_file, 100));
    508     tracker->DatabaseModified(kOriginId, kName);
    509     EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100));
    510     test_quota_proxy->reset();
    511 
    512     EXPECT_EQ(net::ERR_IO_PENDING,
    513               tracker->DeleteDatabase(kOriginId, kName,
    514                                       net::CompletionCallback()));
    515     EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
    516 
    517     tracker->DatabaseClosed(kOriginId, kName);
    518     EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
    519     EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
    520     test_quota_proxy->reset();
    521 
    522     // Create a database and up the file size without telling
    523     // the tracker about the modification, than simulate a
    524     // a renderer crash.
    525     // Observe the tracker notifies accordingly.
    526 
    527     tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
    528                             &database_size);
    529     EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
    530     test_quota_proxy->reset();
    531     db_file = tracker->GetFullDBFilePath(kOriginId, kName);
    532     EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    533     EXPECT_TRUE(EnsureFileOfSize(db_file, 100));
    534     DatabaseConnections crashed_renderer_connections;
    535     crashed_renderer_connections.AddConnection(kOriginId, kName);
    536     EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, 100));
    537     tracker->CloseDatabases(crashed_renderer_connections);
    538     EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100));
    539 
    540     // Cleanup.
    541     crashed_renderer_connections.RemoveAllConnections();
    542     test_quota_proxy->SimulateQuotaManagerDestroyed();
    543   }
    544 
    545   static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() {
    546     int64 database_size = 0;
    547     const std::string kOrigin1 =
    548         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
    549     const std::string kOrigin2 =
    550         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
    551     const base::string16 kDB1 = ASCIIToUTF16("db1");
    552     const base::string16 kDB2 = ASCIIToUTF16("db2");
    553     const base::string16 kDescription = ASCIIToUTF16("database_description");
    554 
    555     // Initialize the tracker database.
    556     base::MessageLoop message_loop;
    557     base::ScopedTempDir temp_dir;
    558     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    559     base::FilePath origin1_db_dir;
    560     base::FilePath origin2_db_dir;
    561     {
    562       scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
    563           new quota::MockSpecialStoragePolicy;
    564       special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
    565       scoped_refptr<DatabaseTracker> tracker(
    566           new DatabaseTracker(temp_dir.path(),
    567                               false,
    568                               special_storage_policy.get(),
    569                               NULL,
    570                               base::MessageLoopProxy::current().get()));
    571 
    572       // Open two new databases.
    573       tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    574                               &database_size);
    575       EXPECT_EQ(0, database_size);
    576       tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
    577                               &database_size);
    578       EXPECT_EQ(0, database_size);
    579 
    580       // Write some data to each file.
    581       base::FilePath db_file;
    582       db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1);
    583       EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    584       EXPECT_TRUE(EnsureFileOfSize(db_file, 1));
    585 
    586       db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
    587       EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    588       EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
    589 
    590       // Store the origin database directories as long as they still exist.
    591       origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName();
    592       origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName();
    593 
    594       tracker->DatabaseModified(kOrigin1, kDB1);
    595       tracker->DatabaseModified(kOrigin2, kDB2);
    596 
    597       // Close all databases.
    598       tracker->DatabaseClosed(kOrigin1, kDB1);
    599       tracker->DatabaseClosed(kOrigin2, kDB2);
    600 
    601       tracker->Shutdown();
    602     }
    603 
    604     // At this point, the database tracker should be gone. Create a new one.
    605     scoped_refptr<DatabaseTracker> tracker(
    606         new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL));
    607 
    608     // Get all data for all origins.
    609     std::vector<OriginInfo> origins_info;
    610     EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
    611     // kOrigin1 was not session-only, so it survived. kOrigin2 was session-only
    612     // and it got deleted.
    613     EXPECT_EQ(size_t(1), origins_info.size());
    614     EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier());
    615     EXPECT_TRUE(
    616         base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
    617     EXPECT_EQ(base::FilePath(), tracker->GetFullDBFilePath(kOrigin2, kDB2));
    618 
    619     // The origin directory of kOrigin1 remains, but the origin directory of
    620     // kOrigin2 is deleted.
    621     EXPECT_TRUE(base::PathExists(origin1_db_dir));
    622     EXPECT_FALSE(base::PathExists(origin2_db_dir));
    623   }
    624 
    625   static void DatabaseTrackerSetForceKeepSessionState() {
    626     int64 database_size = 0;
    627     const std::string kOrigin1 =
    628         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
    629     const std::string kOrigin2 =
    630         webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
    631     const base::string16 kDB1 = ASCIIToUTF16("db1");
    632     const base::string16 kDB2 = ASCIIToUTF16("db2");
    633     const base::string16 kDescription = ASCIIToUTF16("database_description");
    634 
    635     // Initialize the tracker database.
    636     base::MessageLoop message_loop;
    637     base::ScopedTempDir temp_dir;
    638     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    639     base::FilePath origin1_db_dir;
    640     base::FilePath origin2_db_dir;
    641     {
    642       scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
    643           new quota::MockSpecialStoragePolicy;
    644       special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
    645       scoped_refptr<DatabaseTracker> tracker(
    646           new DatabaseTracker(temp_dir.path(),
    647                               false,
    648                               special_storage_policy.get(),
    649                               NULL,
    650                               base::MessageLoopProxy::current().get()));
    651       tracker->SetForceKeepSessionState();
    652 
    653       // Open two new databases.
    654       tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
    655                               &database_size);
    656       EXPECT_EQ(0, database_size);
    657       tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
    658                               &database_size);
    659       EXPECT_EQ(0, database_size);
    660 
    661       // Write some data to each file.
    662       base::FilePath db_file;
    663       db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1);
    664       EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    665       EXPECT_TRUE(EnsureFileOfSize(db_file, 1));
    666 
    667       db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
    668       EXPECT_TRUE(file_util::CreateDirectory(db_file.DirName()));
    669       EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
    670 
    671       // Store the origin database directories as long as they still exist.
    672       origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName();
    673       origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName();
    674 
    675       tracker->DatabaseModified(kOrigin1, kDB1);
    676       tracker->DatabaseModified(kOrigin2, kDB2);
    677 
    678       // Close all databases.
    679       tracker->DatabaseClosed(kOrigin1, kDB1);
    680       tracker->DatabaseClosed(kOrigin2, kDB2);
    681 
    682       tracker->Shutdown();
    683     }
    684 
    685     // At this point, the database tracker should be gone. Create a new one.
    686     scoped_refptr<DatabaseTracker> tracker(
    687         new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL));
    688 
    689     // Get all data for all origins.
    690     std::vector<OriginInfo> origins_info;
    691     EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info));
    692     // No origins were deleted.
    693     EXPECT_EQ(size_t(2), origins_info.size());
    694     EXPECT_TRUE(
    695         base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
    696     EXPECT_TRUE(
    697         base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
    698 
    699     EXPECT_TRUE(base::PathExists(origin1_db_dir));
    700     EXPECT_TRUE(base::PathExists(origin2_db_dir));
    701   }
    702 
    703   static void EmptyDatabaseNameIsValid() {
    704     const GURL kOrigin(kOrigin1Url);
    705     const std::string kOriginId =
    706         webkit_database::GetIdentifierFromOrigin(kOrigin);
    707     const base::string16 kEmptyName;
    708     const base::string16 kDescription(ASCIIToUTF16("description"));
    709     const base::string16 kChangedDescription(
    710         ASCIIToUTF16("changed_description"));
    711 
    712     // Initialize a tracker database, no need to put it on disk.
    713     const bool kUseInMemoryTrackerDatabase = true;
    714     base::ScopedTempDir temp_dir;
    715     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    716     scoped_refptr<DatabaseTracker> tracker(
    717         new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase,
    718                             NULL, NULL, NULL));
    719 
    720     // Starts off with no databases.
    721     std::vector<OriginInfo> infos;
    722     EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
    723     EXPECT_TRUE(infos.empty());
    724 
    725     // Create a db with an empty name.
    726     int64 database_size = -1;
    727     tracker->DatabaseOpened(kOriginId, kEmptyName, kDescription, 0,
    728                             &database_size);
    729     EXPECT_EQ(0, database_size);
    730     tracker->DatabaseModified(kOriginId, kEmptyName);
    731     EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
    732     EXPECT_EQ(1u, infos.size());
    733     EXPECT_EQ(kDescription, infos[0].GetDatabaseDescription(kEmptyName));
    734     EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kEmptyName).empty());
    735     tracker->DatabaseOpened(kOriginId, kEmptyName, kChangedDescription, 0,
    736                             &database_size);
    737     infos.clear();
    738     EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
    739     EXPECT_EQ(1u, infos.size());
    740     EXPECT_EQ(kChangedDescription, infos[0].GetDatabaseDescription(kEmptyName));
    741     tracker->DatabaseClosed(kOriginId, kEmptyName);
    742     tracker->DatabaseClosed(kOriginId, kEmptyName);
    743 
    744     // Deleting it should return to the initial state.
    745     EXPECT_EQ(net::OK, tracker->DeleteDatabase(kOriginId, kEmptyName,
    746                                                net::CompletionCallback()));
    747     infos.clear();
    748     EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
    749     EXPECT_TRUE(infos.empty());
    750   }
    751 
    752   static void HandleSqliteError() {
    753     const GURL kOrigin(kOrigin1Url);
    754     const std::string kOriginId =
    755         webkit_database::GetIdentifierFromOrigin(kOrigin);
    756     const base::string16 kName(ASCIIToUTF16("name"));
    757     const base::string16 kDescription(ASCIIToUTF16("description"));
    758 
    759     // Initialize a tracker database, no need to put it on disk.
    760     const bool kUseInMemoryTrackerDatabase = true;
    761     base::ScopedTempDir temp_dir;
    762     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    763     scoped_refptr<DatabaseTracker> tracker(
    764         new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase,
    765                             NULL, NULL, NULL));
    766 
    767     // Setup to observe OnScheduledForDelete notifications.
    768     TestObserver observer(false, true);
    769     tracker->AddObserver(&observer);
    770 
    771     // Verify does no harm when there is no such database.
    772     tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
    773     EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
    774     EXPECT_FALSE(observer.DidReceiveNewNotification());
    775 
    776     // --------------------------------------------------------
    777     // Create a record of a database in the tracker db and create
    778     // a spoof_db_file on disk in the expected location.
    779     int64 database_size = 0;
    780     tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
    781                             &database_size);
    782     base::FilePath spoof_db_file = tracker->GetFullDBFilePath(kOriginId, kName);
    783     EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
    784     EXPECT_TRUE(file_util::CreateDirectory(spoof_db_file.DirName()));
    785     EXPECT_TRUE(EnsureFileOfSize(spoof_db_file, 1));
    786 
    787     // Verify does no harm with a non-error is reported.
    788     tracker->HandleSqliteError(kOriginId, kName, SQLITE_OK);
    789     EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
    790     EXPECT_FALSE(observer.DidReceiveNewNotification());
    791 
    792     // Verify that with a connection open, the db is scheduled for deletion,
    793     // but that the file still exists.
    794     tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
    795     EXPECT_TRUE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
    796     EXPECT_TRUE(observer.DidReceiveNewNotification());
    797     EXPECT_TRUE(base::PathExists(spoof_db_file));
    798 
    799     // Verify that once closed, the file is deleted and the record in the
    800     // tracker db is removed.
    801     tracker->DatabaseClosed(kOriginId, kName);
    802     EXPECT_FALSE(base::PathExists(spoof_db_file));
    803     EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
    804 
    805     // --------------------------------------------------------
    806     // Create another record of a database in the tracker db and create
    807     // a spoof_db_file on disk in the expected location.
    808     tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
    809                             &database_size);
    810     base::FilePath spoof_db_file2 = tracker->GetFullDBFilePath(kOriginId, kName);
    811     EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
    812     EXPECT_NE(spoof_db_file, spoof_db_file2);
    813     EXPECT_TRUE(file_util::CreateDirectory(spoof_db_file2.DirName()));
    814     EXPECT_TRUE(EnsureFileOfSize(spoof_db_file2, 1));
    815 
    816     // Verify that with no connection open, the db is deleted immediately.
    817     tracker->DatabaseClosed(kOriginId, kName);
    818     tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT);
    819     EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName));
    820     EXPECT_FALSE(observer.DidReceiveNewNotification());
    821     EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty());
    822     EXPECT_FALSE(base::PathExists(spoof_db_file2));
    823 
    824     tracker->RemoveObserver(&observer);
    825   }
    826 };
    827 
    828 TEST(DatabaseTrackerTest, DeleteOpenDatabase) {
    829   DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false);
    830 }
    831 
    832 TEST(DatabaseTrackerTest, DeleteOpenDatabaseIncognitoMode) {
    833   DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true);
    834 }
    835 
    836 TEST(DatabaseTrackerTest, DatabaseTracker) {
    837   DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false);
    838 }
    839 
    840 TEST(DatabaseTrackerTest, DatabaseTrackerIncognitoMode) {
    841   DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true);
    842 }
    843 
    844 TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) {
    845   // There is no difference in behavior between incognito and not.
    846   DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration();
    847 }
    848 
    849 TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) {
    850   // Only works for regular mode.
    851   DatabaseTracker_TestHelper_Test::
    852       DatabaseTrackerClearSessionOnlyDatabasesOnExit();
    853 }
    854 
    855 TEST(DatabaseTrackerTest, DatabaseTrackerSetForceKeepSessionState) {
    856   // Only works for regular mode.
    857   DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState();
    858 }
    859 
    860 TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) {
    861   DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
    862 }
    863 
    864 TEST(DatabaseTrackerTest, HandleSqliteError) {
    865   DatabaseTracker_TestHelper_Test::HandleSqliteError();
    866 }
    867 
    868 }  // namespace webkit_database
    869