- add sources.
[platform/framework/web/crosswalk.git] / src / webkit / browser / appcache / appcache_database_unittest.cc
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 #if defined(APPCACHE_USE_SIMPLE_CACHE)
672 // There is no such upgrade path in this case.
673 #else
674 TEST(AppCacheDatabaseTest, UpgradeSchema3to5) {
675   // Real file on disk for this test.
676   base::ScopedTempDir temp_dir;
677   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
678   const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade3.db");
679
680   const GURL kMockOrigin("http://mockorigin/");
681   const char kNamespaceUrlFormat[] = "namespace%d";
682   const char kTargetUrlFormat[] = "target%d";
683   const int kNumNamespaces = 10;
684
685   // Create a v3 schema based database containing some fallback records.
686   {
687     const int kVersion3 = 3;
688     const char kGroupsTable[] = "Groups";
689     const char kCachesTable[] = "Caches";
690     const char kEntriesTable[] = "Entries";
691     const char kFallbackNameSpacesTable[] = "FallbackNameSpaces";
692     const char kOnlineWhiteListsTable[] = "OnlineWhiteLists";
693     const char kDeletableResponseIdsTable[] = "DeletableResponseIds";
694
695     const struct {
696       const char* table_name;
697       const char* columns;
698     } kTables3[] = {
699       { kGroupsTable,
700         "(group_id INTEGER PRIMARY KEY,"
701         " origin TEXT,"
702         " manifest_url TEXT,"
703         " creation_time INTEGER,"
704         " last_access_time INTEGER)" },
705
706       { kCachesTable,
707         "(cache_id INTEGER PRIMARY KEY,"
708         " group_id INTEGER,"
709         " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
710         " update_time INTEGER,"
711         " cache_size INTEGER)" },  // intentionally not normalized
712
713       { kEntriesTable,
714         "(cache_id INTEGER,"
715         " url TEXT,"
716         " flags INTEGER,"
717         " response_id INTEGER,"
718         " response_size INTEGER)" },
719
720       { kFallbackNameSpacesTable,
721         "(cache_id INTEGER,"
722         " origin TEXT,"  // intentionally not normalized
723         " namespace_url TEXT,"
724         " fallback_entry_url TEXT)" },
725
726       { kOnlineWhiteListsTable,
727         "(cache_id INTEGER,"
728         " namespace_url TEXT)" },
729
730       { kDeletableResponseIdsTable,
731         "(response_id INTEGER NOT NULL)" },
732     };
733
734     const struct {
735       const char* index_name;
736       const char* table_name;
737       const char* columns;
738       bool unique;
739     } kIndexes3[] = {
740       { "GroupsOriginIndex",
741         kGroupsTable,
742         "(origin)",
743         false },
744
745       { "GroupsManifestIndex",
746         kGroupsTable,
747         "(manifest_url)",
748         true },
749
750       { "CachesGroupIndex",
751         kCachesTable,
752         "(group_id)",
753         false },
754
755       { "EntriesCacheIndex",
756         kEntriesTable,
757         "(cache_id)",
758         false },
759
760       { "EntriesCacheAndUrlIndex",
761         kEntriesTable,
762         "(cache_id, url)",
763         true },
764
765       { "EntriesResponseIdIndex",
766         kEntriesTable,
767         "(response_id)",
768         true },
769
770       { "FallbackNameSpacesCacheIndex",
771         kFallbackNameSpacesTable,
772         "(cache_id)",
773         false },
774
775       { "FallbackNameSpacesOriginIndex",
776         kFallbackNameSpacesTable,
777         "(origin)",
778         false },
779
780       { "FallbackNameSpacesCacheAndUrlIndex",
781         kFallbackNameSpacesTable,
782         "(cache_id, namespace_url)",
783         true },
784
785       { "OnlineWhiteListCacheIndex",
786         kOnlineWhiteListsTable,
787         "(cache_id)",
788         false },
789
790       { "DeletableResponsesIdIndex",
791         kDeletableResponseIdsTable,
792         "(response_id)",
793         true },
794     };
795
796     const int kTableCount3 = ARRAYSIZE_UNSAFE(kTables3);
797     const int kIndexCount3 = ARRAYSIZE_UNSAFE(kIndexes3);
798
799     sql::Connection connection;
800     EXPECT_TRUE(connection.Open(kDbFile));
801
802     sql::Transaction transaction(&connection);
803     EXPECT_TRUE(transaction.Begin());
804
805     sql::MetaTable meta_table;
806     EXPECT_TRUE(meta_table.Init(&connection, kVersion3, kVersion3));
807
808     for (int i = 0; i < kTableCount3; ++i) {
809       std::string sql("CREATE TABLE ");
810       sql += kTables3[i].table_name;
811       sql += kTables3[i].columns;
812       EXPECT_TRUE(connection.Execute(sql.c_str()));
813     }
814
815     for (int i = 0; i < kIndexCount3; ++i) {
816       std::string sql;
817       if (kIndexes3[i].unique)
818         sql += "CREATE UNIQUE INDEX ";
819       else
820         sql += "CREATE INDEX ";
821       sql += kIndexes3[i].index_name;
822       sql += " ON ";
823       sql += kIndexes3[i].table_name;
824       sql += kIndexes3[i].columns;
825       EXPECT_TRUE(connection.Execute(sql.c_str()));
826     }
827
828     const char* kSql =
829         "INSERT INTO FallbackNameSpaces"
830         "  (cache_id, origin, namespace_url, fallback_entry_url)"
831         "  VALUES (?, ?, ?, ?)";
832
833     sql::Statement statement;
834     statement.Assign(connection.GetUniqueStatement(kSql));
835     EXPECT_TRUE(statement.is_valid());
836     for (int i = 0; i < kNumNamespaces; ++i) {
837       GURL namespace_url(
838           kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i)));
839       GURL target_url(
840           kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i)));
841       statement.BindInt64(0, i);
842       statement.BindString(1, kMockOrigin.spec().c_str());
843       statement.BindString(2, namespace_url.spec().c_str());
844       statement.BindString(3, target_url.spec().c_str());
845       ASSERT_TRUE(statement.Run());
846       statement.Reset(true);
847     }
848
849     EXPECT_TRUE(transaction.Commit());
850   }
851
852   // Open that database and verify that it got updated.
853   AppCacheDatabase db(kDbFile);
854   EXPECT_TRUE(db.LazyOpen(true));
855
856   EXPECT_FALSE(db.db_->DoesTableExist("FallbackNameSpaces"));
857   EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNamesSpacesCacheIndex"));
858   EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNameSpacesOriginIndex"));
859   EXPECT_FALSE(db.db_->DoesIndexExist("FallbackNameSpacesCacheAndUrlIndex"));
860
861   EXPECT_TRUE(db.db_->DoesTableExist("Namespaces"));
862   EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheIndex"));
863   EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesOriginIndex"));
864   EXPECT_TRUE(db.db_->DoesIndexExist("NamespacesCacheAndUrlIndex"));
865   EXPECT_TRUE(db.db_->DoesColumnExist("Namespaces", "is_pattern"));
866   EXPECT_TRUE(db.db_->DoesColumnExist("OnlineWhiteLists", "is_pattern"));
867
868   EXPECT_EQ(5, db.meta_table_->GetVersionNumber());
869   EXPECT_EQ(5, db.meta_table_->GetCompatibleVersionNumber());
870
871   std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
872   std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
873   EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts,
874                                          &fallbacks));
875   EXPECT_TRUE(intercepts.empty());
876   EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size()));
877
878   for (int i = 0; i < kNumNamespaces; ++i) {
879     GURL expected_namespace_url(
880         kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i)));
881     GURL expected_target_url(
882         kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i)));
883
884     EXPECT_EQ(i, fallbacks[i].cache_id);
885     EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[i].namespace_.type);
886     EXPECT_EQ(kMockOrigin, fallbacks[i].origin);
887     EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_.namespace_url);
888     EXPECT_EQ(expected_target_url, fallbacks[i].namespace_.target_url);
889     EXPECT_FALSE(fallbacks[i].namespace_.is_pattern);
890   }
891 }
892 #endif  // !APPCACHE_USE_SIMPLE_CACHE
893
894 #if defined(APPCACHE_USE_SIMPLE_CACHE)
895 // There is no such upgrade path in this case.
896 #else
897 TEST(AppCacheDatabaseTest, UpgradeSchema4to5) {
898   // Real file on disk for this test.
899   base::ScopedTempDir temp_dir;
900   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
901   const base::FilePath kDbFile = temp_dir.path().AppendASCII("upgrade4.db");
902
903   const GURL kMockOrigin("http://mockorigin/");
904   const char kNamespaceUrlFormat[] = "namespace%d";
905   const char kWhitelistUrlFormat[] = "whitelist%d";
906   const char kTargetUrlFormat[] = "target%d";
907   const int kNumNamespaces = 10;
908   const int kWhitelistCacheId = 1;
909
910   // Create a v4 schema based database containing some fallback records.
911   {
912     const int kVersion4 = 4;
913     const char kGroupsTable[] = "Groups";
914     const char kCachesTable[] = "Caches";
915     const char kEntriesTable[] = "Entries";
916     const char kNamespacesTable[] = "Namespaces";
917     const char kOnlineWhiteListsTable[] = "OnlineWhiteLists";
918     const char kDeletableResponseIdsTable[] = "DeletableResponseIds";
919
920     struct TableInfo {
921       const char* table_name;
922       const char* columns;
923     };
924
925     struct IndexInfo {
926       const char* index_name;
927       const char* table_name;
928       const char* columns;
929       bool unique;
930     };
931
932     const TableInfo kTables4[] = {
933       { kGroupsTable,
934         "(group_id INTEGER PRIMARY KEY,"
935         " origin TEXT,"
936         " manifest_url TEXT,"
937         " creation_time INTEGER,"
938         " last_access_time INTEGER)" },
939
940       { kCachesTable,
941         "(cache_id INTEGER PRIMARY KEY,"
942         " group_id INTEGER,"
943         " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
944         " update_time INTEGER,"
945         " cache_size INTEGER)" },  // intentionally not normalized
946
947       { kEntriesTable,
948         "(cache_id INTEGER,"
949         " url TEXT,"
950         " flags INTEGER,"
951         " response_id INTEGER,"
952         " response_size INTEGER)" },
953
954       { kNamespacesTable,
955         "(cache_id INTEGER,"
956         " origin TEXT,"  // intentionally not normalized
957         " type INTEGER,"
958         " namespace_url TEXT,"
959         " target_url TEXT)" },
960
961       { kOnlineWhiteListsTable,
962         "(cache_id INTEGER,"
963         " namespace_url TEXT)" },
964
965       { kDeletableResponseIdsTable,
966         "(response_id INTEGER NOT NULL)" },
967     };
968
969     const IndexInfo kIndexes4[] = {
970       { "GroupsOriginIndex",
971         kGroupsTable,
972         "(origin)",
973         false },
974
975       { "GroupsManifestIndex",
976         kGroupsTable,
977         "(manifest_url)",
978         true },
979
980       { "CachesGroupIndex",
981         kCachesTable,
982         "(group_id)",
983         false },
984
985       { "EntriesCacheIndex",
986         kEntriesTable,
987         "(cache_id)",
988         false },
989
990       { "EntriesCacheAndUrlIndex",
991         kEntriesTable,
992         "(cache_id, url)",
993         true },
994
995       { "EntriesResponseIdIndex",
996         kEntriesTable,
997         "(response_id)",
998         true },
999
1000       { "NamespacesCacheIndex",
1001         kNamespacesTable,
1002         "(cache_id)",
1003         false },
1004
1005       { "NamespacesOriginIndex",
1006         kNamespacesTable,
1007         "(origin)",
1008         false },
1009
1010       { "NamespacesCacheAndUrlIndex",
1011         kNamespacesTable,
1012         "(cache_id, namespace_url)",
1013         true },
1014
1015       { "OnlineWhiteListCacheIndex",
1016         kOnlineWhiteListsTable,
1017         "(cache_id)",
1018         false },
1019
1020       { "DeletableResponsesIdIndex",
1021         kDeletableResponseIdsTable,
1022         "(response_id)",
1023         true },
1024     };
1025
1026     const int kTableCount4 = ARRAYSIZE_UNSAFE(kTables4);
1027     const int kIndexCount4 = ARRAYSIZE_UNSAFE(kIndexes4);
1028
1029     sql::Connection connection;
1030     EXPECT_TRUE(connection.Open(kDbFile));
1031
1032     sql::Transaction transaction(&connection);
1033     EXPECT_TRUE(transaction.Begin());
1034
1035     sql::MetaTable meta_table;
1036     EXPECT_TRUE(meta_table.Init(&connection, kVersion4, kVersion4));
1037
1038     for (int i = 0; i < kTableCount4; ++i) {
1039       std::string sql("CREATE TABLE ");
1040       sql += kTables4[i].table_name;
1041       sql += kTables4[i].columns;
1042       EXPECT_TRUE(connection.Execute(sql.c_str()));
1043     }
1044
1045     for (int i = 0; i < kIndexCount4; ++i) {
1046       std::string sql;
1047       if (kIndexes4[i].unique)
1048         sql += "CREATE UNIQUE INDEX ";
1049       else
1050         sql += "CREATE INDEX ";
1051       sql += kIndexes4[i].index_name;
1052       sql += " ON ";
1053       sql += kIndexes4[i].table_name;
1054       sql += kIndexes4[i].columns;
1055       EXPECT_TRUE(connection.Execute(sql.c_str()));
1056     }
1057
1058     const char* kNamespacesSql =
1059         "INSERT INTO Namespaces"
1060         "  (cache_id, origin, type, namespace_url, target_url)"
1061         "  VALUES (?, ?, ?, ?, ?)";
1062     sql::Statement statement;
1063     statement.Assign(connection.GetUniqueStatement(kNamespacesSql));
1064     EXPECT_TRUE(statement.is_valid());
1065     for (int i = 0; i < kNumNamespaces; ++i) {
1066       GURL namespace_url(
1067           kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i)));
1068       GURL target_url(
1069           kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i)));
1070       statement.BindInt64(0, i);
1071       statement.BindString(1, kMockOrigin.spec().c_str());
1072       statement.BindInt(2, FALLBACK_NAMESPACE);
1073       statement.BindString(3, namespace_url.spec().c_str());
1074       statement.BindString(4, target_url.spec().c_str());
1075       ASSERT_TRUE(statement.Run());
1076       statement.Reset(true);
1077     }
1078
1079     const char* kWhitelistsSql =
1080         "INSERT INTO OnlineWhiteLists"
1081         "  (cache_id, namespace_url)"
1082         "  VALUES (?, ?)";
1083     statement.Assign(connection.GetUniqueStatement(kWhitelistsSql));
1084     EXPECT_TRUE(statement.is_valid());
1085     for (int i = 0; i < kNumNamespaces; ++i) {
1086       GURL namespace_url(
1087           kMockOrigin.Resolve(base::StringPrintf(kWhitelistUrlFormat, i)));
1088       statement.BindInt64(0, kWhitelistCacheId);
1089       statement.BindString(1, namespace_url.spec().c_str());
1090       ASSERT_TRUE(statement.Run());
1091       statement.Reset(true);
1092     }
1093
1094     EXPECT_TRUE(transaction.Commit());
1095   }
1096
1097   // Open that database and verify that it got upgraded to v5.
1098   AppCacheDatabase db(kDbFile);
1099   EXPECT_TRUE(db.LazyOpen(true));
1100   EXPECT_TRUE(db.db_->DoesColumnExist("Namespaces", "is_pattern"));
1101   EXPECT_TRUE(db.db_->DoesColumnExist("OnlineWhiteLists", "is_pattern"));
1102   EXPECT_EQ(5, db.meta_table_->GetVersionNumber());
1103   EXPECT_EQ(5, db.meta_table_->GetCompatibleVersionNumber());
1104
1105   std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1106   std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1107   EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts,
1108                                          &fallbacks));
1109   EXPECT_TRUE(intercepts.empty());
1110   EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size()));
1111
1112   std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1113   EXPECT_TRUE(db.FindOnlineWhiteListForCache(kWhitelistCacheId, &whitelists));
1114   EXPECT_EQ(kNumNamespaces, static_cast<int>(whitelists.size()));
1115
1116   for (int i = 0; i < kNumNamespaces; ++i) {
1117     GURL expected_namespace_url(
1118         kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i)));
1119     GURL expected_target_url(
1120         kMockOrigin.Resolve(base::StringPrintf(kTargetUrlFormat, i)));
1121     GURL expected_whitelist_url(
1122         kMockOrigin.Resolve(base::StringPrintf(kWhitelistUrlFormat, i)));
1123
1124     EXPECT_EQ(i, fallbacks[i].cache_id);
1125     EXPECT_EQ(FALLBACK_NAMESPACE, fallbacks[i].namespace_.type);
1126     EXPECT_EQ(kMockOrigin, fallbacks[i].origin);
1127     EXPECT_EQ(expected_namespace_url, fallbacks[i].namespace_.namespace_url);
1128     EXPECT_EQ(expected_target_url, fallbacks[i].namespace_.target_url);
1129     EXPECT_FALSE(fallbacks[i].namespace_.is_pattern);
1130     EXPECT_EQ(expected_whitelist_url, whitelists[i].namespace_url);
1131     EXPECT_FALSE(whitelists[i].is_pattern);
1132   }
1133 }
1134 #endif  // !APPCACHE_USE_SIMPLE_CACHE
1135
1136 }  // namespace appcache