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