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