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