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/bind.h" 6#include "base/files/file_util.h" 7#include "base/files/scoped_temp_dir.h" 8#include "base/strings/stringprintf.h" 9#include "content/browser/appcache/appcache_database.h" 10#include "content/browser/appcache/appcache_entry.h" 11#include "sql/connection.h" 12#include "sql/meta_table.h" 13#include "sql/statement.h" 14#include "sql/test/scoped_error_ignorer.h" 15#include "sql/test/test_helpers.h" 16#include "sql/transaction.h" 17#include "testing/gtest/include/gtest/gtest.h" 18#include "third_party/sqlite/sqlite3.h" 19 20namespace { 21 22const base::Time kZeroTime; 23 24} // namespace 25 26namespace content { 27 28class AppCacheDatabaseTest {}; 29 30TEST(AppCacheDatabaseTest, LazyOpen) { 31 // Use an empty file path to use an in-memory sqlite database. 32 const base::FilePath kEmptyPath; 33 AppCacheDatabase db(kEmptyPath); 34 35 EXPECT_FALSE(db.LazyOpen(false)); 36 EXPECT_TRUE(db.LazyOpen(true)); 37 38 int64 group_id, cache_id, response_id, deleteable_response_rowid; 39 group_id = cache_id = response_id = deleteable_response_rowid = 0; 40 EXPECT_TRUE(db.FindLastStorageIds(&group_id, &cache_id, &response_id, 41 &deleteable_response_rowid)); 42 EXPECT_EQ(0, group_id); 43 EXPECT_EQ(0, cache_id); 44 EXPECT_EQ(0, response_id); 45 EXPECT_EQ(0, deleteable_response_rowid); 46 47 std::set<GURL> origins; 48 EXPECT_TRUE(db.FindOriginsWithGroups(&origins)); 49 EXPECT_TRUE(origins.empty()); 50} 51 52TEST(AppCacheDatabaseTest, ReCreate) { 53 // Real files on disk for this test. 54 base::ScopedTempDir temp_dir; 55 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 56 const base::FilePath kDbFile = temp_dir.path().AppendASCII("appcache.db"); 57 const base::FilePath kNestedDir = temp_dir.path().AppendASCII("nested"); 58 const base::FilePath kOtherFile = kNestedDir.AppendASCII("other_file"); 59 EXPECT_TRUE(base::CreateDirectory(kNestedDir)); 60 EXPECT_EQ(3, base::WriteFile(kOtherFile, "foo", 3)); 61 62 AppCacheDatabase db(kDbFile); 63 EXPECT_FALSE(db.LazyOpen(false)); 64 EXPECT_TRUE(db.LazyOpen(true)); 65 66 EXPECT_TRUE(base::PathExists(kDbFile)); 67 EXPECT_TRUE(base::DirectoryExists(kNestedDir)); 68 EXPECT_TRUE(base::PathExists(kOtherFile)); 69 70 EXPECT_TRUE(db.DeleteExistingAndCreateNewDatabase()); 71 72 EXPECT_TRUE(base::PathExists(kDbFile)); 73 EXPECT_FALSE(base::DirectoryExists(kNestedDir)); 74 EXPECT_FALSE(base::PathExists(kOtherFile)); 75} 76 77#ifdef NDEBUG 78// Only run in release builds because sql::Connection and familiy 79// crank up DLOG(FATAL)'ness and this test presents it with 80// intentionally bad data which causes debug builds to exit instead 81// of run to completion. In release builds, errors the are delivered 82// to the consumer so we can test the error handling of the consumer. 83// TODO: crbug/328576 84TEST(AppCacheDatabaseTest, QuickIntegrityCheck) { 85 // Real files on disk for this test too, a corrupt database file. 86 base::ScopedTempDir temp_dir; 87 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 88 base::FilePath mock_dir = temp_dir.path().AppendASCII("mock"); 89 ASSERT_TRUE(base::CreateDirectory(mock_dir)); 90 91 const base::FilePath kDbFile = mock_dir.AppendASCII("appcache.db"); 92 const base::FilePath kOtherFile = mock_dir.AppendASCII("other_file"); 93 EXPECT_EQ(3, base::WriteFile(kOtherFile, "foo", 3)); 94 95 // First create a valid db file. 96 { 97 AppCacheDatabase db(kDbFile); 98 EXPECT_TRUE(db.LazyOpen(true)); 99 EXPECT_TRUE(base::PathExists(kOtherFile)); 100 EXPECT_TRUE(base::PathExists(kDbFile)); 101 } 102 103 // Break it. 104 ASSERT_TRUE(sql::test::CorruptSizeInHeader(kDbFile)); 105 106 // Reopening will notice the corruption and delete/recreate the directory. 107 { 108 sql::ScopedErrorIgnorer ignore_errors; 109 ignore_errors.IgnoreError(SQLITE_CORRUPT); 110 AppCacheDatabase db(kDbFile); 111 EXPECT_TRUE(db.LazyOpen(true)); 112 EXPECT_FALSE(base::PathExists(kOtherFile)); 113 EXPECT_TRUE(base::PathExists(kDbFile)); 114 EXPECT_TRUE(ignore_errors.CheckIgnoredErrors()); 115 } 116} 117#endif // NDEBUG 118 119TEST(AppCacheDatabaseTest, WasCorrutionDetected) { 120 // Real files on disk for this test too, a corrupt database file. 121 base::ScopedTempDir temp_dir; 122 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 123 const base::FilePath kDbFile = temp_dir.path().AppendASCII("appcache.db"); 124 125 // First create a valid db file. 126 AppCacheDatabase db(kDbFile); 127 EXPECT_TRUE(db.LazyOpen(true)); 128 EXPECT_TRUE(base::PathExists(kDbFile)); 129 EXPECT_FALSE(db.was_corruption_detected()); 130 131 // Break it. 132 ASSERT_TRUE(sql::test::CorruptSizeInHeader(kDbFile)); 133 134 // See the the corruption is detected and reported. 135 { 136 sql::ScopedErrorIgnorer ignore_errors; 137 ignore_errors.IgnoreError(SQLITE_CORRUPT); 138 std::map<GURL, int64> usage_map; 139 EXPECT_FALSE(db.GetAllOriginUsage(&usage_map)); 140 EXPECT_TRUE(db.was_corruption_detected()); 141 EXPECT_TRUE(base::PathExists(kDbFile)); 142 EXPECT_TRUE(ignore_errors.CheckIgnoredErrors()); 143 } 144} 145 146TEST(AppCacheDatabaseTest, ExperimentalFlags) { 147 const char kExperimentFlagsKey[] = "ExperimentFlags"; 148 std::string kInjectedFlags("exp1,exp2"); 149 150 // Real files on disk for this test. 151 base::ScopedTempDir temp_dir; 152 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 153 const base::FilePath kDbFile = temp_dir.path().AppendASCII("appcache.db"); 154 const base::FilePath kOtherFile = temp_dir.path().AppendASCII("other_file"); 155 EXPECT_EQ(3, base::WriteFile(kOtherFile, "foo", 3)); 156 EXPECT_TRUE(base::PathExists(kOtherFile)); 157 158 // Inject a non empty flags value, and verify it got there. 159 { 160 AppCacheDatabase db(kDbFile); 161 EXPECT_TRUE(db.LazyOpen(true)); 162 EXPECT_TRUE(db.meta_table_->SetValue(kExperimentFlagsKey, kInjectedFlags)); 163 std::string flags; 164 EXPECT_TRUE(db.meta_table_->GetValue(kExperimentFlagsKey, &flags)); 165 EXPECT_EQ(kInjectedFlags, flags); 166 } 167 168 // If flags don't match the expected value, empty string by default, 169 // the database should be recreated and other files should be cleared out. 170 { 171 AppCacheDatabase db(kDbFile); 172 EXPECT_TRUE(db.LazyOpen(false)); 173 std::string flags; 174 EXPECT_TRUE(db.meta_table_->GetValue(kExperimentFlagsKey, &flags)); 175 EXPECT_TRUE(flags.empty()); 176 EXPECT_FALSE(base::PathExists(kOtherFile)); 177 } 178} 179 180TEST(AppCacheDatabaseTest, EntryRecords) { 181 const base::FilePath kEmptyPath; 182 AppCacheDatabase db(kEmptyPath); 183 EXPECT_TRUE(db.LazyOpen(true)); 184 185 sql::ScopedErrorIgnorer ignore_errors; 186 // TODO(shess): Suppressing SQLITE_CONSTRAINT because the code 187 // expects that and handles the resulting error. Consider revising 188 // the code to use INSERT OR IGNORE (which would not throw 189 // SQLITE_CONSTRAINT) and then check ChangeCount() to see if any 190 // changes were made. 191 ignore_errors.IgnoreError(SQLITE_CONSTRAINT); 192 193 AppCacheDatabase::EntryRecord entry; 194 195 entry.cache_id = 1; 196 entry.url = GURL("http://blah/1"); 197 entry.flags = AppCacheEntry::MASTER; 198 entry.response_id = 1; 199 entry.response_size = 100; 200 EXPECT_TRUE(db.InsertEntry(&entry)); 201 EXPECT_FALSE(db.InsertEntry(&entry)); 202 203 entry.cache_id = 2; 204 entry.url = GURL("http://blah/2"); 205 entry.flags = AppCacheEntry::EXPLICIT; 206 entry.response_id = 2; 207 entry.response_size = 200; 208 EXPECT_TRUE(db.InsertEntry(&entry)); 209 210 entry.cache_id = 2; 211 entry.url = GURL("http://blah/3"); 212 entry.flags = AppCacheEntry::MANIFEST; 213 entry.response_id = 3; 214 entry.response_size = 300; 215 EXPECT_TRUE(db.InsertEntry(&entry)); 216 217 std::vector<AppCacheDatabase::EntryRecord> found; 218 219 EXPECT_TRUE(db.FindEntriesForCache(1, &found)); 220 EXPECT_EQ(1U, found.size()); 221 EXPECT_EQ(1, found[0].cache_id); 222 EXPECT_EQ(GURL("http://blah/1"), found[0].url); 223 EXPECT_EQ(AppCacheEntry::MASTER, found[0].flags); 224 EXPECT_EQ(1, found[0].response_id); 225 EXPECT_EQ(100, found[0].response_size); 226 found.clear(); 227 228 EXPECT_TRUE(db.AddEntryFlags(GURL("http://blah/1"), 1, 229 AppCacheEntry::FOREIGN)); 230 EXPECT_TRUE(db.FindEntriesForCache(1, &found)); 231 EXPECT_EQ(1U, found.size()); 232 EXPECT_EQ(AppCacheEntry::MASTER | AppCacheEntry::FOREIGN, found[0].flags); 233 found.clear(); 234 235 EXPECT_TRUE(db.FindEntriesForCache(2, &found)); 236 EXPECT_EQ(2U, found.size()); 237 EXPECT_EQ(2, found[0].cache_id); 238 EXPECT_EQ(GURL("http://blah/2"), found[0].url); 239 EXPECT_EQ(AppCacheEntry::EXPLICIT, found[0].flags); 240 EXPECT_EQ(2, found[0].response_id); 241 EXPECT_EQ(200, found[0].response_size); 242 EXPECT_EQ(2, found[1].cache_id); 243 EXPECT_EQ(GURL("http://blah/3"), found[1].url); 244 EXPECT_EQ(AppCacheEntry::MANIFEST, found[1].flags); 245 EXPECT_EQ(3, found[1].response_id); 246 EXPECT_EQ(300, found[1].response_size); 247 found.clear(); 248 249 EXPECT_TRUE(db.DeleteEntriesForCache(2)); 250 EXPECT_TRUE(db.FindEntriesForCache(2, &found)); 251 EXPECT_TRUE(found.empty()); 252 found.clear(); 253 254 EXPECT_TRUE(db.DeleteEntriesForCache(1)); 255 EXPECT_FALSE(db.AddEntryFlags(GURL("http://blah/1"), 1, 256 AppCacheEntry::FOREIGN)); 257 258 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 259} 260 261TEST(AppCacheDatabaseTest, CacheRecords) { 262 const base::FilePath kEmptyPath; 263 AppCacheDatabase db(kEmptyPath); 264 EXPECT_TRUE(db.LazyOpen(true)); 265 266 sql::ScopedErrorIgnorer ignore_errors; 267 // TODO(shess): See EntryRecords test. 268 ignore_errors.IgnoreError(SQLITE_CONSTRAINT); 269 270 const AppCacheDatabase::CacheRecord kZeroRecord; 271 AppCacheDatabase::CacheRecord record; 272 EXPECT_FALSE(db.FindCache(1, &record)); 273 274 record.cache_id = 1; 275 record.group_id = 1; 276 record.online_wildcard = true; 277 record.update_time = kZeroTime; 278 record.cache_size = 100; 279 EXPECT_TRUE(db.InsertCache(&record)); 280 EXPECT_FALSE(db.InsertCache(&record)); 281 282 record = kZeroRecord; 283 EXPECT_TRUE(db.FindCache(1, &record)); 284 EXPECT_EQ(1, record.cache_id); 285 EXPECT_EQ(1, record.group_id); 286 EXPECT_TRUE(record.online_wildcard); 287 EXPECT_TRUE(kZeroTime == record.update_time); 288 EXPECT_EQ(100, record.cache_size); 289 290 record = kZeroRecord; 291 EXPECT_TRUE(db.FindCacheForGroup(1, &record)); 292 EXPECT_EQ(1, record.cache_id); 293 EXPECT_EQ(1, record.group_id); 294 EXPECT_TRUE(record.online_wildcard); 295 EXPECT_TRUE(kZeroTime == record.update_time); 296 EXPECT_EQ(100, record.cache_size); 297 298 EXPECT_TRUE(db.DeleteCache(1)); 299 EXPECT_FALSE(db.FindCache(1, &record)); 300 EXPECT_FALSE(db.FindCacheForGroup(1, &record)); 301 302 EXPECT_TRUE(db.DeleteCache(1)); 303 304 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 305} 306 307TEST(AppCacheDatabaseTest, GroupRecords) { 308 const base::FilePath kEmptyPath; 309 AppCacheDatabase db(kEmptyPath); 310 EXPECT_TRUE(db.LazyOpen(true)); 311 312 sql::ScopedErrorIgnorer ignore_errors; 313 // TODO(shess): See EntryRecords test. 314 ignore_errors.IgnoreError(SQLITE_CONSTRAINT); 315 316 const GURL kManifestUrl("http://blah/manifest"); 317 const GURL kOrigin(kManifestUrl.GetOrigin()); 318 const base::Time kLastAccessTime = base::Time::Now(); 319 const base::Time kCreationTime = 320 kLastAccessTime - base::TimeDelta::FromDays(7); 321 322 const AppCacheDatabase::GroupRecord kZeroRecord; 323 AppCacheDatabase::GroupRecord record; 324 std::vector<AppCacheDatabase::GroupRecord> records; 325 326 // Behavior with an empty table 327 EXPECT_FALSE(db.FindGroup(1, &record)); 328 EXPECT_FALSE(db.FindGroupForManifestUrl(kManifestUrl, &record)); 329 EXPECT_TRUE(db.DeleteGroup(1)); 330 EXPECT_TRUE(db.FindGroupsForOrigin(kOrigin, &records)); 331 EXPECT_TRUE(records.empty()); 332 EXPECT_FALSE(db.FindGroupForCache(1, &record)); 333 334 record.group_id = 1; 335 record.manifest_url = kManifestUrl; 336 record.origin = kOrigin; 337 record.last_access_time = kLastAccessTime; 338 record.creation_time = kCreationTime; 339 EXPECT_TRUE(db.InsertGroup(&record)); 340 EXPECT_FALSE(db.InsertGroup(&record)); 341 342 record.group_id = 2; 343 EXPECT_FALSE(db.InsertGroup(&record)); 344 345 record = kZeroRecord; 346 EXPECT_TRUE(db.FindGroup(1, &record)); 347 EXPECT_EQ(1, record.group_id); 348 EXPECT_EQ(kManifestUrl, record.manifest_url); 349 EXPECT_EQ(kOrigin, record.origin); 350 EXPECT_EQ(kCreationTime.ToInternalValue(), 351 record.creation_time.ToInternalValue()); 352 EXPECT_EQ(kLastAccessTime.ToInternalValue(), 353 record.last_access_time.ToInternalValue()); 354 355 record = kZeroRecord; 356 EXPECT_TRUE(db.FindGroupForManifestUrl(kManifestUrl, &record)); 357 EXPECT_EQ(1, record.group_id); 358 EXPECT_EQ(kManifestUrl, record.manifest_url); 359 EXPECT_EQ(kOrigin, record.origin); 360 EXPECT_EQ(kCreationTime.ToInternalValue(), 361 record.creation_time.ToInternalValue()); 362 EXPECT_EQ(kLastAccessTime.ToInternalValue(), 363 record.last_access_time.ToInternalValue()); 364 365 record.group_id = 2; 366 record.manifest_url = kOrigin; 367 record.origin = kOrigin; 368 record.last_access_time = kLastAccessTime; 369 record.creation_time = kCreationTime; 370 EXPECT_TRUE(db.InsertGroup(&record)); 371 372 record = kZeroRecord; 373 EXPECT_TRUE(db.FindGroupForManifestUrl(kOrigin, &record)); 374 EXPECT_EQ(2, record.group_id); 375 EXPECT_EQ(kOrigin, record.manifest_url); 376 EXPECT_EQ(kOrigin, record.origin); 377 EXPECT_EQ(kCreationTime.ToInternalValue(), 378 record.creation_time.ToInternalValue()); 379 EXPECT_EQ(kLastAccessTime.ToInternalValue(), 380 record.last_access_time.ToInternalValue()); 381 382 EXPECT_TRUE(db.FindGroupsForOrigin(kOrigin, &records)); 383 EXPECT_EQ(2U, records.size()); 384 EXPECT_EQ(1, records[0].group_id); 385 EXPECT_EQ(kManifestUrl, records[0].manifest_url); 386 EXPECT_EQ(kOrigin, records[0].origin); 387 EXPECT_EQ(2, records[1].group_id); 388 EXPECT_EQ(kOrigin, records[1].manifest_url); 389 EXPECT_EQ(kOrigin, records[1].origin); 390 391 EXPECT_TRUE(db.DeleteGroup(1)); 392 393 records.clear(); 394 EXPECT_TRUE(db.FindGroupsForOrigin(kOrigin, &records)); 395 EXPECT_EQ(1U, records.size()); 396 EXPECT_EQ(2, records[0].group_id); 397 EXPECT_EQ(kOrigin, records[0].manifest_url); 398 EXPECT_EQ(kOrigin, records[0].origin); 399 EXPECT_EQ(kCreationTime.ToInternalValue(), 400 record.creation_time.ToInternalValue()); 401 EXPECT_EQ(kLastAccessTime.ToInternalValue(), 402 record.last_access_time.ToInternalValue()); 403 404 std::set<GURL> origins; 405 EXPECT_TRUE(db.FindOriginsWithGroups(&origins)); 406 EXPECT_EQ(1U, origins.size()); 407 EXPECT_EQ(kOrigin, *(origins.begin())); 408 409 const GURL kManifest2("http://blah2/manifest"); 410 const GURL kOrigin2(kManifest2.GetOrigin()); 411 record.group_id = 1; 412 record.manifest_url = kManifest2; 413 record.origin = kOrigin2; 414 EXPECT_TRUE(db.InsertGroup(&record)); 415 416 origins.clear(); 417 EXPECT_TRUE(db.FindOriginsWithGroups(&origins)); 418 EXPECT_EQ(2U, origins.size()); 419 EXPECT_TRUE(origins.end() != origins.find(kOrigin)); 420 EXPECT_TRUE(origins.end() != origins.find(kOrigin2)); 421 422 AppCacheDatabase::CacheRecord cache_record; 423 cache_record.cache_id = 1; 424 cache_record.group_id = 1; 425 cache_record.online_wildcard = true; 426 cache_record.update_time = kZeroTime; 427 EXPECT_TRUE(db.InsertCache(&cache_record)); 428 429 record = kZeroRecord; 430 EXPECT_TRUE(db.FindGroupForCache(1, &record)); 431 EXPECT_EQ(1, record.group_id); 432 EXPECT_EQ(kManifest2, record.manifest_url); 433 EXPECT_EQ(kOrigin2, record.origin); 434 435 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 436} 437 438TEST(AppCacheDatabaseTest, NamespaceRecords) { 439 const base::FilePath kEmptyPath; 440 AppCacheDatabase db(kEmptyPath); 441 EXPECT_TRUE(db.LazyOpen(true)); 442 443 sql::ScopedErrorIgnorer ignore_errors; 444 // TODO(shess): See EntryRecords test. 445 ignore_errors.IgnoreError(SQLITE_CONSTRAINT); 446 447 const GURL kFooNameSpace1("http://foo/namespace1"); 448 const GURL kFooNameSpace2("http://foo/namespace2"); 449 const GURL kFooFallbackEntry("http://foo/entry"); 450 const GURL kFooOrigin(kFooNameSpace1.GetOrigin()); 451 const GURL kBarNameSpace1("http://bar/namespace1"); 452 const GURL kBarNameSpace2("http://bar/namespace2"); 453 const GURL kBarFallbackEntry("http://bar/entry"); 454 const GURL kBarOrigin(kBarNameSpace1.GetOrigin()); 455 456 const AppCacheDatabase::NamespaceRecord kZeroRecord; 457 AppCacheDatabase::NamespaceRecord record; 458 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 459 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 460 461 // Behavior with an empty table 462 EXPECT_TRUE(db.FindNamespacesForCache(1, &intercepts, &fallbacks)); 463 EXPECT_TRUE(fallbacks.empty()); 464 EXPECT_TRUE(db.FindNamespacesForOrigin(kFooOrigin, &intercepts, &fallbacks)); 465 EXPECT_TRUE(fallbacks.empty()); 466 EXPECT_TRUE(db.DeleteNamespacesForCache(1)); 467 468 // Two records for two differenent caches in the Foo origin. 469 record.cache_id = 1; 470 record.origin = kFooOrigin; 471 record.namespace_.namespace_url = kFooNameSpace1; 472 record.namespace_.target_url = kFooFallbackEntry; 473 EXPECT_TRUE(db.InsertNamespace(&record)); 474 EXPECT_FALSE(db.InsertNamespace(&record)); 475 476 record.cache_id = 2; 477 record.origin = kFooOrigin; 478 record.namespace_.namespace_url = kFooNameSpace2; 479 record.namespace_.target_url = kFooFallbackEntry; 480 EXPECT_TRUE(db.InsertNamespace(&record)); 481 482 fallbacks.clear(); 483 EXPECT_TRUE(db.FindNamespacesForCache(1, &intercepts, &fallbacks)); 484 EXPECT_EQ(1U, fallbacks.size()); 485 EXPECT_EQ(1, fallbacks[0].cache_id); 486 EXPECT_EQ(kFooOrigin, fallbacks[0].origin); 487 EXPECT_EQ(kFooNameSpace1, fallbacks[0].namespace_.namespace_url); 488 EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url); 489 EXPECT_FALSE(fallbacks[0].namespace_.is_pattern); 490 491 fallbacks.clear(); 492 EXPECT_TRUE(db.FindNamespacesForCache(2, &intercepts, &fallbacks)); 493 EXPECT_EQ(1U, fallbacks.size()); 494 EXPECT_EQ(2, fallbacks[0].cache_id); 495 EXPECT_EQ(kFooOrigin, fallbacks[0].origin); 496 EXPECT_EQ(kFooNameSpace2, fallbacks[0].namespace_.namespace_url); 497 EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url); 498 EXPECT_FALSE(fallbacks[0].namespace_.is_pattern); 499 500 fallbacks.clear(); 501 EXPECT_TRUE(db.FindNamespacesForOrigin(kFooOrigin, &intercepts, &fallbacks)); 502 EXPECT_EQ(2U, fallbacks.size()); 503 EXPECT_EQ(1, fallbacks[0].cache_id); 504 EXPECT_EQ(kFooOrigin, fallbacks[0].origin); 505 EXPECT_EQ(kFooNameSpace1, fallbacks[0].namespace_.namespace_url); 506 EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url); 507 EXPECT_FALSE(fallbacks[0].namespace_.is_pattern); 508 EXPECT_EQ(2, fallbacks[1].cache_id); 509 EXPECT_EQ(kFooOrigin, fallbacks[1].origin); 510 EXPECT_EQ(kFooNameSpace2, fallbacks[1].namespace_.namespace_url); 511 EXPECT_EQ(kFooFallbackEntry, fallbacks[1].namespace_.target_url); 512 EXPECT_FALSE(fallbacks[1].namespace_.is_pattern); 513 514 EXPECT_TRUE(db.DeleteNamespacesForCache(1)); 515 fallbacks.clear(); 516 EXPECT_TRUE(db.FindNamespacesForOrigin(kFooOrigin, &intercepts, &fallbacks)); 517 EXPECT_EQ(1U, fallbacks.size()); 518 EXPECT_EQ(2, fallbacks[0].cache_id); 519 EXPECT_EQ(kFooOrigin, fallbacks[0].origin); 520 EXPECT_EQ(kFooNameSpace2, fallbacks[0].namespace_.namespace_url); 521 EXPECT_EQ(kFooFallbackEntry, fallbacks[0].namespace_.target_url); 522 EXPECT_FALSE(fallbacks[0].namespace_.is_pattern); 523 524 // Two more records for the same cache in the Bar origin. 525 record.cache_id = 3; 526 record.origin = kBarOrigin; 527 record.namespace_.namespace_url = kBarNameSpace1; 528 record.namespace_.target_url = kBarFallbackEntry; 529 record.namespace_.is_pattern = true; 530 EXPECT_TRUE(db.InsertNamespace(&record)); 531 532 record.cache_id = 3; 533 record.origin = kBarOrigin; 534 record.namespace_.namespace_url = kBarNameSpace2; 535 record.namespace_.target_url = kBarFallbackEntry; 536 record.namespace_.is_pattern = true; 537 EXPECT_TRUE(db.InsertNamespace(&record)); 538 539 fallbacks.clear(); 540 EXPECT_TRUE(db.FindNamespacesForCache(3, &intercepts, &fallbacks)); 541 EXPECT_EQ(2U, fallbacks.size()); 542 EXPECT_TRUE(fallbacks[0].namespace_.is_pattern); 543 EXPECT_TRUE(fallbacks[1].namespace_.is_pattern); 544 545 fallbacks.clear(); 546 EXPECT_TRUE(db.FindNamespacesForOrigin(kBarOrigin, &intercepts, &fallbacks)); 547 EXPECT_EQ(2U, fallbacks.size()); 548 EXPECT_TRUE(fallbacks[0].namespace_.is_pattern); 549 EXPECT_TRUE(fallbacks[1].namespace_.is_pattern); 550 551 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 552} 553 554TEST(AppCacheDatabaseTest, OnlineWhiteListRecords) { 555 const base::FilePath kEmptyPath; 556 AppCacheDatabase db(kEmptyPath); 557 EXPECT_TRUE(db.LazyOpen(true)); 558 559 const GURL kFooNameSpace1("http://foo/namespace1"); 560 const GURL kFooNameSpace2("http://foo/namespace2"); 561 const GURL kBarNameSpace1("http://bar/namespace1"); 562 563 const AppCacheDatabase::OnlineWhiteListRecord kZeroRecord; 564 AppCacheDatabase::OnlineWhiteListRecord record; 565 std::vector<AppCacheDatabase::OnlineWhiteListRecord> records; 566 567 // Behavior with an empty table 568 EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records)); 569 EXPECT_TRUE(records.empty()); 570 EXPECT_TRUE(db.DeleteOnlineWhiteListForCache(1)); 571 572 record.cache_id = 1; 573 record.namespace_url = kFooNameSpace1; 574 EXPECT_TRUE(db.InsertOnlineWhiteList(&record)); 575 record.namespace_url = kFooNameSpace2; 576 record.is_pattern = true; 577 EXPECT_TRUE(db.InsertOnlineWhiteList(&record)); 578 records.clear(); 579 EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records)); 580 EXPECT_EQ(2U, records.size()); 581 EXPECT_EQ(1, records[0].cache_id); 582 EXPECT_EQ(kFooNameSpace1, records[0].namespace_url); 583 EXPECT_FALSE(records[0].is_pattern); 584 EXPECT_EQ(1, records[1].cache_id); 585 EXPECT_EQ(kFooNameSpace2, records[1].namespace_url); 586 EXPECT_TRUE(records[1].is_pattern); 587 588 record.cache_id = 2; 589 record.namespace_url = kBarNameSpace1; 590 EXPECT_TRUE(db.InsertOnlineWhiteList(&record)); 591 records.clear(); 592 EXPECT_TRUE(db.FindOnlineWhiteListForCache(2, &records)); 593 EXPECT_EQ(1U, records.size()); 594 595 EXPECT_TRUE(db.DeleteOnlineWhiteListForCache(1)); 596 records.clear(); 597 EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records)); 598 EXPECT_TRUE(records.empty()); 599} 600 601TEST(AppCacheDatabaseTest, DeletableResponseIds) { 602 const base::FilePath kEmptyPath; 603 AppCacheDatabase db(kEmptyPath); 604 EXPECT_TRUE(db.LazyOpen(true)); 605 606 sql::ScopedErrorIgnorer ignore_errors; 607 // TODO(shess): See EntryRecords test. 608 ignore_errors.IgnoreError(SQLITE_CONSTRAINT); 609 610 std::vector<int64> ids; 611 612 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100)); 613 EXPECT_TRUE(ids.empty()); 614 ids.push_back(0); 615 EXPECT_TRUE(db.DeleteDeletableResponseIds(ids)); 616 EXPECT_TRUE(db.InsertDeletableResponseIds(ids)); 617 618 ids.clear(); 619 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100)); 620 EXPECT_EQ(1U, ids.size()); 621 EXPECT_EQ(0, ids[0]); 622 623 int64 unused, deleteable_response_rowid; 624 unused = deleteable_response_rowid = 0; 625 EXPECT_TRUE(db.FindLastStorageIds(&unused, &unused, &unused, 626 &deleteable_response_rowid)); 627 EXPECT_EQ(1, deleteable_response_rowid); 628 629 630 // Expected to fail due to the duplicate id, 0 is already in the table. 631 ids.clear(); 632 ids.push_back(0); 633 ids.push_back(1); 634 EXPECT_FALSE(db.InsertDeletableResponseIds(ids)); 635 636 ids.clear(); 637 for (int i = 1; i < 10; ++i) 638 ids.push_back(i); 639 EXPECT_TRUE(db.InsertDeletableResponseIds(ids)); 640 EXPECT_TRUE(db.FindLastStorageIds(&unused, &unused, &unused, 641 &deleteable_response_rowid)); 642 EXPECT_EQ(10, deleteable_response_rowid); 643 644 ids.clear(); 645 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100)); 646 EXPECT_EQ(10U, ids.size()); 647 for (int i = 0; i < 10; ++i) 648 EXPECT_EQ(i, ids[i]); 649 650 // Ensure the limit is respected. 651 ids.clear(); 652 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 5)); 653 EXPECT_EQ(5U, ids.size()); 654 for (int i = 0; i < static_cast<int>(ids.size()); ++i) 655 EXPECT_EQ(i, ids[i]); 656 657 // Ensure the max_rowid is respected (the first rowid is 1). 658 ids.clear(); 659 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, 5, 100)); 660 EXPECT_EQ(5U, ids.size()); 661 for (int i = 0; i < static_cast<int>(ids.size()); ++i) 662 EXPECT_EQ(i, ids[i]); 663 664 // Ensure that we can delete from the table. 665 EXPECT_TRUE(db.DeleteDeletableResponseIds(ids)); 666 ids.clear(); 667 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100)); 668 EXPECT_EQ(5U, ids.size()); 669 for (int i = 0; i < static_cast<int>(ids.size()); ++i) 670 EXPECT_EQ(i + 5, ids[i]); 671 672 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 673} 674 675TEST(AppCacheDatabaseTest, OriginUsage) { 676 const GURL kManifestUrl("http://blah/manifest"); 677 const GURL kManifestUrl2("http://blah/manifest2"); 678 const GURL kOrigin(kManifestUrl.GetOrigin()); 679 const GURL kOtherOriginManifestUrl("http://other/manifest"); 680 const GURL kOtherOrigin(kOtherOriginManifestUrl.GetOrigin()); 681 682 const base::FilePath kEmptyPath; 683 AppCacheDatabase db(kEmptyPath); 684 EXPECT_TRUE(db.LazyOpen(true)); 685 686 std::vector<AppCacheDatabase::CacheRecord> cache_records; 687 EXPECT_EQ(0, db.GetOriginUsage(kOrigin)); 688 EXPECT_TRUE(db.FindCachesForOrigin(kOrigin, &cache_records)); 689 EXPECT_TRUE(cache_records.empty()); 690 691 AppCacheDatabase::GroupRecord group_record; 692 group_record.group_id = 1; 693 group_record.manifest_url = kManifestUrl; 694 group_record.origin = kOrigin; 695 EXPECT_TRUE(db.InsertGroup(&group_record)); 696 AppCacheDatabase::CacheRecord cache_record; 697 cache_record.cache_id = 1; 698 cache_record.group_id = 1; 699 cache_record.online_wildcard = true; 700 cache_record.update_time = kZeroTime; 701 cache_record.cache_size = 100; 702 EXPECT_TRUE(db.InsertCache(&cache_record)); 703 704 EXPECT_EQ(100, db.GetOriginUsage(kOrigin)); 705 706 group_record.group_id = 2; 707 group_record.manifest_url = kManifestUrl2; 708 group_record.origin = kOrigin; 709 EXPECT_TRUE(db.InsertGroup(&group_record)); 710 cache_record.cache_id = 2; 711 cache_record.group_id = 2; 712 cache_record.online_wildcard = true; 713 cache_record.update_time = kZeroTime; 714 cache_record.cache_size = 1000; 715 EXPECT_TRUE(db.InsertCache(&cache_record)); 716 717 EXPECT_EQ(1100, db.GetOriginUsage(kOrigin)); 718 719 group_record.group_id = 3; 720 group_record.manifest_url = kOtherOriginManifestUrl; 721 group_record.origin = kOtherOrigin; 722 EXPECT_TRUE(db.InsertGroup(&group_record)); 723 cache_record.cache_id = 3; 724 cache_record.group_id = 3; 725 cache_record.online_wildcard = true; 726 cache_record.update_time = kZeroTime; 727 cache_record.cache_size = 5000; 728 EXPECT_TRUE(db.InsertCache(&cache_record)); 729 730 EXPECT_EQ(5000, db.GetOriginUsage(kOtherOrigin)); 731 732 EXPECT_TRUE(db.FindCachesForOrigin(kOrigin, &cache_records)); 733 EXPECT_EQ(2U, cache_records.size()); 734 cache_records.clear(); 735 EXPECT_TRUE(db.FindCachesForOrigin(kOtherOrigin, &cache_records)); 736 EXPECT_EQ(1U, cache_records.size()); 737 738 std::map<GURL, int64> usage_map; 739 EXPECT_TRUE(db.GetAllOriginUsage(&usage_map)); 740 EXPECT_EQ(2U, usage_map.size()); 741 EXPECT_EQ(1100, usage_map[kOrigin]); 742 EXPECT_EQ(5000, usage_map[kOtherOrigin]); 743} 744 745#if defined(APPCACHE_USE_SIMPLE_CACHE) 746// There is no such upgrade path in this case. 747#else 748TEST(AppCacheDatabaseTest, UpgradeSchema3to5) { 749 // Real file on disk for this test. 750 base::ScopedTempDir temp_dir; 751 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 752 const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade3.db"); 753 754 const GURL kMockOrigin("http://mockorigin/"); 755 const char kNamespaceUrlFormat[] = "namespace%d"; 756 const char kTargetUrlFormat[] = "target%d"; 757 const int kNumNamespaces = 10; 758 759 // Create a v3 schema based database containing some fallback records. 760 { 761 const int kVersion3 = 3; 762 const char kGroupsTable[] = "Groups"; 763 const char kCachesTable[] = "Caches"; 764 const char kEntriesTable[] = "Entries"; 765 const char kFallbackNameSpacesTable[] = "FallbackNameSpaces"; 766 const char kOnlineWhiteListsTable[] = "OnlineWhiteLists"; 767 const char kDeletableResponseIdsTable[] = "DeletableResponseIds"; 768 769 const struct { 770 const char* table_name; 771 const char* columns; 772 } kTables3[] = { 773 { kGroupsTable, 774 "(group_id INTEGER PRIMARY KEY," 775 " origin TEXT," 776 " manifest_url TEXT," 777 " creation_time INTEGER," 778 " last_access_time INTEGER)" }, 779 780 { kCachesTable, 781 "(cache_id INTEGER PRIMARY KEY," 782 " group_id INTEGER," 783 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1))," 784 " update_time INTEGER," 785 " cache_size INTEGER)" }, // intentionally not normalized 786 787 { kEntriesTable, 788 "(cache_id INTEGER," 789 " url TEXT," 790 " flags INTEGER," 791 " response_id INTEGER," 792 " response_size INTEGER)" }, 793 794 { kFallbackNameSpacesTable, 795 "(cache_id INTEGER," 796 " origin TEXT," // intentionally not normalized 797 " namespace_url TEXT," 798 " fallback_entry_url TEXT)" }, 799 800 { kOnlineWhiteListsTable, 801 "(cache_id INTEGER," 802 " namespace_url TEXT)" }, 803 804 { kDeletableResponseIdsTable, 805 "(response_id INTEGER NOT NULL)" }, 806 }; 807 808 const struct { 809 const char* index_name; 810 const char* table_name; 811 const char* columns; 812 bool unique; 813 } kIndexes3[] = { 814 { "GroupsOriginIndex", 815 kGroupsTable, 816 "(origin)", 817 false }, 818 819 { "GroupsManifestIndex", 820 kGroupsTable, 821 "(manifest_url)", 822 true }, 823 824 { "CachesGroupIndex", 825 kCachesTable, 826 "(group_id)", 827 false }, 828 829 { "EntriesCacheIndex", 830 kEntriesTable, 831 "(cache_id)", 832 false }, 833 834 { "EntriesCacheAndUrlIndex", 835 kEntriesTable, 836 "(cache_id, url)", 837 true }, 838 839 { "EntriesResponseIdIndex", 840 kEntriesTable, 841 "(response_id)", 842 true }, 843 844 { "FallbackNameSpacesCacheIndex", 845 kFallbackNameSpacesTable, 846 "(cache_id)", 847 false }, 848 849 { "FallbackNameSpacesOriginIndex", 850 kFallbackNameSpacesTable, 851 "(origin)", 852 false }, 853 854 { "FallbackNameSpacesCacheAndUrlIndex", 855 kFallbackNameSpacesTable, 856 "(cache_id, namespace_url)", 857 true }, 858 859 { "OnlineWhiteListCacheIndex", 860 kOnlineWhiteListsTable, 861 "(cache_id)", 862 false }, 863 864 { "DeletableResponsesIdIndex", 865 kDeletableResponseIdsTable, 866 "(response_id)", 867 true }, 868 }; 869 870 const int kTableCount3 = ARRAYSIZE_UNSAFE(kTables3); 871 const int kIndexCount3 = ARRAYSIZE_UNSAFE(kIndexes3); 872 873 sql::Connection connection; 874 EXPECT_TRUE(connection.Open(kDbFile)); 875 876 sql::Transaction transaction(&connection); 877 EXPECT_TRUE(transaction.Begin()); 878 879 sql::MetaTable meta_table; 880 EXPECT_TRUE(meta_table.Init(&connection, kVersion3, kVersion3)); 881 882 for (int i = 0; i < kTableCount3; ++i) { 883 std::string sql("CREATE TABLE "); 884 sql += kTables3[i].table_name; 885 sql += kTables3[i].columns; 886 EXPECT_TRUE(connection.Execute(sql.c_str())); 887 } 888 889 for (int i = 0; i < kIndexCount3; ++i) { 890 std::string sql; 891 if (kIndexes3[i].unique) 892 sql += "CREATE UNIQUE INDEX "; 893 else 894 sql += "CREATE INDEX "; 895 sql += kIndexes3[i].index_name; 896 sql += " ON "; 897 sql += kIndexes3[i].table_name; 898 sql += kIndexes3[i].columns; 899 EXPECT_TRUE(connection.Execute(sql.c_str())); 900 } 901 902 const char* kSql = 903 "INSERT INTO FallbackNameSpaces" 904 " (cache_id, origin, namespace_url, fallback_entry_url)" 905 " VALUES (?, ?, ?, ?)"; 906 907 sql::Statement statement; 908 statement.Assign(connection.GetUniqueStatement(kSql)); 909 EXPECT_TRUE(statement.is_valid()); 910 for (int i = 0; i < kNumNamespaces; ++i) { 911 GURL namespace_url( 912 kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i))); 913 GURL target_url( 914 kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i))); 915 statement.BindInt64(0, i); 916 statement.BindString(1, kMockOrigin.spec().c_str()); 917 statement.BindString(2, namespace_url.spec().c_str()); 918 statement.BindString(3, target_url.spec().c_str()); 919 ASSERT_TRUE(statement.Run()); 920 statement.Reset(true); 921 } 922 923 EXPECT_TRUE(transaction.Commit()); 924 } 925 926 // Open that database and verify that it got updated. 927 AppCacheDatabase db(kDbFile); 928 EXPECT_TRUE(db.LazyOpen(true)); 929 930 EXPECT_FALSE(db.db_->DoesTableExist("FallbackNameSpaces")); 931 EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNamesSpacesCacheIndex")); 932 EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNameSpacesOriginIndex")); 933 EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNameSpacesCacheAndUrlIndex")); 934 935 EXPECT_TRUE(db.db_->DoesTableExist("Namespaces")); 936 EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheIndex")); 937 EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesOriginIndex")); 938 EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheAndUrlIndex")); 939 EXPECT_TRUE(db.db_->DoesColumnExist("Namespaces", "is_pattern")); 940 EXPECT_TRUE(db.db_->DoesColumnExist("OnlineWhiteLists", "is_pattern")); 941 942 EXPECT_EQ(5, db.meta_table_->GetVersionNumber()); 943 EXPECT_EQ(5, db.meta_table_->GetCompatibleVersionNumber()); 944 945 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 946 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 947 EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts, 948 &fallbacks)); 949 EXPECT_TRUE(intercepts.empty()); 950 EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size())); 951 952 for (int i = 0; i < kNumNamespaces; ++i) { 953 GURL expected_namespace_url( 954 kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i))); 955 GURL expected_target_url( 956 kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i))); 957 958 EXPECT_EQ(i, fallbacks[i].cache_id); 959 EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[i].namespace_.type); 960 EXPECT_EQ(kMockOrigin, fallbacks[i].origin); 961 EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_.namespace_url); 962 EXPECT_EQ(expected_target_url, fallbacks[i].namespace_.target_url); 963 EXPECT_FALSE(fallbacks[i].namespace_.is_pattern); 964 } 965} 966#endif // !APPCACHE_USE_SIMPLE_CACHE 967 968#if defined(APPCACHE_USE_SIMPLE_CACHE) 969// There is no such upgrade path in this case. 970#else 971TEST(AppCacheDatabaseTest, UpgradeSchema4to5) { 972 // Real file on disk for this test. 973 base::ScopedTempDir temp_dir; 974 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 975 const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade4.db"); 976 977 const GURL kMockOrigin("http://mockorigin/"); 978 const char kNamespaceUrlFormat[] = "namespace%d"; 979 const char kWhitelistUrlFormat[] = "whitelist%d"; 980 const char kTargetUrlFormat[] = "target%d"; 981 const int kNumNamespaces = 10; 982 const int kWhitelistCacheId = 1; 983 984 // Create a v4 schema based database containing some fallback records. 985 { 986 const int kVersion4 = 4; 987 const char kGroupsTable[] = "Groups"; 988 const char kCachesTable[] = "Caches"; 989 const char kEntriesTable[] = "Entries"; 990 const char kNamespacesTable[] = "Namespaces"; 991 const char kOnlineWhiteListsTable[] = "OnlineWhiteLists"; 992 const char kDeletableResponseIdsTable[] = "DeletableResponseIds"; 993 994 struct TableInfo { 995 const char* table_name; 996 const char* columns; 997 }; 998 999 struct IndexInfo { 1000 const char* index_name; 1001 const char* table_name; 1002 const char* columns; 1003 bool unique; 1004 }; 1005 1006 const TableInfo kTables4[] = { 1007 { kGroupsTable, 1008 "(group_id INTEGER PRIMARY KEY," 1009 " origin TEXT," 1010 " manifest_url TEXT," 1011 " creation_time INTEGER," 1012 " last_access_time INTEGER)" }, 1013 1014 { kCachesTable, 1015 "(cache_id INTEGER PRIMARY KEY," 1016 " group_id INTEGER," 1017 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1))," 1018 " update_time INTEGER," 1019 " cache_size INTEGER)" }, // intentionally not normalized 1020 1021 { kEntriesTable, 1022 "(cache_id INTEGER," 1023 " url TEXT," 1024 " flags INTEGER," 1025 " response_id INTEGER," 1026 " response_size INTEGER)" }, 1027 1028 { kNamespacesTable, 1029 "(cache_id INTEGER," 1030 " origin TEXT," // intentionally not normalized 1031 " type INTEGER," 1032 " namespace_url TEXT," 1033 " target_url TEXT)" }, 1034 1035 { kOnlineWhiteListsTable, 1036 "(cache_id INTEGER," 1037 " namespace_url TEXT)" }, 1038 1039 { kDeletableResponseIdsTable, 1040 "(response_id INTEGER NOT NULL)" }, 1041 }; 1042 1043 const IndexInfo kIndexes4[] = { 1044 { "GroupsOriginIndex", 1045 kGroupsTable, 1046 "(origin)", 1047 false }, 1048 1049 { "GroupsManifestIndex", 1050 kGroupsTable, 1051 "(manifest_url)", 1052 true }, 1053 1054 { "CachesGroupIndex", 1055 kCachesTable, 1056 "(group_id)", 1057 false }, 1058 1059 { "EntriesCacheIndex", 1060 kEntriesTable, 1061 "(cache_id)", 1062 false }, 1063 1064 { "EntriesCacheAndUrlIndex", 1065 kEntriesTable, 1066 "(cache_id, url)", 1067 true }, 1068 1069 { "EntriesResponseIdIndex", 1070 kEntriesTable, 1071 "(response_id)", 1072 true }, 1073 1074 { "NamespacesCacheIndex", 1075 kNamespacesTable, 1076 "(cache_id)", 1077 false }, 1078 1079 { "NamespacesOriginIndex", 1080 kNamespacesTable, 1081 "(origin)", 1082 false }, 1083 1084 { "NamespacesCacheAndUrlIndex", 1085 kNamespacesTable, 1086 "(cache_id, namespace_url)", 1087 true }, 1088 1089 { "OnlineWhiteListCacheIndex", 1090 kOnlineWhiteListsTable, 1091 "(cache_id)", 1092 false }, 1093 1094 { "DeletableResponsesIdIndex", 1095 kDeletableResponseIdsTable, 1096 "(response_id)", 1097 true }, 1098 }; 1099 1100 const int kTableCount4 = ARRAYSIZE_UNSAFE(kTables4); 1101 const int kIndexCount4 = ARRAYSIZE_UNSAFE(kIndexes4); 1102 1103 sql::Connection connection; 1104 EXPECT_TRUE(connection.Open(kDbFile)); 1105 1106 sql::Transaction transaction(&connection); 1107 EXPECT_TRUE(transaction.Begin()); 1108 1109 sql::MetaTable meta_table; 1110 EXPECT_TRUE(meta_table.Init(&connection, kVersion4, kVersion4)); 1111 1112 for (int i = 0; i < kTableCount4; ++i) { 1113 std::string sql("CREATE TABLE "); 1114 sql += kTables4[i].table_name; 1115 sql += kTables4[i].columns; 1116 EXPECT_TRUE(connection.Execute(sql.c_str())); 1117 } 1118 1119 for (int i = 0; i < kIndexCount4; ++i) { 1120 std::string sql; 1121 if (kIndexes4[i].unique) 1122 sql += "CREATE UNIQUE INDEX "; 1123 else 1124 sql += "CREATE INDEX "; 1125 sql += kIndexes4[i].index_name; 1126 sql += " ON "; 1127 sql += kIndexes4[i].table_name; 1128 sql += kIndexes4[i].columns; 1129 EXPECT_TRUE(connection.Execute(sql.c_str())); 1130 } 1131 1132 const char* kNamespacesSql = 1133 "INSERT INTO Namespaces" 1134 " (cache_id, origin, type, namespace_url, target_url)" 1135 " VALUES (?, ?, ?, ?, ?)"; 1136 sql::Statement statement; 1137 statement.Assign(connection.GetUniqueStatement(kNamespacesSql)); 1138 EXPECT_TRUE(statement.is_valid()); 1139 for (int i = 0; i < kNumNamespaces; ++i) { 1140 GURL namespace_url( 1141 kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i))); 1142 GURL target_url( 1143 kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i))); 1144 statement.BindInt64(0, i); 1145 statement.BindString(1, kMockOrigin.spec().c_str()); 1146 statement.BindInt(2, APPCACHE_FALLBACK_NAMESPACE); 1147 statement.BindString(3, namespace_url.spec().c_str()); 1148 statement.BindString(4, target_url.spec().c_str()); 1149 ASSERT_TRUE(statement.Run()); 1150 statement.Reset(true); 1151 } 1152 1153 const char* kWhitelistsSql = 1154 "INSERT INTO OnlineWhiteLists" 1155 " (cache_id, namespace_url)" 1156 " VALUES (?, ?)"; 1157 statement.Assign(connection.GetUniqueStatement(kWhitelistsSql)); 1158 EXPECT_TRUE(statement.is_valid()); 1159 for (int i = 0; i < kNumNamespaces; ++i) { 1160 GURL namespace_url( 1161 kMockOrigin.Resolve(base::StringPrintf(kWhitelistUrlFormat, i))); 1162 statement.BindInt64(0, kWhitelistCacheId); 1163 statement.BindString(1, namespace_url.spec().c_str()); 1164 ASSERT_TRUE(statement.Run()); 1165 statement.Reset(true); 1166 } 1167 1168 EXPECT_TRUE(transaction.Commit()); 1169 } 1170 1171 // Open that database and verify that it got upgraded to v5. 1172 AppCacheDatabase db(kDbFile); 1173 EXPECT_TRUE(db.LazyOpen(true)); 1174 EXPECT_TRUE(db.db_->DoesColumnExist("Namespaces", "is_pattern")); 1175 EXPECT_TRUE(db.db_->DoesColumnExist("OnlineWhiteLists", "is_pattern")); 1176 EXPECT_EQ(5, db.meta_table_->GetVersionNumber()); 1177 EXPECT_EQ(5, db.meta_table_->GetCompatibleVersionNumber()); 1178 1179 std::vector<AppCacheDatabase::NamespaceRecord> intercepts; 1180 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks; 1181 EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts, 1182 &fallbacks)); 1183 EXPECT_TRUE(intercepts.empty()); 1184 EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size())); 1185 1186 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists; 1187 EXPECT_TRUE(db.FindOnlineWhiteListForCache(kWhitelistCacheId, &whitelists)); 1188 EXPECT_EQ(kNumNamespaces, static_cast<int>(whitelists.size())); 1189 1190 for (int i = 0; i < kNumNamespaces; ++i) { 1191 GURL expected_namespace_url( 1192 kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i))); 1193 GURL expected_target_url( 1194 kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i))); 1195 GURL expected_whitelist_url( 1196 kMockOrigin.Resolve(base::StringPrintf(kWhitelistUrlFormat, i))); 1197 1198 EXPECT_EQ(i, fallbacks[i].cache_id); 1199 EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[i].namespace_.type); 1200 EXPECT_EQ(kMockOrigin, fallbacks[i].origin); 1201 EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_.namespace_url); 1202 EXPECT_EQ(expected_target_url, fallbacks[i].namespace_.target_url); 1203 EXPECT_FALSE(fallbacks[i].namespace_.is_pattern); 1204 EXPECT_EQ(expected_whitelist_url, whitelists[i].namespace_url); 1205 EXPECT_FALSE(whitelists[i].is_pattern); 1206 } 1207} 1208#endif // !APPCACHE_USE_SIMPLE_CACHE 1209 1210} // namespace content 1211