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