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.
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"
23 using base::ASCIIToUTF16;
27 const char kOrigin1Url[] = "http://origin1";
28 const char kOrigin2Url[] = "http://protected_origin2";
30 class TestObserver : public webkit_database::DatabaseTracker::Observer {
33 : new_notification_received_(false),
34 observe_size_changes_(true),
35 observe_scheduled_deletions_(true) {
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) {
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_)
49 new_notification_received_ = true;
50 origin_identifier_ = origin_identifier;
51 database_name_ = database_name;
52 database_size_ = database_size;
54 virtual void OnDatabaseScheduledForDeletion(
55 const std::string& origin_identifier,
56 const base::string16& database_name) OVERRIDE {
57 if (!observe_scheduled_deletions_)
59 new_notification_received_ = true;
60 origin_identifier_ = origin_identifier;
61 database_name_ = database_name;
63 bool DidReceiveNewNotification() {
64 bool temp_new_notification_received = new_notification_received_;
65 new_notification_received_ = false;
66 return temp_new_notification_received;
68 std::string GetNotificationOriginIdentifier() {
69 return origin_identifier_;
71 base::string16 GetNotificationDatabaseName() { return database_name_; }
72 int64 GetNotificationDatabaseSize() { return database_size_; }
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_;
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());
96 class TestQuotaManagerProxy : public quota::QuotaManagerProxy {
98 TestQuotaManagerProxy()
99 : QuotaManagerProxy(NULL, NULL),
100 registered_client_(NULL) {
103 virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {
104 EXPECT_FALSE(registered_client_);
105 registered_client_ = client;
108 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
110 quota::StorageType type) OVERRIDE {
111 EXPECT_EQ(quota::QuotaClient::kDatabase, client_id);
112 EXPECT_EQ(quota::kStorageTypeTemporary, type);
113 accesses_[origin] += 1;
116 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
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;
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,
131 quota::StorageType type,
132 bool enabled) OVERRIDE {}
133 virtual void GetUsageAndQuota(
134 base::SequencedTaskRunner* original_task_runner,
136 quota::StorageType type,
137 const GetUsageAndQuotaCallback& callback) OVERRIDE {}
139 void SimulateQuotaManagerDestroyed() {
140 if (registered_client_) {
141 registered_client_->OnQuotaManagerDestroyed();
142 registered_client_ = NULL;
146 bool WasAccessNotified(const GURL& origin) {
147 return accesses_[origin] != 0;
150 bool WasModificationNotified(const GURL& origin, int64 amount) {
151 return modifications_[origin].first != 0 &&
152 modifications_[origin].second == amount;
157 modifications_.clear();
160 quota::QuotaClient* registered_client_;
162 // Map from origin to count of access notifications.
163 std::map<GURL, int> accesses_;
165 // Map from origin to <count, sum of deltas>
166 std::map<GURL, std::pair<int, int64> > modifications_;
169 virtual ~TestQuotaManagerProxy() {
170 EXPECT_FALSE(registered_client_);
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(
180 base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_WRITE,
183 if (error_code != base::PLATFORM_FILE_OK)
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;
193 namespace webkit_database {
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 {
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(),
212 special_storage_policy.get(),
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");
227 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
229 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
231 tracker->DatabaseOpened(kOrigin2, kDB3, kDescription, 0,
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);
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)));
267 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
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);
276 // Setup file modification times. db1 and db2 are modified now, db3 three
278 base::Time now = base::Time::Now();
279 EXPECT_TRUE(base::TouchFile(tracker->GetFullDBFilePath(kOrigin1, kDB1),
281 EXPECT_TRUE(base::TouchFile(tracker->GetFullDBFilePath(kOrigin2, kDB2),
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));
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)));
302 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
304 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB3)));
306 tracker->DatabaseClosed(kOrigin2, kDB3);
307 tracker->RemoveObserver(&observer);
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(),
320 special_storage_policy.get(),
324 // Add two observers.
325 TestObserver observer1;
326 TestObserver observer2;
327 tracker->AddObserver(&observer1);
328 tracker->AddObserver(&observer2);
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");
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);
350 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
352 EXPECT_EQ(0, database_size);
353 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
355 EXPECT_EQ(0, database_size);
356 tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
358 EXPECT_EQ(0, database_size);
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);
384 // Close all databases
385 tracker->DatabaseClosed(kOrigin1, kDB1);
386 tracker->DatabaseClosed(kOrigin2, kDB2);
387 tracker->DatabaseClosed(kOrigin1, kDB3);
389 // Open an existing database and check the reported size
390 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
392 EXPECT_EQ(1, database_size);
393 tracker->DatabaseClosed(kOrigin1, kDB1);
395 // Remove an observer; this should clear all caches.
396 tracker->RemoveObserver(&observer2);
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,
403 EXPECT_EQ(1, database_size);
404 tracker->DatabaseClosed(kOrigin1, kDB1);
406 // Remove all observers.
407 tracker->RemoveObserver(&observer1);
409 // Trying to delete a database in use should fail
410 tracker->DatabaseOpened(kOrigin1, kDB3, kDescription, 0,
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);
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));
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));
434 EXPECT_EQ(kOrigin2, origins_info[1].GetOriginIdentifier());
435 EXPECT_EQ(2, origins_info[1].TotalSize());
437 // Trying to delete an origin with databases in use should fail
438 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
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);
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());
453 origin1_info = tracker->GetCachedOriginInfo(kOrigin1);
454 EXPECT_TRUE(origin1_info);
455 EXPECT_EQ(0, origin1_info->TotalSize());
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");
465 base::ScopedTempDir temp_dir;
466 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
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 */,
475 test_quota_proxy.get(),
477 EXPECT_TRUE(test_quota_proxy->registered_client_);
479 // Create a database and modify it a couple of times, close it,
480 // then delete it. Observe the tracker notifies accordingly.
482 int64 database_size = 0;
483 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
485 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
486 test_quota_proxy->reset();
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();
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();
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();
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.
511 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
513 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin));
514 test_quota_proxy->reset();
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();
523 EXPECT_EQ(net::ERR_IO_PENDING,
524 tracker->DeleteDatabase(kOriginId, kName,
525 net::CompletionCallback()));
526 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, -100));
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();
533 // Create a database and up the file size without telling
534 // the tracker about the modification, than simulate a
536 // Observe the tracker notifies accordingly.
538 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0,
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));
552 crashed_renderer_connections.RemoveAllConnections();
553 test_quota_proxy->SimulateQuotaManagerDestroyed();
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");
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;
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(),
579 special_storage_policy.get(),
581 base::MessageLoopProxy::current().get()));
583 // Open two new databases.
584 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
586 EXPECT_EQ(0, database_size);
587 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
589 EXPECT_EQ(0, database_size);
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));
597 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
598 EXPECT_TRUE(base::CreateDirectory(db_file.DirName()));
599 EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
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();
605 tracker->DatabaseModified(kOrigin1, kDB1);
606 tracker->DatabaseModified(kOrigin2, kDB2);
608 // Close all databases.
609 tracker->DatabaseClosed(kOrigin1, kDB1);
610 tracker->DatabaseClosed(kOrigin2, kDB2);
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));
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());
627 base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
628 EXPECT_EQ(base::FilePath(), tracker->GetFullDBFilePath(kOrigin2, kDB2));
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));
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");
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;
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(),
659 special_storage_policy.get(),
661 base::MessageLoopProxy::current().get()));
662 tracker->SetForceKeepSessionState();
664 // Open two new databases.
665 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
667 EXPECT_EQ(0, database_size);
668 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0,
670 EXPECT_EQ(0, database_size);
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));
678 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2);
679 EXPECT_TRUE(base::CreateDirectory(db_file.DirName()));
680 EXPECT_TRUE(EnsureFileOfSize(db_file, 2));
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();
686 tracker->DatabaseModified(kOrigin1, kDB1);
687 tracker->DatabaseModified(kOrigin2, kDB2);
689 // Close all databases.
690 tracker->DatabaseClosed(kOrigin1, kDB1);
691 tracker->DatabaseClosed(kOrigin2, kDB2);
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));
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());
706 base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1)));
708 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2)));
710 EXPECT_TRUE(base::PathExists(origin1_db_dir));
711 EXPECT_TRUE(base::PathExists(origin2_db_dir));
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"));
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,
731 // Starts off with no databases.
732 std::vector<OriginInfo> infos;
733 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
734 EXPECT_TRUE(infos.empty());
736 // Create a db with an empty name.
737 int64 database_size = -1;
738 tracker->DatabaseOpened(kOriginId, kEmptyName, kDescription, 0,
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,
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);
755 // Deleting it should return to the initial state.
756 EXPECT_EQ(net::OK, tracker->DeleteDatabase(kOriginId, kEmptyName,
757 net::CompletionCallback()));
759 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos));
760 EXPECT_TRUE(infos.empty());
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"));
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,
778 // Setup to observe OnScheduledForDelete notifications.
779 TestObserver observer(false, true);
780 tracker->AddObserver(&observer);
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());
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,
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));
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());
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));
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());
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,
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));
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));
835 tracker->RemoveObserver(&observer);
839 TEST(DatabaseTrackerTest, DeleteOpenDatabase) {
840 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false);
843 TEST(DatabaseTrackerTest, DeleteOpenDatabaseIncognitoMode) {
844 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true);
847 TEST(DatabaseTrackerTest, DatabaseTracker) {
848 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false);
851 TEST(DatabaseTrackerTest, DatabaseTrackerIncognitoMode) {
852 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true);
855 TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) {
856 // There is no difference in behavior between incognito and not.
857 DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration();
860 TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) {
861 // Only works for regular mode.
862 DatabaseTracker_TestHelper_Test::
863 DatabaseTrackerClearSessionOnlyDatabasesOnExit();
866 TEST(DatabaseTrackerTest, DatabaseTrackerSetForceKeepSessionState) {
867 // Only works for regular mode.
868 DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState();
871 TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) {
872 DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid();
875 TEST(DatabaseTrackerTest, HandleSqliteError) {
876 DatabaseTracker_TestHelper_Test::HandleSqliteError();
879 } // namespace webkit_database