1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/browser/appcache/appcache_database.h"
10 #include "content/browser/appcache/appcache_entry.h"
11 #include "sql/connection.h"
12 #include "sql/meta_table.h"
13 #include "sql/statement.h"
14 #include "sql/test/scoped_error_ignorer.h"
15 #include "sql/test/test_helpers.h"
16 #include "sql/transaction.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/sqlite/sqlite3.h"
22 const base::Time kZeroTime
;
28 class AppCacheDatabaseTest
{};
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
);
35 EXPECT_FALSE(db
.LazyOpen(false));
36 EXPECT_TRUE(db
.LazyOpen(true));
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
);
47 std::set
<GURL
> origins
;
48 EXPECT_TRUE(db
.FindOriginsWithGroups(&origins
));
49 EXPECT_TRUE(origins
.empty());
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, base::WriteFile(kOtherFile
, "foo", 3));
62 AppCacheDatabase
db(kDbFile
);
63 EXPECT_FALSE(db
.LazyOpen(false));
64 EXPECT_TRUE(db
.LazyOpen(true));
66 EXPECT_TRUE(base::PathExists(kDbFile
));
67 EXPECT_TRUE(base::DirectoryExists(kNestedDir
));
68 EXPECT_TRUE(base::PathExists(kOtherFile
));
70 EXPECT_TRUE(db
.DeleteExistingAndCreateNewDatabase());
72 EXPECT_TRUE(base::PathExists(kDbFile
));
73 EXPECT_FALSE(base::DirectoryExists(kNestedDir
));
74 EXPECT_FALSE(base::PathExists(kOtherFile
));
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.
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
));
91 const base::FilePath kDbFile
= mock_dir
.AppendASCII("appcache.db");
92 const base::FilePath kOtherFile
= mock_dir
.AppendASCII("other_file");
93 EXPECT_EQ(3, base::WriteFile(kOtherFile
, "foo", 3));
95 // First create a valid db file.
97 AppCacheDatabase
db(kDbFile
);
98 EXPECT_TRUE(db
.LazyOpen(true));
99 EXPECT_TRUE(base::PathExists(kOtherFile
));
100 EXPECT_TRUE(base::PathExists(kDbFile
));
104 ASSERT_TRUE(sql::test::CorruptSizeInHeader(kDbFile
));
106 // Reopening will notice the corruption and delete/recreate the directory.
108 sql::ScopedErrorIgnorer ignore_errors
;
109 ignore_errors
.IgnoreError(SQLITE_CORRUPT
);
110 AppCacheDatabase
db(kDbFile
);
111 EXPECT_TRUE(db
.LazyOpen(true));
112 EXPECT_FALSE(base::PathExists(kOtherFile
));
113 EXPECT_TRUE(base::PathExists(kDbFile
));
114 EXPECT_TRUE(ignore_errors
.CheckIgnoredErrors());
119 TEST(AppCacheDatabaseTest
, WasCorrutionDetected
) {
120 // Real files on disk for this test too, a corrupt database file.
121 base::ScopedTempDir temp_dir
;
122 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
123 const base::FilePath kDbFile
= temp_dir
.path().AppendASCII("appcache.db");
125 // First create a valid db file.
126 AppCacheDatabase
db(kDbFile
);
127 EXPECT_TRUE(db
.LazyOpen(true));
128 EXPECT_TRUE(base::PathExists(kDbFile
));
129 EXPECT_FALSE(db
.was_corruption_detected());
132 ASSERT_TRUE(sql::test::CorruptSizeInHeader(kDbFile
));
134 // See the the corruption is detected and reported.
136 sql::ScopedErrorIgnorer ignore_errors
;
137 ignore_errors
.IgnoreError(SQLITE_CORRUPT
);
138 std::map
<GURL
, int64
> usage_map
;
139 EXPECT_FALSE(db
.GetAllOriginUsage(&usage_map
));
140 EXPECT_TRUE(db
.was_corruption_detected());
141 EXPECT_TRUE(base::PathExists(kDbFile
));
142 EXPECT_TRUE(ignore_errors
.CheckIgnoredErrors());
146 TEST(AppCacheDatabaseTest
, ExperimentalFlags
) {
147 const char kExperimentFlagsKey
[] = "ExperimentFlags";
148 std::string
kInjectedFlags("exp1,exp2");
150 // Real files on disk for this test.
151 base::ScopedTempDir temp_dir
;
152 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
153 const base::FilePath kDbFile
= temp_dir
.path().AppendASCII("appcache.db");
154 const base::FilePath kOtherFile
= temp_dir
.path().AppendASCII("other_file");
155 EXPECT_EQ(3, base::WriteFile(kOtherFile
, "foo", 3));
156 EXPECT_TRUE(base::PathExists(kOtherFile
));
158 // Inject a non empty flags value, and verify it got there.
160 AppCacheDatabase
db(kDbFile
);
161 EXPECT_TRUE(db
.LazyOpen(true));
162 EXPECT_TRUE(db
.meta_table_
->SetValue(kExperimentFlagsKey
, kInjectedFlags
));
164 EXPECT_TRUE(db
.meta_table_
->GetValue(kExperimentFlagsKey
, &flags
));
165 EXPECT_EQ(kInjectedFlags
, flags
);
168 // If flags don't match the expected value, empty string by default,
169 // the database should be recreated and other files should be cleared out.
171 AppCacheDatabase
db(kDbFile
);
172 EXPECT_TRUE(db
.LazyOpen(false));
174 EXPECT_TRUE(db
.meta_table_
->GetValue(kExperimentFlagsKey
, &flags
));
175 EXPECT_TRUE(flags
.empty());
176 EXPECT_FALSE(base::PathExists(kOtherFile
));
180 TEST(AppCacheDatabaseTest
, EntryRecords
) {
181 const base::FilePath kEmptyPath
;
182 AppCacheDatabase
db(kEmptyPath
);
183 EXPECT_TRUE(db
.LazyOpen(true));
185 sql::ScopedErrorIgnorer ignore_errors
;
186 // TODO(shess): Suppressing SQLITE_CONSTRAINT because the code
187 // expects that and handles the resulting error. Consider revising
188 // the code to use INSERT OR IGNORE (which would not throw
189 // SQLITE_CONSTRAINT) and then check ChangeCount() to see if any
190 // changes were made.
191 ignore_errors
.IgnoreError(SQLITE_CONSTRAINT
);
193 AppCacheDatabase::EntryRecord entry
;
196 entry
.url
= GURL("http://blah/1");
197 entry
.flags
= AppCacheEntry::MASTER
;
198 entry
.response_id
= 1;
199 entry
.response_size
= 100;
200 EXPECT_TRUE(db
.InsertEntry(&entry
));
201 EXPECT_FALSE(db
.InsertEntry(&entry
));
204 entry
.url
= GURL("http://blah/2");
205 entry
.flags
= AppCacheEntry::EXPLICIT
;
206 entry
.response_id
= 2;
207 entry
.response_size
= 200;
208 EXPECT_TRUE(db
.InsertEntry(&entry
));
211 entry
.url
= GURL("http://blah/3");
212 entry
.flags
= AppCacheEntry::MANIFEST
;
213 entry
.response_id
= 3;
214 entry
.response_size
= 300;
215 EXPECT_TRUE(db
.InsertEntry(&entry
));
217 std::vector
<AppCacheDatabase::EntryRecord
> found
;
219 EXPECT_TRUE(db
.FindEntriesForCache(1, &found
));
220 EXPECT_EQ(1U, found
.size());
221 EXPECT_EQ(1, found
[0].cache_id
);
222 EXPECT_EQ(GURL("http://blah/1"), found
[0].url
);
223 EXPECT_EQ(AppCacheEntry::MASTER
, found
[0].flags
);
224 EXPECT_EQ(1, found
[0].response_id
);
225 EXPECT_EQ(100, found
[0].response_size
);
228 EXPECT_TRUE(db
.AddEntryFlags(GURL("http://blah/1"), 1,
229 AppCacheEntry::FOREIGN
));
230 EXPECT_TRUE(db
.FindEntriesForCache(1, &found
));
231 EXPECT_EQ(1U, found
.size());
232 EXPECT_EQ(AppCacheEntry::MASTER
| AppCacheEntry::FOREIGN
, found
[0].flags
);
235 EXPECT_TRUE(db
.FindEntriesForCache(2, &found
));
236 EXPECT_EQ(2U, found
.size());
237 EXPECT_EQ(2, found
[0].cache_id
);
238 EXPECT_EQ(GURL("http://blah/2"), found
[0].url
);
239 EXPECT_EQ(AppCacheEntry::EXPLICIT
, found
[0].flags
);
240 EXPECT_EQ(2, found
[0].response_id
);
241 EXPECT_EQ(200, found
[0].response_size
);
242 EXPECT_EQ(2, found
[1].cache_id
);
243 EXPECT_EQ(GURL("http://blah/3"), found
[1].url
);
244 EXPECT_EQ(AppCacheEntry::MANIFEST
, found
[1].flags
);
245 EXPECT_EQ(3, found
[1].response_id
);
246 EXPECT_EQ(300, found
[1].response_size
);
249 EXPECT_TRUE(db
.DeleteEntriesForCache(2));
250 EXPECT_TRUE(db
.FindEntriesForCache(2, &found
));
251 EXPECT_TRUE(found
.empty());
254 EXPECT_TRUE(db
.DeleteEntriesForCache(1));
255 EXPECT_FALSE(db
.AddEntryFlags(GURL("http://blah/1"), 1,
256 AppCacheEntry::FOREIGN
));
258 ASSERT_TRUE(ignore_errors
.CheckIgnoredErrors());
261 TEST(AppCacheDatabaseTest
, CacheRecords
) {
262 const base::FilePath kEmptyPath
;
263 AppCacheDatabase
db(kEmptyPath
);
264 EXPECT_TRUE(db
.LazyOpen(true));
266 sql::ScopedErrorIgnorer ignore_errors
;
267 // TODO(shess): See EntryRecords test.
268 ignore_errors
.IgnoreError(SQLITE_CONSTRAINT
);
270 const AppCacheDatabase::CacheRecord kZeroRecord
;
271 AppCacheDatabase::CacheRecord record
;
272 EXPECT_FALSE(db
.FindCache(1, &record
));
276 record
.online_wildcard
= true;
277 record
.update_time
= kZeroTime
;
278 record
.cache_size
= 100;
279 EXPECT_TRUE(db
.InsertCache(&record
));
280 EXPECT_FALSE(db
.InsertCache(&record
));
282 record
= kZeroRecord
;
283 EXPECT_TRUE(db
.FindCache(1, &record
));
284 EXPECT_EQ(1, record
.cache_id
);
285 EXPECT_EQ(1, record
.group_id
);
286 EXPECT_TRUE(record
.online_wildcard
);
287 EXPECT_TRUE(kZeroTime
== record
.update_time
);
288 EXPECT_EQ(100, record
.cache_size
);
290 record
= kZeroRecord
;
291 EXPECT_TRUE(db
.FindCacheForGroup(1, &record
));
292 EXPECT_EQ(1, record
.cache_id
);
293 EXPECT_EQ(1, record
.group_id
);
294 EXPECT_TRUE(record
.online_wildcard
);
295 EXPECT_TRUE(kZeroTime
== record
.update_time
);
296 EXPECT_EQ(100, record
.cache_size
);
298 EXPECT_TRUE(db
.DeleteCache(1));
299 EXPECT_FALSE(db
.FindCache(1, &record
));
300 EXPECT_FALSE(db
.FindCacheForGroup(1, &record
));
302 EXPECT_TRUE(db
.DeleteCache(1));
304 ASSERT_TRUE(ignore_errors
.CheckIgnoredErrors());
307 TEST(AppCacheDatabaseTest
, GroupRecords
) {
308 const base::FilePath kEmptyPath
;
309 AppCacheDatabase
db(kEmptyPath
);
310 EXPECT_TRUE(db
.LazyOpen(true));
312 sql::ScopedErrorIgnorer ignore_errors
;
313 // TODO(shess): See EntryRecords test.
314 ignore_errors
.IgnoreError(SQLITE_CONSTRAINT
);
316 const GURL
kManifestUrl("http://blah/manifest");
317 const GURL
kOrigin(kManifestUrl
.GetOrigin());
318 const base::Time kLastAccessTime
= base::Time::Now();
319 const base::Time kCreationTime
=
320 kLastAccessTime
- base::TimeDelta::FromDays(7);
322 const AppCacheDatabase::GroupRecord kZeroRecord
;
323 AppCacheDatabase::GroupRecord record
;
324 std::vector
<AppCacheDatabase::GroupRecord
> records
;
326 // Behavior with an empty table
327 EXPECT_FALSE(db
.FindGroup(1, &record
));
328 EXPECT_FALSE(db
.FindGroupForManifestUrl(kManifestUrl
, &record
));
329 EXPECT_TRUE(db
.DeleteGroup(1));
330 EXPECT_TRUE(db
.FindGroupsForOrigin(kOrigin
, &records
));
331 EXPECT_TRUE(records
.empty());
332 EXPECT_FALSE(db
.FindGroupForCache(1, &record
));
335 record
.manifest_url
= kManifestUrl
;
336 record
.origin
= kOrigin
;
337 record
.last_access_time
= kLastAccessTime
;
338 record
.creation_time
= kCreationTime
;
339 EXPECT_TRUE(db
.InsertGroup(&record
));
340 EXPECT_FALSE(db
.InsertGroup(&record
));
343 EXPECT_FALSE(db
.InsertGroup(&record
));
345 record
= kZeroRecord
;
346 EXPECT_TRUE(db
.FindGroup(1, &record
));
347 EXPECT_EQ(1, record
.group_id
);
348 EXPECT_EQ(kManifestUrl
, record
.manifest_url
);
349 EXPECT_EQ(kOrigin
, record
.origin
);
350 EXPECT_EQ(kCreationTime
.ToInternalValue(),
351 record
.creation_time
.ToInternalValue());
352 EXPECT_EQ(kLastAccessTime
.ToInternalValue(),
353 record
.last_access_time
.ToInternalValue());
355 record
= kZeroRecord
;
356 EXPECT_TRUE(db
.FindGroupForManifestUrl(kManifestUrl
, &record
));
357 EXPECT_EQ(1, record
.group_id
);
358 EXPECT_EQ(kManifestUrl
, record
.manifest_url
);
359 EXPECT_EQ(kOrigin
, record
.origin
);
360 EXPECT_EQ(kCreationTime
.ToInternalValue(),
361 record
.creation_time
.ToInternalValue());
362 EXPECT_EQ(kLastAccessTime
.ToInternalValue(),
363 record
.last_access_time
.ToInternalValue());
366 record
.manifest_url
= kOrigin
;
367 record
.origin
= kOrigin
;
368 record
.last_access_time
= kLastAccessTime
;
369 record
.creation_time
= kCreationTime
;
370 EXPECT_TRUE(db
.InsertGroup(&record
));
372 record
= kZeroRecord
;
373 EXPECT_TRUE(db
.FindGroupForManifestUrl(kOrigin
, &record
));
374 EXPECT_EQ(2, record
.group_id
);
375 EXPECT_EQ(kOrigin
, record
.manifest_url
);
376 EXPECT_EQ(kOrigin
, record
.origin
);
377 EXPECT_EQ(kCreationTime
.ToInternalValue(),
378 record
.creation_time
.ToInternalValue());
379 EXPECT_EQ(kLastAccessTime
.ToInternalValue(),
380 record
.last_access_time
.ToInternalValue());
382 EXPECT_TRUE(db
.FindGroupsForOrigin(kOrigin
, &records
));
383 EXPECT_EQ(2U, records
.size());
384 EXPECT_EQ(1, records
[0].group_id
);
385 EXPECT_EQ(kManifestUrl
, records
[0].manifest_url
);
386 EXPECT_EQ(kOrigin
, records
[0].origin
);
387 EXPECT_EQ(2, records
[1].group_id
);
388 EXPECT_EQ(kOrigin
, records
[1].manifest_url
);
389 EXPECT_EQ(kOrigin
, records
[1].origin
);
391 EXPECT_TRUE(db
.DeleteGroup(1));
394 EXPECT_TRUE(db
.FindGroupsForOrigin(kOrigin
, &records
));
395 EXPECT_EQ(1U, records
.size());
396 EXPECT_EQ(2, records
[0].group_id
);
397 EXPECT_EQ(kOrigin
, records
[0].manifest_url
);
398 EXPECT_EQ(kOrigin
, records
[0].origin
);
399 EXPECT_EQ(kCreationTime
.ToInternalValue(),
400 record
.creation_time
.ToInternalValue());
401 EXPECT_EQ(kLastAccessTime
.ToInternalValue(),
402 record
.last_access_time
.ToInternalValue());
404 std::set
<GURL
> origins
;
405 EXPECT_TRUE(db
.FindOriginsWithGroups(&origins
));
406 EXPECT_EQ(1U, origins
.size());
407 EXPECT_EQ(kOrigin
, *(origins
.begin()));
409 const GURL
kManifest2("http://blah2/manifest");
410 const GURL
kOrigin2(kManifest2
.GetOrigin());
412 record
.manifest_url
= kManifest2
;
413 record
.origin
= kOrigin2
;
414 EXPECT_TRUE(db
.InsertGroup(&record
));
417 EXPECT_TRUE(db
.FindOriginsWithGroups(&origins
));
418 EXPECT_EQ(2U, origins
.size());
419 EXPECT_TRUE(origins
.end() != origins
.find(kOrigin
));
420 EXPECT_TRUE(origins
.end() != origins
.find(kOrigin2
));
422 AppCacheDatabase::CacheRecord cache_record
;
423 cache_record
.cache_id
= 1;
424 cache_record
.group_id
= 1;
425 cache_record
.online_wildcard
= true;
426 cache_record
.update_time
= kZeroTime
;
427 EXPECT_TRUE(db
.InsertCache(&cache_record
));
429 record
= kZeroRecord
;
430 EXPECT_TRUE(db
.FindGroupForCache(1, &record
));
431 EXPECT_EQ(1, record
.group_id
);
432 EXPECT_EQ(kManifest2
, record
.manifest_url
);
433 EXPECT_EQ(kOrigin2
, record
.origin
);
435 ASSERT_TRUE(ignore_errors
.CheckIgnoredErrors());
438 TEST(AppCacheDatabaseTest
, GroupAccessAndEvictionTimes
) {
439 const base::FilePath kEmptyPath
;
440 AppCacheDatabase
db(kEmptyPath
);
441 EXPECT_TRUE(db
.LazyOpen(true));
443 const GURL
kManifestUrl("http://blah/manifest");
444 const GURL
kOrigin(kManifestUrl
.GetOrigin());
445 const base::Time kDayOne
=
446 base::Time() + base::TimeDelta::FromDays(1);
447 const base::Time kDayTwo
= kDayOne
+ base::TimeDelta::FromDays(1);
449 // See that the methods behave as expected with an empty db.
450 // To accomodate lazy updating, for consistency, none of them fail
451 // given ids not found in the db.
452 EXPECT_TRUE(db
.UpdateEvictionTimes(1, kDayOne
, kDayTwo
));
453 EXPECT_TRUE(db
.UpdateLastAccessTime(1, kDayOne
));
454 EXPECT_TRUE(db
.CommitLazyLastAccessTimes());
455 EXPECT_TRUE(db
.LazyUpdateLastAccessTime(1, kDayTwo
));
456 EXPECT_TRUE(db
.CommitLazyLastAccessTimes());
458 // Insert a group at DAY1
459 AppCacheDatabase::GroupRecord record
;
461 record
.manifest_url
= kManifestUrl
;
462 record
.origin
= kOrigin
;
463 record
.creation_time
= kDayOne
;
464 record
.last_access_time
= kDayOne
;
465 record
.last_full_update_check_time
= kDayOne
;
466 record
.first_evictable_error_time
= kDayOne
;
467 EXPECT_TRUE(db
.InsertGroup(&record
));
469 // Verify the round trip.
470 record
= AppCacheDatabase::GroupRecord();
471 EXPECT_TRUE(db
.FindGroup(1, &record
));
472 EXPECT_EQ(kDayOne
, record
.last_access_time
);
473 EXPECT_EQ(kDayOne
, record
.last_full_update_check_time
);
474 EXPECT_EQ(kDayOne
, record
.first_evictable_error_time
);
476 // Update the times to DAY2 and verify.
477 EXPECT_TRUE(db
.UpdateEvictionTimes(1, kDayTwo
, kDayTwo
));
478 EXPECT_TRUE(db
.UpdateLastAccessTime(1, kDayTwo
));
479 record
= AppCacheDatabase::GroupRecord();
480 EXPECT_TRUE(db
.FindGroup(1, &record
));
481 EXPECT_EQ(kDayTwo
, record
.last_access_time
);
482 EXPECT_EQ(kDayTwo
, record
.last_full_update_check_time
);
483 EXPECT_EQ(kDayTwo
, record
.first_evictable_error_time
);
485 // Lazy update back to DAY1 and verify its reflected without having committed.
486 EXPECT_TRUE(db
.lazy_last_access_times_
.empty());
487 EXPECT_TRUE(db
.LazyUpdateLastAccessTime(1, kDayOne
));
488 EXPECT_FALSE(db
.lazy_last_access_times_
.empty());
489 record
= AppCacheDatabase::GroupRecord();
490 EXPECT_TRUE(db
.FindGroup(1, &record
));
491 EXPECT_EQ(kDayOne
, record
.last_access_time
);
493 // Commit the lazy value and verify it sticks.
494 EXPECT_TRUE(db
.CommitLazyLastAccessTimes());
495 EXPECT_TRUE(db
.lazy_last_access_times_
.empty());
496 record
= AppCacheDatabase::GroupRecord();
497 EXPECT_TRUE(db
.FindGroup(1, &record
));
498 EXPECT_EQ(kDayOne
, record
.last_access_time
);
500 // Verify a bad lazy group id doesn't fail to commit the good ones on DAY2.
501 EXPECT_TRUE(db
.LazyUpdateLastAccessTime(1, kDayTwo
));
502 EXPECT_TRUE(db
.LazyUpdateLastAccessTime(2, kDayTwo
));
503 EXPECT_EQ(2u, db
.lazy_last_access_times_
.size());
504 EXPECT_TRUE(db
.CommitLazyLastAccessTimes());
505 EXPECT_TRUE(db
.lazy_last_access_times_
.empty());
506 record
= AppCacheDatabase::GroupRecord();
507 EXPECT_TRUE(db
.FindGroup(1, &record
));
508 EXPECT_EQ(kDayTwo
, record
.last_access_time
);
511 TEST(AppCacheDatabaseTest
, NamespaceRecords
) {
512 const base::FilePath kEmptyPath
;
513 AppCacheDatabase
db(kEmptyPath
);
514 EXPECT_TRUE(db
.LazyOpen(true));
516 sql::ScopedErrorIgnorer ignore_errors
;
517 // TODO(shess): See EntryRecords test.
518 ignore_errors
.IgnoreError(SQLITE_CONSTRAINT
);
520 const GURL
kFooNameSpace1("http://foo/namespace1");
521 const GURL
kFooNameSpace2("http://foo/namespace2");
522 const GURL
kFooFallbackEntry("http://foo/entry");
523 const GURL
kFooOrigin(kFooNameSpace1
.GetOrigin());
524 const GURL
kBarNameSpace1("http://bar/namespace1");
525 const GURL
kBarNameSpace2("http://bar/namespace2");
526 const GURL
kBarFallbackEntry("http://bar/entry");
527 const GURL
kBarOrigin(kBarNameSpace1
.GetOrigin());
529 const AppCacheDatabase::NamespaceRecord kZeroRecord
;
530 AppCacheDatabase::NamespaceRecord record
;
531 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
532 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
534 // Behavior with an empty table
535 EXPECT_TRUE(db
.FindNamespacesForCache(1, &intercepts
, &fallbacks
));
536 EXPECT_TRUE(fallbacks
.empty());
537 EXPECT_TRUE(db
.FindNamespacesForOrigin(kFooOrigin
, &intercepts
, &fallbacks
));
538 EXPECT_TRUE(fallbacks
.empty());
539 EXPECT_TRUE(db
.DeleteNamespacesForCache(1));
541 // Two records for two differenent caches in the Foo origin.
543 record
.origin
= kFooOrigin
;
544 record
.namespace_
.namespace_url
= kFooNameSpace1
;
545 record
.namespace_
.target_url
= kFooFallbackEntry
;
546 EXPECT_TRUE(db
.InsertNamespace(&record
));
547 EXPECT_FALSE(db
.InsertNamespace(&record
));
550 record
.origin
= kFooOrigin
;
551 record
.namespace_
.namespace_url
= kFooNameSpace2
;
552 record
.namespace_
.target_url
= kFooFallbackEntry
;
553 EXPECT_TRUE(db
.InsertNamespace(&record
));
556 EXPECT_TRUE(db
.FindNamespacesForCache(1, &intercepts
, &fallbacks
));
557 EXPECT_EQ(1U, fallbacks
.size());
558 EXPECT_EQ(1, fallbacks
[0].cache_id
);
559 EXPECT_EQ(kFooOrigin
, fallbacks
[0].origin
);
560 EXPECT_EQ(kFooNameSpace1
, fallbacks
[0].namespace_
.namespace_url
);
561 EXPECT_EQ(kFooFallbackEntry
, fallbacks
[0].namespace_
.target_url
);
562 EXPECT_FALSE(fallbacks
[0].namespace_
.is_pattern
);
565 EXPECT_TRUE(db
.FindNamespacesForCache(2, &intercepts
, &fallbacks
));
566 EXPECT_EQ(1U, fallbacks
.size());
567 EXPECT_EQ(2, fallbacks
[0].cache_id
);
568 EXPECT_EQ(kFooOrigin
, fallbacks
[0].origin
);
569 EXPECT_EQ(kFooNameSpace2
, fallbacks
[0].namespace_
.namespace_url
);
570 EXPECT_EQ(kFooFallbackEntry
, fallbacks
[0].namespace_
.target_url
);
571 EXPECT_FALSE(fallbacks
[0].namespace_
.is_pattern
);
574 EXPECT_TRUE(db
.FindNamespacesForOrigin(kFooOrigin
, &intercepts
, &fallbacks
));
575 EXPECT_EQ(2U, fallbacks
.size());
576 EXPECT_EQ(1, fallbacks
[0].cache_id
);
577 EXPECT_EQ(kFooOrigin
, fallbacks
[0].origin
);
578 EXPECT_EQ(kFooNameSpace1
, fallbacks
[0].namespace_
.namespace_url
);
579 EXPECT_EQ(kFooFallbackEntry
, fallbacks
[0].namespace_
.target_url
);
580 EXPECT_FALSE(fallbacks
[0].namespace_
.is_pattern
);
581 EXPECT_EQ(2, fallbacks
[1].cache_id
);
582 EXPECT_EQ(kFooOrigin
, fallbacks
[1].origin
);
583 EXPECT_EQ(kFooNameSpace2
, fallbacks
[1].namespace_
.namespace_url
);
584 EXPECT_EQ(kFooFallbackEntry
, fallbacks
[1].namespace_
.target_url
);
585 EXPECT_FALSE(fallbacks
[1].namespace_
.is_pattern
);
587 EXPECT_TRUE(db
.DeleteNamespacesForCache(1));
589 EXPECT_TRUE(db
.FindNamespacesForOrigin(kFooOrigin
, &intercepts
, &fallbacks
));
590 EXPECT_EQ(1U, fallbacks
.size());
591 EXPECT_EQ(2, fallbacks
[0].cache_id
);
592 EXPECT_EQ(kFooOrigin
, fallbacks
[0].origin
);
593 EXPECT_EQ(kFooNameSpace2
, fallbacks
[0].namespace_
.namespace_url
);
594 EXPECT_EQ(kFooFallbackEntry
, fallbacks
[0].namespace_
.target_url
);
595 EXPECT_FALSE(fallbacks
[0].namespace_
.is_pattern
);
597 // Two more records for the same cache in the Bar origin.
599 record
.origin
= kBarOrigin
;
600 record
.namespace_
.namespace_url
= kBarNameSpace1
;
601 record
.namespace_
.target_url
= kBarFallbackEntry
;
602 record
.namespace_
.is_pattern
= true;
603 EXPECT_TRUE(db
.InsertNamespace(&record
));
606 record
.origin
= kBarOrigin
;
607 record
.namespace_
.namespace_url
= kBarNameSpace2
;
608 record
.namespace_
.target_url
= kBarFallbackEntry
;
609 record
.namespace_
.is_pattern
= true;
610 EXPECT_TRUE(db
.InsertNamespace(&record
));
613 EXPECT_TRUE(db
.FindNamespacesForCache(3, &intercepts
, &fallbacks
));
614 EXPECT_EQ(2U, fallbacks
.size());
615 EXPECT_TRUE(fallbacks
[0].namespace_
.is_pattern
);
616 EXPECT_TRUE(fallbacks
[1].namespace_
.is_pattern
);
619 EXPECT_TRUE(db
.FindNamespacesForOrigin(kBarOrigin
, &intercepts
, &fallbacks
));
620 EXPECT_EQ(2U, fallbacks
.size());
621 EXPECT_TRUE(fallbacks
[0].namespace_
.is_pattern
);
622 EXPECT_TRUE(fallbacks
[1].namespace_
.is_pattern
);
624 ASSERT_TRUE(ignore_errors
.CheckIgnoredErrors());
627 TEST(AppCacheDatabaseTest
, OnlineWhiteListRecords
) {
628 const base::FilePath kEmptyPath
;
629 AppCacheDatabase
db(kEmptyPath
);
630 EXPECT_TRUE(db
.LazyOpen(true));
632 const GURL
kFooNameSpace1("http://foo/namespace1");
633 const GURL
kFooNameSpace2("http://foo/namespace2");
634 const GURL
kBarNameSpace1("http://bar/namespace1");
636 const AppCacheDatabase::OnlineWhiteListRecord kZeroRecord
;
637 AppCacheDatabase::OnlineWhiteListRecord record
;
638 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> records
;
640 // Behavior with an empty table
641 EXPECT_TRUE(db
.FindOnlineWhiteListForCache(1, &records
));
642 EXPECT_TRUE(records
.empty());
643 EXPECT_TRUE(db
.DeleteOnlineWhiteListForCache(1));
646 record
.namespace_url
= kFooNameSpace1
;
647 EXPECT_TRUE(db
.InsertOnlineWhiteList(&record
));
648 record
.namespace_url
= kFooNameSpace2
;
649 record
.is_pattern
= true;
650 EXPECT_TRUE(db
.InsertOnlineWhiteList(&record
));
652 EXPECT_TRUE(db
.FindOnlineWhiteListForCache(1, &records
));
653 EXPECT_EQ(2U, records
.size());
654 EXPECT_EQ(1, records
[0].cache_id
);
655 EXPECT_EQ(kFooNameSpace1
, records
[0].namespace_url
);
656 EXPECT_FALSE(records
[0].is_pattern
);
657 EXPECT_EQ(1, records
[1].cache_id
);
658 EXPECT_EQ(kFooNameSpace2
, records
[1].namespace_url
);
659 EXPECT_TRUE(records
[1].is_pattern
);
662 record
.namespace_url
= kBarNameSpace1
;
663 EXPECT_TRUE(db
.InsertOnlineWhiteList(&record
));
665 EXPECT_TRUE(db
.FindOnlineWhiteListForCache(2, &records
));
666 EXPECT_EQ(1U, records
.size());
668 EXPECT_TRUE(db
.DeleteOnlineWhiteListForCache(1));
670 EXPECT_TRUE(db
.FindOnlineWhiteListForCache(1, &records
));
671 EXPECT_TRUE(records
.empty());
674 TEST(AppCacheDatabaseTest
, DeletableResponseIds
) {
675 const base::FilePath kEmptyPath
;
676 AppCacheDatabase
db(kEmptyPath
);
677 EXPECT_TRUE(db
.LazyOpen(true));
679 sql::ScopedErrorIgnorer ignore_errors
;
680 // TODO(shess): See EntryRecords test.
681 ignore_errors
.IgnoreError(SQLITE_CONSTRAINT
);
683 std::vector
<int64
> ids
;
685 EXPECT_TRUE(db
.GetDeletableResponseIds(&ids
, kint64max
, 100));
686 EXPECT_TRUE(ids
.empty());
688 EXPECT_TRUE(db
.DeleteDeletableResponseIds(ids
));
689 EXPECT_TRUE(db
.InsertDeletableResponseIds(ids
));
692 EXPECT_TRUE(db
.GetDeletableResponseIds(&ids
, kint64max
, 100));
693 EXPECT_EQ(1U, ids
.size());
694 EXPECT_EQ(0, ids
[0]);
696 int64 unused
, deleteable_response_rowid
;
697 unused
= deleteable_response_rowid
= 0;
698 EXPECT_TRUE(db
.FindLastStorageIds(&unused
, &unused
, &unused
,
699 &deleteable_response_rowid
));
700 EXPECT_EQ(1, deleteable_response_rowid
);
703 // Expected to fail due to the duplicate id, 0 is already in the table.
707 EXPECT_FALSE(db
.InsertDeletableResponseIds(ids
));
710 for (int i
= 1; i
< 10; ++i
)
712 EXPECT_TRUE(db
.InsertDeletableResponseIds(ids
));
713 EXPECT_TRUE(db
.FindLastStorageIds(&unused
, &unused
, &unused
,
714 &deleteable_response_rowid
));
715 EXPECT_EQ(10, deleteable_response_rowid
);
718 EXPECT_TRUE(db
.GetDeletableResponseIds(&ids
, kint64max
, 100));
719 EXPECT_EQ(10U, ids
.size());
720 for (int i
= 0; i
< 10; ++i
)
721 EXPECT_EQ(i
, ids
[i
]);
723 // Ensure the limit is respected.
725 EXPECT_TRUE(db
.GetDeletableResponseIds(&ids
, kint64max
, 5));
726 EXPECT_EQ(5U, ids
.size());
727 for (int i
= 0; i
< static_cast<int>(ids
.size()); ++i
)
728 EXPECT_EQ(i
, ids
[i
]);
730 // Ensure the max_rowid is respected (the first rowid is 1).
732 EXPECT_TRUE(db
.GetDeletableResponseIds(&ids
, 5, 100));
733 EXPECT_EQ(5U, ids
.size());
734 for (int i
= 0; i
< static_cast<int>(ids
.size()); ++i
)
735 EXPECT_EQ(i
, ids
[i
]);
737 // Ensure that we can delete from the table.
738 EXPECT_TRUE(db
.DeleteDeletableResponseIds(ids
));
740 EXPECT_TRUE(db
.GetDeletableResponseIds(&ids
, kint64max
, 100));
741 EXPECT_EQ(5U, ids
.size());
742 for (int i
= 0; i
< static_cast<int>(ids
.size()); ++i
)
743 EXPECT_EQ(i
+ 5, ids
[i
]);
745 ASSERT_TRUE(ignore_errors
.CheckIgnoredErrors());
748 TEST(AppCacheDatabaseTest
, OriginUsage
) {
749 const GURL
kManifestUrl("http://blah/manifest");
750 const GURL
kManifestUrl2("http://blah/manifest2");
751 const GURL
kOrigin(kManifestUrl
.GetOrigin());
752 const GURL
kOtherOriginManifestUrl("http://other/manifest");
753 const GURL
kOtherOrigin(kOtherOriginManifestUrl
.GetOrigin());
755 const base::FilePath kEmptyPath
;
756 AppCacheDatabase
db(kEmptyPath
);
757 EXPECT_TRUE(db
.LazyOpen(true));
759 std::vector
<AppCacheDatabase::CacheRecord
> cache_records
;
760 EXPECT_EQ(0, db
.GetOriginUsage(kOrigin
));
761 EXPECT_TRUE(db
.FindCachesForOrigin(kOrigin
, &cache_records
));
762 EXPECT_TRUE(cache_records
.empty());
764 AppCacheDatabase::GroupRecord group_record
;
765 group_record
.group_id
= 1;
766 group_record
.manifest_url
= kManifestUrl
;
767 group_record
.origin
= kOrigin
;
768 EXPECT_TRUE(db
.InsertGroup(&group_record
));
769 AppCacheDatabase::CacheRecord cache_record
;
770 cache_record
.cache_id
= 1;
771 cache_record
.group_id
= 1;
772 cache_record
.online_wildcard
= true;
773 cache_record
.update_time
= kZeroTime
;
774 cache_record
.cache_size
= 100;
775 EXPECT_TRUE(db
.InsertCache(&cache_record
));
777 EXPECT_EQ(100, db
.GetOriginUsage(kOrigin
));
779 group_record
.group_id
= 2;
780 group_record
.manifest_url
= kManifestUrl2
;
781 group_record
.origin
= kOrigin
;
782 EXPECT_TRUE(db
.InsertGroup(&group_record
));
783 cache_record
.cache_id
= 2;
784 cache_record
.group_id
= 2;
785 cache_record
.online_wildcard
= true;
786 cache_record
.update_time
= kZeroTime
;
787 cache_record
.cache_size
= 1000;
788 EXPECT_TRUE(db
.InsertCache(&cache_record
));
790 EXPECT_EQ(1100, db
.GetOriginUsage(kOrigin
));
792 group_record
.group_id
= 3;
793 group_record
.manifest_url
= kOtherOriginManifestUrl
;
794 group_record
.origin
= kOtherOrigin
;
795 EXPECT_TRUE(db
.InsertGroup(&group_record
));
796 cache_record
.cache_id
= 3;
797 cache_record
.group_id
= 3;
798 cache_record
.online_wildcard
= true;
799 cache_record
.update_time
= kZeroTime
;
800 cache_record
.cache_size
= 5000;
801 EXPECT_TRUE(db
.InsertCache(&cache_record
));
803 EXPECT_EQ(5000, db
.GetOriginUsage(kOtherOrigin
));
805 EXPECT_TRUE(db
.FindCachesForOrigin(kOrigin
, &cache_records
));
806 EXPECT_EQ(2U, cache_records
.size());
807 cache_records
.clear();
808 EXPECT_TRUE(db
.FindCachesForOrigin(kOtherOrigin
, &cache_records
));
809 EXPECT_EQ(1U, cache_records
.size());
811 std::map
<GURL
, int64
> usage_map
;
812 EXPECT_TRUE(db
.GetAllOriginUsage(&usage_map
));
813 EXPECT_EQ(2U, usage_map
.size());
814 EXPECT_EQ(1100, usage_map
[kOrigin
]);
815 EXPECT_EQ(5000, usage_map
[kOtherOrigin
]);
818 #if defined(APPCACHE_USE_SIMPLE_CACHE)
819 // There is no such upgrade path in this case.
821 TEST(AppCacheDatabaseTest
, UpgradeSchema4to7
) {
822 // Real file on disk for this test.
823 base::ScopedTempDir temp_dir
;
824 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
825 const base::FilePath kDbFile
= temp_dir
.path().AppendASCII("upgrade4.db");
827 const GURL
kMockOrigin("http://mockorigin/");
828 const char kNamespaceUrlFormat
[] = "namespace%d";
829 const char kWhitelistUrlFormat
[] = "whitelist%d";
830 const char kTargetUrlFormat
[] = "target%d";
831 const int kNumNamespaces
= 10;
832 const int kWhitelistCacheId
= 1;
834 // Create a v4 schema based database containing some fallback records.
836 const int kVersion4
= 4;
837 const char kGroupsTable
[] = "Groups";
838 const char kCachesTable
[] = "Caches";
839 const char kEntriesTable
[] = "Entries";
840 const char kNamespacesTable
[] = "Namespaces";
841 const char kOnlineWhiteListsTable
[] = "OnlineWhiteLists";
842 const char kDeletableResponseIdsTable
[] = "DeletableResponseIds";
845 const char* table_name
;
850 const char* index_name
;
851 const char* table_name
;
856 const TableInfo kTables4
[] = {
858 "(group_id INTEGER PRIMARY KEY,"
860 " manifest_url TEXT,"
861 " creation_time INTEGER,"
862 " last_access_time INTEGER)" },
865 "(cache_id INTEGER PRIMARY KEY,"
867 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
868 " update_time INTEGER,"
869 " cache_size INTEGER)" }, // intentionally not normalized
875 " response_id INTEGER,"
876 " response_size INTEGER)" },
880 " origin TEXT," // intentionally not normalized
882 " namespace_url TEXT,"
883 " target_url TEXT)" },
885 { kOnlineWhiteListsTable
,
887 " namespace_url TEXT)" },
889 { kDeletableResponseIdsTable
,
890 "(response_id INTEGER NOT NULL)" },
893 const IndexInfo kIndexes4
[] = {
894 { "GroupsOriginIndex",
899 { "GroupsManifestIndex",
904 { "CachesGroupIndex",
909 { "EntriesCacheIndex",
914 { "EntriesCacheAndUrlIndex",
919 { "EntriesResponseIdIndex",
924 { "NamespacesCacheIndex",
929 { "NamespacesOriginIndex",
934 { "NamespacesCacheAndUrlIndex",
936 "(cache_id, namespace_url)",
939 { "OnlineWhiteListCacheIndex",
940 kOnlineWhiteListsTable
,
944 { "DeletableResponsesIdIndex",
945 kDeletableResponseIdsTable
,
950 const int kTableCount4
= arraysize(kTables4
);
951 const int kIndexCount4
= arraysize(kIndexes4
);
953 sql::Connection connection
;
954 EXPECT_TRUE(connection
.Open(kDbFile
));
956 sql::Transaction
transaction(&connection
);
957 EXPECT_TRUE(transaction
.Begin());
959 sql::MetaTable meta_table
;
960 EXPECT_TRUE(meta_table
.Init(&connection
, kVersion4
, kVersion4
));
962 for (int i
= 0; i
< kTableCount4
; ++i
) {
963 std::string
sql("CREATE TABLE ");
964 sql
+= kTables4
[i
].table_name
;
965 sql
+= kTables4
[i
].columns
;
966 EXPECT_TRUE(connection
.Execute(sql
.c_str()));
969 for (int i
= 0; i
< kIndexCount4
; ++i
) {
971 if (kIndexes4
[i
].unique
)
972 sql
+= "CREATE UNIQUE INDEX ";
974 sql
+= "CREATE INDEX ";
975 sql
+= kIndexes4
[i
].index_name
;
977 sql
+= kIndexes4
[i
].table_name
;
978 sql
+= kIndexes4
[i
].columns
;
979 EXPECT_TRUE(connection
.Execute(sql
.c_str()));
982 const char* kNamespacesSql
=
983 "INSERT INTO Namespaces"
984 " (cache_id, origin, type, namespace_url, target_url)"
985 " VALUES (?, ?, ?, ?, ?)";
986 sql::Statement statement
;
987 statement
.Assign(connection
.GetUniqueStatement(kNamespacesSql
));
988 EXPECT_TRUE(statement
.is_valid());
989 for (int i
= 0; i
< kNumNamespaces
; ++i
) {
991 kMockOrigin
.Resolve(base::StringPrintf(kNamespaceUrlFormat
, i
)));
993 kMockOrigin
.Resolve(base::StringPrintf(kTargetUrlFormat
, i
)));
994 statement
.BindInt64(0, i
);
995 statement
.BindString(1, kMockOrigin
.spec().c_str());
996 statement
.BindInt(2, APPCACHE_FALLBACK_NAMESPACE
);
997 statement
.BindString(3, namespace_url
.spec().c_str());
998 statement
.BindString(4, target_url
.spec().c_str());
999 ASSERT_TRUE(statement
.Run());
1000 statement
.Reset(true);
1003 const char* kWhitelistsSql
=
1004 "INSERT INTO OnlineWhiteLists"
1005 " (cache_id, namespace_url)"
1007 statement
.Assign(connection
.GetUniqueStatement(kWhitelistsSql
));
1008 EXPECT_TRUE(statement
.is_valid());
1009 for (int i
= 0; i
< kNumNamespaces
; ++i
) {
1011 kMockOrigin
.Resolve(base::StringPrintf(kWhitelistUrlFormat
, i
)));
1012 statement
.BindInt64(0, kWhitelistCacheId
);
1013 statement
.BindString(1, namespace_url
.spec().c_str());
1014 ASSERT_TRUE(statement
.Run());
1015 statement
.Reset(true);
1018 EXPECT_TRUE(transaction
.Commit());
1021 // Open that database and verify that it got upgraded to v7.
1022 AppCacheDatabase
db(kDbFile
);
1023 EXPECT_TRUE(db
.LazyOpen(true));
1024 EXPECT_TRUE(db
.db_
->DoesColumnExist("Namespaces", "is_pattern"));
1025 EXPECT_TRUE(db
.db_
->DoesColumnExist("OnlineWhiteLists", "is_pattern"));
1026 EXPECT_TRUE(db
.db_
->DoesColumnExist("Groups",
1027 "last_full_update_check_time"));
1028 EXPECT_TRUE(db
.db_
->DoesColumnExist("Groups",
1029 "first_evictable_error_time"));
1030 EXPECT_EQ(7, db
.meta_table_
->GetVersionNumber());
1031 EXPECT_EQ(7, db
.meta_table_
->GetCompatibleVersionNumber());
1033 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1034 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1035 EXPECT_TRUE(db
.FindNamespacesForOrigin(kMockOrigin
, &intercepts
,
1037 EXPECT_TRUE(intercepts
.empty());
1038 EXPECT_EQ(kNumNamespaces
, static_cast<int>(fallbacks
.size()));
1040 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1041 EXPECT_TRUE(db
.FindOnlineWhiteListForCache(kWhitelistCacheId
, &whitelists
));
1042 EXPECT_EQ(kNumNamespaces
, static_cast<int>(whitelists
.size()));
1044 for (int i
= 0; i
< kNumNamespaces
; ++i
) {
1045 GURL
expected_namespace_url(
1046 kMockOrigin
.Resolve(base::StringPrintf(kNamespaceUrlFormat
, i
)));
1047 GURL
expected_target_url(
1048 kMockOrigin
.Resolve(base::StringPrintf(kTargetUrlFormat
, i
)));
1049 GURL
expected_whitelist_url(
1050 kMockOrigin
.Resolve(base::StringPrintf(kWhitelistUrlFormat
, i
)));
1052 EXPECT_EQ(i
, fallbacks
[i
].cache_id
);
1053 EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE
, fallbacks
[i
].namespace_
.type
);
1054 EXPECT_EQ(kMockOrigin
, fallbacks
[i
].origin
);
1055 EXPECT_EQ(expected_namespace_url
, fallbacks
[i
].namespace_
.namespace_url
);
1056 EXPECT_EQ(expected_target_url
, fallbacks
[i
].namespace_
.target_url
);
1057 EXPECT_FALSE(fallbacks
[i
].namespace_
.is_pattern
);
1058 EXPECT_EQ(expected_whitelist_url
, whitelists
[i
].namespace_url
);
1059 EXPECT_FALSE(whitelists
[i
].is_pattern
);
1062 #endif // !APPCACHE_USE_SIMPLE_CACHE
1064 // Verify last_full_update_check_time and first_evictable_error_time.
1065 TEST(AppCacheDatabaseTest
, UpgradeSchema5or6to7
) {
1066 // Real file on disk for this test.
1067 base::ScopedTempDir temp_dir
;
1068 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
1069 const base::FilePath kDbFile
=
1070 temp_dir
.path().AppendASCII("upgrade5or6to7.db");
1072 const GURL
kMockOrigin("http://mockorigin/");
1073 const base::Time kMockTime
= base::Time::Now();
1075 // Create a v5or6 schema based database containing two groups, one
1076 // that has an associated cache as expected, and one which erroneously
1077 // is missing its cache record.
1079 // The SQL schema is the same in these two cases.
1080 #if defined(APPCACHE_USE_SIMPLE_CACHE)
1081 const int kVersionN
= 6;
1083 const int kVersionN
= 5;
1084 #endif // !APPCACHE_USE_SIMPLE_CACHE
1086 const char kGroupsTable
[] = "Groups";
1087 const char kCachesTable
[] = "Caches";
1088 const char kEntriesTable
[] = "Entries";
1089 const char kNamespacesTable
[] = "Namespaces";
1090 const char kOnlineWhiteListsTable
[] = "OnlineWhiteLists";
1091 const char kDeletableResponseIdsTable
[] = "DeletableResponseIds";
1094 const char* table_name
;
1095 const char* columns
;
1099 const char* index_name
;
1100 const char* table_name
;
1101 const char* columns
;
1105 const TableInfo kTables5
[] = {
1107 "(group_id INTEGER PRIMARY KEY,"
1109 " manifest_url TEXT,"
1110 " creation_time INTEGER,"
1111 " last_access_time INTEGER)" },
1114 "(cache_id INTEGER PRIMARY KEY,"
1115 " group_id INTEGER,"
1116 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
1117 " update_time INTEGER,"
1118 " cache_size INTEGER)" }, // intentionally not normalized
1121 "(cache_id INTEGER,"
1124 " response_id INTEGER,"
1125 " response_size INTEGER)" },
1128 "(cache_id INTEGER,"
1129 " origin TEXT," // intentionally not normalized
1131 " namespace_url TEXT,"
1133 " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
1135 { kOnlineWhiteListsTable
,
1136 "(cache_id INTEGER,"
1137 " namespace_url TEXT,"
1138 " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
1140 { kDeletableResponseIdsTable
,
1141 "(response_id INTEGER NOT NULL)" },
1144 const IndexInfo kIndexes5
[] = {
1145 { "GroupsOriginIndex",
1150 { "GroupsManifestIndex",
1155 { "CachesGroupIndex",
1160 { "EntriesCacheIndex",
1165 { "EntriesCacheAndUrlIndex",
1170 { "EntriesResponseIdIndex",
1175 { "NamespacesCacheIndex",
1180 { "NamespacesOriginIndex",
1185 { "NamespacesCacheAndUrlIndex",
1187 "(cache_id, namespace_url)",
1190 { "OnlineWhiteListCacheIndex",
1191 kOnlineWhiteListsTable
,
1195 { "DeletableResponsesIdIndex",
1196 kDeletableResponseIdsTable
,
1201 const int kTableCount5
= arraysize(kTables5
);
1202 const int kIndexCount5
= arraysize(kIndexes5
);
1204 sql::Connection connection
;
1205 EXPECT_TRUE(connection
.Open(kDbFile
));
1207 sql::Transaction
transaction(&connection
);
1208 EXPECT_TRUE(transaction
.Begin());
1210 sql::MetaTable meta_table
;
1211 EXPECT_TRUE(meta_table
.Init(&connection
, kVersionN
, kVersionN
));
1213 for (int i
= 0; i
< kTableCount5
; ++i
) {
1214 std::string
sql("CREATE TABLE ");
1215 sql
+= kTables5
[i
].table_name
;
1216 sql
+= kTables5
[i
].columns
;
1217 EXPECT_TRUE(connection
.Execute(sql
.c_str()));
1220 for (int i
= 0; i
< kIndexCount5
; ++i
) {
1222 if (kIndexes5
[i
].unique
)
1223 sql
+= "CREATE UNIQUE INDEX ";
1225 sql
+= "CREATE INDEX ";
1226 sql
+= kIndexes5
[i
].index_name
;
1228 sql
+= kIndexes5
[i
].table_name
;
1229 sql
+= kIndexes5
[i
].columns
;
1230 EXPECT_TRUE(connection
.Execute(sql
.c_str()));
1233 sql::Statement statement
;
1235 const GURL
kMockManifestUrl(kMockOrigin
.Resolve("mockmanifest"));
1236 const GURL
kMockManifest2Url(kMockOrigin
.Resolve("mockmanifest2"));
1238 const char* kInsertGroup
=
1239 "INSERT INTO Groups"
1240 " (group_id, origin, manifest_url, creation_time, last_access_time)"
1241 " VALUES (?, ?, ?, ?, ?)";
1242 statement
.Assign(connection
.GetUniqueStatement(kInsertGroup
));
1243 EXPECT_TRUE(statement
.is_valid());
1244 statement
.BindInt64(0, 1);
1245 statement
.BindString(1, kMockOrigin
.spec().c_str());
1246 statement
.BindString(2, kMockManifestUrl
.spec().c_str());
1247 statement
.BindInt64(3, kMockTime
.ToInternalValue());
1248 statement
.BindInt64(4, kMockTime
.ToInternalValue());
1249 ASSERT_TRUE(statement
.Run());
1250 statement
.Reset(true);
1251 statement
.BindInt64(0, 2);
1252 statement
.BindString(1, kMockOrigin
.spec().c_str());
1253 statement
.BindString(2, kMockManifest2Url
.spec().c_str());
1254 statement
.BindInt64(3, kMockTime
.ToInternalValue());
1255 statement
.BindInt64(4, kMockTime
.ToInternalValue());
1256 ASSERT_TRUE(statement
.Run());
1257 statement
.Reset(true);
1259 const char* kInsertCache
=
1260 "INSERT INTO Caches"
1261 " (cache_id, group_id, online_wildcard, update_time, cache_size)"
1262 " VALUES (?, ?, ?, ?, ?)";
1263 statement
.Assign(connection
.GetUniqueStatement(kInsertCache
));
1264 EXPECT_TRUE(statement
.is_valid());
1265 statement
.BindInt64(0, 1);
1266 statement
.BindInt64(1, 1);
1267 statement
.BindInt(2, 0);
1268 statement
.BindInt64(3, kMockTime
.ToInternalValue());
1269 statement
.BindInt64(4, 1000);
1270 ASSERT_TRUE(statement
.Run());
1271 statement
.Reset(true);
1273 EXPECT_TRUE(transaction
.Commit());
1276 // Open that database and verify that it got upgraded to v7.
1277 AppCacheDatabase
db(kDbFile
);
1278 EXPECT_TRUE(db
.LazyOpen(true));
1279 EXPECT_TRUE(db
.db_
->DoesColumnExist("Groups",
1280 "last_full_update_check_time"));
1281 EXPECT_TRUE(db
.db_
->DoesColumnExist("Groups",
1282 "first_evictable_error_time"));
1283 EXPECT_EQ(7, db
.meta_table_
->GetVersionNumber());
1284 EXPECT_EQ(7, db
.meta_table_
->GetCompatibleVersionNumber());
1286 AppCacheDatabase::GroupRecord group
;
1287 EXPECT_TRUE(db
.FindGroup(1, &group
));
1288 EXPECT_EQ(kMockTime
, group
.last_full_update_check_time
);
1289 EXPECT_EQ(kZeroTime
, group
.first_evictable_error_time
);
1290 EXPECT_TRUE(db
.FindGroup(2, &group
));
1291 EXPECT_EQ(kZeroTime
, group
.last_full_update_check_time
);
1292 EXPECT_EQ(kZeroTime
, group
.first_evictable_error_time
);
1295 } // namespace content