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