database_tracker_unittest.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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
23using base::ASCIIToUTF16;
24using webkit_database::DatabaseConnections;
25using webkit_database::DatabaseTracker;
26using webkit_database::OriginInfo;
27
28namespace {
29
30const char kOrigin1Url[] = "http://origin1";
31const char kOrigin2Url[] = "http://protected_origin2";
32
33class 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
86void 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
99class 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
178bool 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
188namespace 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.
195class 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
835TEST(DatabaseTrackerTest, DeleteOpenDatabase) {
836  DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false);
837}
838
839TEST(DatabaseTrackerTest, DeleteOpenDatabaseIncognitoMode) {
840  DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true);
841}
842
843TEST(DatabaseTrackerTest, DatabaseTracker) {
844  DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false);
845}
846
847TEST(DatabaseTrackerTest, DatabaseTrackerIncognitoMode) {
848  DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true);
849}
850
851TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) {
852  // There is no difference in behavior between incognito and not.
853  DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration();
854}
855
856TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) {
857  // Only works for regular mode.
858  DatabaseTracker_TestHelper_Test::
859      DatabaseTrackerClearSessionOnlyDatabasesOnExit();
860}
861
862TEST(DatabaseTrackerTest, DatabaseTrackerSetForceKeepSessionState) {
863  // Only works for regular mode.
864  DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState();
865}
866
867TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) {
868  DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
869}
870
871TEST(DatabaseTrackerTest, HandleSqliteError) {
872  DatabaseTracker_TestHelper_Test::HandleSqliteError();
873}
874
875}  // namespace content
876