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/files/file.h" 6 #include "base/files/file_path.h" 7 #include "base/files/file_util.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 "storage/browser/database/database_tracker.h" 18 #include "storage/browser/quota/quota_manager_proxy.h" 19 #include "storage/common/database/database_identifier.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "third_party/sqlite/sqlite3.h" 22 23 using base::ASCIIToUTF16; 24 using storage::DatabaseConnections; 25 using storage::DatabaseTracker; 26 using storage::OriginInfo; 27 28 namespace { 29 30 const char kOrigin1Url[] = "http://origin1"; 31 const char kOrigin2Url[] = "http://protected_origin2"; 32 33 class TestObserver : public storage::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 storage::QuotaManagerProxy { 100 public: 101 TestQuotaManagerProxy() 102 : QuotaManagerProxy(NULL, NULL), 103 registered_client_(NULL) { 104 } 105 106 virtual void RegisterClient(storage::QuotaClient* client) OVERRIDE { 107 EXPECT_FALSE(registered_client_); 108 registered_client_ = client; 109 } 110 111 virtual void NotifyStorageAccessed(storage::QuotaClient::ID client_id, 112 const GURL& origin, 113 storage::StorageType type) OVERRIDE { 114 EXPECT_EQ(storage::QuotaClient::kDatabase, client_id); 115 EXPECT_EQ(storage::kStorageTypeTemporary, type); 116 accesses_[origin] += 1; 117 } 118 119 virtual void NotifyStorageModified(storage::QuotaClient::ID client_id, 120 const GURL& origin, 121 storage::StorageType type, 122 int64 delta) OVERRIDE { 123 EXPECT_EQ(storage::QuotaClient::kDatabase, client_id); 124 EXPECT_EQ(storage::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(storage::QuotaClient::ID client_id, 133 const GURL& origin, 134 storage::StorageType type, 135 bool enabled) OVERRIDE {} 136 virtual void GetUsageAndQuota( 137 base::SequencedTaskRunner* original_task_runner, 138 const GURL& origin, 139 storage::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 storage::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 storage::GetIdentifierFromOrigin(GURL(kOrigin1Url)); 215 const std::string kOrigin2 = 216 storage::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 storage::GetIdentifierFromOrigin(GURL(kOrigin1Url)); 329 const std::string kOrigin2 = 330 storage::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 = storage::GetIdentifierFromOrigin(kOrigin); 456 const base::string16 kName = ASCIIToUTF16("name"); 457 const base::string16 kDescription = ASCIIToUTF16("description"); 458 459 base::ScopedTempDir temp_dir; 460 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 461 462 // Initialize the tracker with a QuotaManagerProxy 463 scoped_refptr<TestQuotaManagerProxy> test_quota_proxy( 464 new TestQuotaManagerProxy); 465 scoped_refptr<DatabaseTracker> tracker( 466 new DatabaseTracker(temp_dir.path(), 467 false /* incognito */, 468 NULL, 469 test_quota_proxy.get(), 470 NULL)); 471 EXPECT_TRUE(test_quota_proxy->registered_client_); 472 473 // Create a database and modify it a couple of times, close it, 474 // then delete it. Observe the tracker notifies accordingly. 475 476 int64 database_size = 0; 477 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, 478 &database_size); 479 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); 480 test_quota_proxy->reset(); 481 482 base::FilePath db_file(tracker->GetFullDBFilePath(kOriginId, kName)); 483 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 484 EXPECT_TRUE(EnsureFileOfSize(db_file, 10)); 485 tracker->DatabaseModified(kOriginId, kName); 486 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 10)); 487 test_quota_proxy->reset(); 488 489 EXPECT_TRUE(EnsureFileOfSize(db_file, 100)); 490 tracker->DatabaseModified(kOriginId, kName); 491 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 90)); 492 test_quota_proxy->reset(); 493 494 tracker->DatabaseClosed(kOriginId, kName); 495 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); 496 EXPECT_EQ(net::OK, tracker->DeleteDatabase( 497 kOriginId, kName, net::CompletionCallback())); 498 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100)); 499 test_quota_proxy->reset(); 500 501 // Create a database and modify it, try to delete it while open, 502 // then close it (at which time deletion will actually occur). 503 // Observe the tracker notifies accordingly. 504 505 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, 506 &database_size); 507 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); 508 test_quota_proxy->reset(); 509 510 db_file = tracker->GetFullDBFilePath(kOriginId, kName); 511 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 512 EXPECT_TRUE(EnsureFileOfSize(db_file, 100)); 513 tracker->DatabaseModified(kOriginId, kName); 514 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100)); 515 test_quota_proxy->reset(); 516 517 EXPECT_EQ(net::ERR_IO_PENDING, 518 tracker->DeleteDatabase(kOriginId, kName, 519 net::CompletionCallback())); 520 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, -100)); 521 522 tracker->DatabaseClosed(kOriginId, kName); 523 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); 524 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, -100)); 525 test_quota_proxy->reset(); 526 527 // Create a database and up the file size without telling 528 // the tracker about the modification, than simulate a 529 // a renderer crash. 530 // Observe the tracker notifies accordingly. 531 532 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, 533 &database_size); 534 EXPECT_TRUE(test_quota_proxy->WasAccessNotified(kOrigin)); 535 test_quota_proxy->reset(); 536 db_file = tracker->GetFullDBFilePath(kOriginId, kName); 537 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 538 EXPECT_TRUE(EnsureFileOfSize(db_file, 100)); 539 DatabaseConnections crashed_renderer_connections; 540 crashed_renderer_connections.AddConnection(kOriginId, kName); 541 EXPECT_FALSE(test_quota_proxy->WasModificationNotified(kOrigin, 100)); 542 tracker->CloseDatabases(crashed_renderer_connections); 543 EXPECT_TRUE(test_quota_proxy->WasModificationNotified(kOrigin, 100)); 544 545 // Cleanup. 546 crashed_renderer_connections.RemoveAllConnections(); 547 test_quota_proxy->SimulateQuotaManagerDestroyed(); 548 } 549 550 static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() { 551 int64 database_size = 0; 552 const std::string kOrigin1 = 553 storage::GetIdentifierFromOrigin(GURL(kOrigin1Url)); 554 const std::string kOrigin2 = 555 storage::GetIdentifierFromOrigin(GURL(kOrigin2Url)); 556 const base::string16 kDB1 = ASCIIToUTF16("db1"); 557 const base::string16 kDB2 = ASCIIToUTF16("db2"); 558 const base::string16 kDescription = ASCIIToUTF16("database_description"); 559 560 // Initialize the tracker database. 561 base::MessageLoop message_loop; 562 base::ScopedTempDir temp_dir; 563 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 564 base::FilePath origin1_db_dir; 565 base::FilePath origin2_db_dir; 566 { 567 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy = 568 new MockSpecialStoragePolicy; 569 special_storage_policy->AddSessionOnly(GURL(kOrigin2Url)); 570 scoped_refptr<DatabaseTracker> tracker( 571 new DatabaseTracker(temp_dir.path(), 572 false, 573 special_storage_policy.get(), 574 NULL, 575 base::MessageLoopProxy::current().get())); 576 577 // Open two new databases. 578 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, 579 &database_size); 580 EXPECT_EQ(0, database_size); 581 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, 582 &database_size); 583 EXPECT_EQ(0, database_size); 584 585 // Write some data to each file. 586 base::FilePath db_file; 587 db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1); 588 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 589 EXPECT_TRUE(EnsureFileOfSize(db_file, 1)); 590 591 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2); 592 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 593 EXPECT_TRUE(EnsureFileOfSize(db_file, 2)); 594 595 // Store the origin database directories as long as they still exist. 596 origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName(); 597 origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName(); 598 599 tracker->DatabaseModified(kOrigin1, kDB1); 600 tracker->DatabaseModified(kOrigin2, kDB2); 601 602 // Close all databases. 603 tracker->DatabaseClosed(kOrigin1, kDB1); 604 tracker->DatabaseClosed(kOrigin2, kDB2); 605 606 tracker->Shutdown(); 607 } 608 609 // At this point, the database tracker should be gone. Create a new one. 610 scoped_refptr<DatabaseTracker> tracker( 611 new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL)); 612 613 // Get all data for all origins. 614 std::vector<OriginInfo> origins_info; 615 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); 616 // kOrigin1 was not session-only, so it survived. kOrigin2 was session-only 617 // and it got deleted. 618 EXPECT_EQ(size_t(1), origins_info.size()); 619 EXPECT_EQ(kOrigin1, origins_info[0].GetOriginIdentifier()); 620 EXPECT_TRUE( 621 base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1))); 622 EXPECT_EQ(base::FilePath(), tracker->GetFullDBFilePath(kOrigin2, kDB2)); 623 624 // The origin directory of kOrigin1 remains, but the origin directory of 625 // kOrigin2 is deleted. 626 EXPECT_TRUE(base::PathExists(origin1_db_dir)); 627 EXPECT_FALSE(base::PathExists(origin2_db_dir)); 628 } 629 630 static void DatabaseTrackerSetForceKeepSessionState() { 631 int64 database_size = 0; 632 const std::string kOrigin1 = 633 storage::GetIdentifierFromOrigin(GURL(kOrigin1Url)); 634 const std::string kOrigin2 = 635 storage::GetIdentifierFromOrigin(GURL(kOrigin2Url)); 636 const base::string16 kDB1 = ASCIIToUTF16("db1"); 637 const base::string16 kDB2 = ASCIIToUTF16("db2"); 638 const base::string16 kDescription = ASCIIToUTF16("database_description"); 639 640 // Initialize the tracker database. 641 base::MessageLoop message_loop; 642 base::ScopedTempDir temp_dir; 643 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 644 base::FilePath origin1_db_dir; 645 base::FilePath origin2_db_dir; 646 { 647 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy = 648 new MockSpecialStoragePolicy; 649 special_storage_policy->AddSessionOnly(GURL(kOrigin2Url)); 650 scoped_refptr<DatabaseTracker> tracker( 651 new DatabaseTracker(temp_dir.path(), 652 false, 653 special_storage_policy.get(), 654 NULL, 655 base::MessageLoopProxy::current().get())); 656 tracker->SetForceKeepSessionState(); 657 658 // Open two new databases. 659 tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0, 660 &database_size); 661 EXPECT_EQ(0, database_size); 662 tracker->DatabaseOpened(kOrigin2, kDB2, kDescription, 0, 663 &database_size); 664 EXPECT_EQ(0, database_size); 665 666 // Write some data to each file. 667 base::FilePath db_file; 668 db_file = tracker->GetFullDBFilePath(kOrigin1, kDB1); 669 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 670 EXPECT_TRUE(EnsureFileOfSize(db_file, 1)); 671 672 db_file = tracker->GetFullDBFilePath(kOrigin2, kDB2); 673 EXPECT_TRUE(base::CreateDirectory(db_file.DirName())); 674 EXPECT_TRUE(EnsureFileOfSize(db_file, 2)); 675 676 // Store the origin database directories as long as they still exist. 677 origin1_db_dir = tracker->GetFullDBFilePath(kOrigin1, kDB1).DirName(); 678 origin2_db_dir = tracker->GetFullDBFilePath(kOrigin2, kDB2).DirName(); 679 680 tracker->DatabaseModified(kOrigin1, kDB1); 681 tracker->DatabaseModified(kOrigin2, kDB2); 682 683 // Close all databases. 684 tracker->DatabaseClosed(kOrigin1, kDB1); 685 tracker->DatabaseClosed(kOrigin2, kDB2); 686 687 tracker->Shutdown(); 688 } 689 690 // At this point, the database tracker should be gone. Create a new one. 691 scoped_refptr<DatabaseTracker> tracker( 692 new DatabaseTracker(temp_dir.path(), false, NULL, NULL, NULL)); 693 694 // Get all data for all origins. 695 std::vector<OriginInfo> origins_info; 696 EXPECT_TRUE(tracker->GetAllOriginsInfo(&origins_info)); 697 // No origins were deleted. 698 EXPECT_EQ(size_t(2), origins_info.size()); 699 EXPECT_TRUE( 700 base::PathExists(tracker->GetFullDBFilePath(kOrigin1, kDB1))); 701 EXPECT_TRUE( 702 base::PathExists(tracker->GetFullDBFilePath(kOrigin2, kDB2))); 703 704 EXPECT_TRUE(base::PathExists(origin1_db_dir)); 705 EXPECT_TRUE(base::PathExists(origin2_db_dir)); 706 } 707 708 static void EmptyDatabaseNameIsValid() { 709 const GURL kOrigin(kOrigin1Url); 710 const std::string kOriginId = storage::GetIdentifierFromOrigin(kOrigin); 711 const base::string16 kEmptyName; 712 const base::string16 kDescription(ASCIIToUTF16("description")); 713 const base::string16 kChangedDescription( 714 ASCIIToUTF16("changed_description")); 715 716 // Initialize a tracker database, no need to put it on disk. 717 const bool kUseInMemoryTrackerDatabase = true; 718 base::ScopedTempDir temp_dir; 719 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 720 scoped_refptr<DatabaseTracker> tracker( 721 new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase, 722 NULL, NULL, NULL)); 723 724 // Starts off with no databases. 725 std::vector<OriginInfo> infos; 726 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); 727 EXPECT_TRUE(infos.empty()); 728 729 // Create a db with an empty name. 730 int64 database_size = -1; 731 tracker->DatabaseOpened(kOriginId, kEmptyName, kDescription, 0, 732 &database_size); 733 EXPECT_EQ(0, database_size); 734 tracker->DatabaseModified(kOriginId, kEmptyName); 735 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); 736 EXPECT_EQ(1u, infos.size()); 737 EXPECT_EQ(kDescription, infos[0].GetDatabaseDescription(kEmptyName)); 738 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kEmptyName).empty()); 739 tracker->DatabaseOpened(kOriginId, kEmptyName, kChangedDescription, 0, 740 &database_size); 741 infos.clear(); 742 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); 743 EXPECT_EQ(1u, infos.size()); 744 EXPECT_EQ(kChangedDescription, infos[0].GetDatabaseDescription(kEmptyName)); 745 tracker->DatabaseClosed(kOriginId, kEmptyName); 746 tracker->DatabaseClosed(kOriginId, kEmptyName); 747 748 // Deleting it should return to the initial state. 749 EXPECT_EQ(net::OK, tracker->DeleteDatabase(kOriginId, kEmptyName, 750 net::CompletionCallback())); 751 infos.clear(); 752 EXPECT_TRUE(tracker->GetAllOriginsInfo(&infos)); 753 EXPECT_TRUE(infos.empty()); 754 } 755 756 static void HandleSqliteError() { 757 const GURL kOrigin(kOrigin1Url); 758 const std::string kOriginId = storage::GetIdentifierFromOrigin(kOrigin); 759 const base::string16 kName(ASCIIToUTF16("name")); 760 const base::string16 kDescription(ASCIIToUTF16("description")); 761 762 // Initialize a tracker database, no need to put it on disk. 763 const bool kUseInMemoryTrackerDatabase = true; 764 base::ScopedTempDir temp_dir; 765 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 766 scoped_refptr<DatabaseTracker> tracker( 767 new DatabaseTracker(temp_dir.path(), kUseInMemoryTrackerDatabase, 768 NULL, NULL, NULL)); 769 770 // Setup to observe OnScheduledForDelete notifications. 771 TestObserver observer(false, true); 772 tracker->AddObserver(&observer); 773 774 // Verify does no harm when there is no such database. 775 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT); 776 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); 777 EXPECT_FALSE(observer.DidReceiveNewNotification()); 778 779 // -------------------------------------------------------- 780 // Create a record of a database in the tracker db and create 781 // a spoof_db_file on disk in the expected location. 782 int64 database_size = 0; 783 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, 784 &database_size); 785 base::FilePath spoof_db_file = tracker->GetFullDBFilePath(kOriginId, kName); 786 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); 787 EXPECT_TRUE(base::CreateDirectory(spoof_db_file.DirName())); 788 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file, 1)); 789 790 // Verify does no harm with a non-error is reported. 791 tracker->HandleSqliteError(kOriginId, kName, SQLITE_OK); 792 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); 793 EXPECT_FALSE(observer.DidReceiveNewNotification()); 794 795 // Verify that with a connection open, the db is scheduled for deletion, 796 // but that the file still exists. 797 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT); 798 EXPECT_TRUE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); 799 EXPECT_TRUE(observer.DidReceiveNewNotification()); 800 EXPECT_TRUE(base::PathExists(spoof_db_file)); 801 802 // Verify that once closed, the file is deleted and the record in the 803 // tracker db is removed. 804 tracker->DatabaseClosed(kOriginId, kName); 805 EXPECT_FALSE(base::PathExists(spoof_db_file)); 806 EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); 807 808 // -------------------------------------------------------- 809 // Create another record of a database in the tracker db and create 810 // a spoof_db_file on disk in the expected location. 811 tracker->DatabaseOpened(kOriginId, kName, kDescription, 0, 812 &database_size); 813 base::FilePath spoof_db_file2 = tracker->GetFullDBFilePath(kOriginId, 814 kName); 815 EXPECT_FALSE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); 816 EXPECT_NE(spoof_db_file, spoof_db_file2); 817 EXPECT_TRUE(base::CreateDirectory(spoof_db_file2.DirName())); 818 EXPECT_TRUE(EnsureFileOfSize(spoof_db_file2, 1)); 819 820 // Verify that with no connection open, the db is deleted immediately. 821 tracker->DatabaseClosed(kOriginId, kName); 822 tracker->HandleSqliteError(kOriginId, kName, SQLITE_CORRUPT); 823 EXPECT_FALSE(tracker->IsDatabaseScheduledForDeletion(kOriginId, kName)); 824 EXPECT_FALSE(observer.DidReceiveNewNotification()); 825 EXPECT_TRUE(tracker->GetFullDBFilePath(kOriginId, kName).empty()); 826 EXPECT_FALSE(base::PathExists(spoof_db_file2)); 827 828 tracker->RemoveObserver(&observer); 829 } 830 }; 831 832 TEST(DatabaseTrackerTest, DeleteOpenDatabase) { 833 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(false); 834 } 835 836 TEST(DatabaseTrackerTest, DeleteOpenDatabaseIncognitoMode) { 837 DatabaseTracker_TestHelper_Test::TestDeleteOpenDatabase(true); 838 } 839 840 TEST(DatabaseTrackerTest, DatabaseTracker) { 841 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(false); 842 } 843 844 TEST(DatabaseTrackerTest, DatabaseTrackerIncognitoMode) { 845 DatabaseTracker_TestHelper_Test::TestDatabaseTracker(true); 846 } 847 848 TEST(DatabaseTrackerTest, DatabaseTrackerQuotaIntegration) { 849 // There is no difference in behavior between incognito and not. 850 DatabaseTracker_TestHelper_Test::DatabaseTrackerQuotaIntegration(); 851 } 852 853 TEST(DatabaseTrackerTest, DatabaseTrackerClearSessionOnlyDatabasesOnExit) { 854 // Only works for regular mode. 855 DatabaseTracker_TestHelper_Test:: 856 DatabaseTrackerClearSessionOnlyDatabasesOnExit(); 857 } 858 859 TEST(DatabaseTrackerTest, DatabaseTrackerSetForceKeepSessionState) { 860 // Only works for regular mode. 861 DatabaseTracker_TestHelper_Test::DatabaseTrackerSetForceKeepSessionState(); 862 } 863 864 TEST(DatabaseTrackerTest, EmptyDatabaseNameIsValid) { 865 DatabaseTracker_TestHelper_Test::EmptyDatabaseNameIsValid(); 866 } 867 868 TEST(DatabaseTrackerTest, HandleSqliteError) { 869 DatabaseTracker_TestHelper_Test::HandleSqliteError(); 870 } 871 872 } // namespace content 873