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