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