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