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.
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"
21 const base::Time kZeroTime;
27 class AppCacheDatabaseTest {};
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);
34 EXPECT_FALSE(db.LazyOpen(false));
35 EXPECT_TRUE(db.LazyOpen(true));
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);
46 std::set<GURL> origins;
47 EXPECT_TRUE(db.FindOriginsWithGroups(&origins));
48 EXPECT_TRUE(origins.empty());
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));
61 AppCacheDatabase db(kDbFile);
62 EXPECT_FALSE(db.LazyOpen(false));
63 EXPECT_TRUE(db.LazyOpen(true));
65 EXPECT_TRUE(base::PathExists(kDbFile));
66 EXPECT_TRUE(base::DirectoryExists(kNestedDir));
67 EXPECT_TRUE(base::PathExists(kOtherFile));
69 EXPECT_TRUE(db.DeleteExistingAndCreateNewDatabase());
71 EXPECT_TRUE(base::PathExists(kDbFile));
72 EXPECT_FALSE(base::DirectoryExists(kNestedDir));
73 EXPECT_FALSE(base::PathExists(kOtherFile));
76 TEST(AppCacheDatabaseTest, ExperimentalFlags) {
77 const char kExperimentFlagsKey[] = "ExperimentFlags";
78 std::string kInjectedFlags("exp1,exp2");
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));
88 AppCacheDatabase db(kDbFile);
89 EXPECT_TRUE(db.LazyOpen(true));
91 // Inject a non empty flags value, and verify it got there.
92 EXPECT_TRUE(db.meta_table_->SetValue(kExperimentFlagsKey, kInjectedFlags));
94 EXPECT_TRUE(db.meta_table_->GetValue(kExperimentFlagsKey, &flags));
95 EXPECT_EQ(kInjectedFlags, flags);
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));
106 TEST(AppCacheDatabaseTest, EntryRecords) {
107 const base::FilePath kEmptyPath;
108 AppCacheDatabase db(kEmptyPath);
109 EXPECT_TRUE(db.LazyOpen(true));
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);
119 AppCacheDatabase::EntryRecord entry;
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));
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));
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));
143 std::vector<AppCacheDatabase::EntryRecord> found;
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);
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);
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);
175 EXPECT_TRUE(db.DeleteEntriesForCache(2));
176 EXPECT_TRUE(db.FindEntriesForCache(2, &found));
177 EXPECT_TRUE(found.empty());
180 EXPECT_TRUE(db.DeleteEntriesForCache(1));
181 EXPECT_FALSE(db.AddEntryFlags(GURL("http://blah/1"), 1,
182 AppCacheEntry::FOREIGN));
184 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
187 TEST(AppCacheDatabaseTest, CacheRecords) {
188 const base::FilePath kEmptyPath;
189 AppCacheDatabase db(kEmptyPath);
190 EXPECT_TRUE(db.LazyOpen(true));
192 sql::ScopedErrorIgnorer ignore_errors;
193 // TODO(shess): See EntryRecords test.
194 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
196 const AppCacheDatabase::CacheRecord kZeroRecord;
197 AppCacheDatabase::CacheRecord record;
198 EXPECT_FALSE(db.FindCache(1, &record));
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));
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);
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);
224 EXPECT_TRUE(db.DeleteCache(1));
225 EXPECT_FALSE(db.FindCache(1, &record));
226 EXPECT_FALSE(db.FindCacheForGroup(1, &record));
228 EXPECT_TRUE(db.DeleteCache(1));
230 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
233 TEST(AppCacheDatabaseTest, GroupRecords) {
234 const base::FilePath kEmptyPath;
235 AppCacheDatabase db(kEmptyPath);
236 EXPECT_TRUE(db.LazyOpen(true));
238 sql::ScopedErrorIgnorer ignore_errors;
239 // TODO(shess): See EntryRecords test.
240 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
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);
248 const AppCacheDatabase::GroupRecord kZeroRecord;
249 AppCacheDatabase::GroupRecord record;
250 std::vector<AppCacheDatabase::GroupRecord> records;
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));
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));
269 EXPECT_FALSE(db.InsertGroup(&record));
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());
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());
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));
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());
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);
317 EXPECT_TRUE(db.DeleteGroup(1));
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());
330 std::set<GURL> origins;
331 EXPECT_TRUE(db.FindOriginsWithGroups(&origins));
332 EXPECT_EQ(1U, origins.size());
333 EXPECT_EQ(kOrigin, *(origins.begin()));
335 const GURL kManifest2("http://blah2/manifest");
336 const GURL kOrigin2(kManifest2.GetOrigin());
338 record.manifest_url = kManifest2;
339 record.origin = kOrigin2;
340 EXPECT_TRUE(db.InsertGroup(&record));
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));
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));
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);
361 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
364 TEST(AppCacheDatabaseTest, NamespaceRecords) {
365 const base::FilePath kEmptyPath;
366 AppCacheDatabase db(kEmptyPath);
367 EXPECT_TRUE(db.LazyOpen(true));
369 sql::ScopedErrorIgnorer ignore_errors;
370 // TODO(shess): See EntryRecords test.
371 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
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());
382 const AppCacheDatabase::NamespaceRecord kZeroRecord;
383 AppCacheDatabase::NamespaceRecord record;
384 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
385 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
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));
394 // Two records for two differenent caches in the Foo origin.
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));
403 record.origin = kFooOrigin;
404 record.namespace_.namespace_url = kFooNameSpace2;
405 record.namespace_.target_url = kFooFallbackEntry;
406 EXPECT_TRUE(db.InsertNamespace(&record));
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);
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);
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);
440 EXPECT_TRUE(db.DeleteNamespacesForCache(1));
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);
450 // Two more records for the same cache in the Bar origin.
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));
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));
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);
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);
477 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
480 TEST(AppCacheDatabaseTest, OnlineWhiteListRecords) {
481 const base::FilePath kEmptyPath;
482 AppCacheDatabase db(kEmptyPath);
483 EXPECT_TRUE(db.LazyOpen(true));
485 const GURL kFooNameSpace1("http://foo/namespace1");
486 const GURL kFooNameSpace2("http://foo/namespace2");
487 const GURL kBarNameSpace1("http://bar/namespace1");
489 const AppCacheDatabase::OnlineWhiteListRecord kZeroRecord;
490 AppCacheDatabase::OnlineWhiteListRecord record;
491 std::vector<AppCacheDatabase::OnlineWhiteListRecord> records;
493 // Behavior with an empty table
494 EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records));
495 EXPECT_TRUE(records.empty());
496 EXPECT_TRUE(db.DeleteOnlineWhiteListForCache(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));
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);
515 record.namespace_url = kBarNameSpace1;
516 EXPECT_TRUE(db.InsertOnlineWhiteList(&record));
518 EXPECT_TRUE(db.FindOnlineWhiteListForCache(2, &records));
519 EXPECT_EQ(1U, records.size());
521 EXPECT_TRUE(db.DeleteOnlineWhiteListForCache(1));
523 EXPECT_TRUE(db.FindOnlineWhiteListForCache(1, &records));
524 EXPECT_TRUE(records.empty());
527 TEST(AppCacheDatabaseTest, DeletableResponseIds) {
528 const base::FilePath kEmptyPath;
529 AppCacheDatabase db(kEmptyPath);
530 EXPECT_TRUE(db.LazyOpen(true));
532 sql::ScopedErrorIgnorer ignore_errors;
533 // TODO(shess): See EntryRecords test.
534 ignore_errors.IgnoreError(SQLITE_CONSTRAINT);
536 std::vector<int64> ids;
538 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100));
539 EXPECT_TRUE(ids.empty());
541 EXPECT_TRUE(db.DeleteDeletableResponseIds(ids));
542 EXPECT_TRUE(db.InsertDeletableResponseIds(ids));
545 EXPECT_TRUE(db.GetDeletableResponseIds(&ids, kint64max, 100));
546 EXPECT_EQ(1U, ids.size());
547 EXPECT_EQ(0, ids[0]);
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);
556 // Expected to fail due to the duplicate id, 0 is already in the table.
560 EXPECT_FALSE(db.InsertDeletableResponseIds(ids));
563 for (int i = 1; i < 10; ++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);
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]);
576 // Ensure the limit is respected.
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]);
583 // Ensure the max_rowid is respected (the first rowid is 1).
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]);
590 // Ensure that we can delete from the table.
591 EXPECT_TRUE(db.DeleteDeletableResponseIds(ids));
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]);
598 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
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());
608 const base::FilePath kEmptyPath;
609 AppCacheDatabase db(kEmptyPath);
610 EXPECT_TRUE(db.LazyOpen(true));
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());
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));
630 EXPECT_EQ(100, db.GetOriginUsage(kOrigin));
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));
643 EXPECT_EQ(1100, db.GetOriginUsage(kOrigin));
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));
656 EXPECT_EQ(5000, db.GetOriginUsage(kOtherOrigin));
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());
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]);
671 #if defined(APPCACHE_USE_SIMPLE_CACHE)
672 // There is no such upgrade path in this case.
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");
680 const GURL kMockOrigin("http://mockorigin/");
681 const char kNamespaceUrlFormat[] = "namespace%d";
682 const char kTargetUrlFormat[] = "target%d";
683 const int kNumNamespaces = 10;
685 // Create a v3 schema based database containing some fallback records.
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";
696 const char* table_name;
700 "(group_id INTEGER PRIMARY KEY,"
702 " manifest_url TEXT,"
703 " creation_time INTEGER,"
704 " last_access_time INTEGER)" },
707 "(cache_id INTEGER PRIMARY KEY,"
709 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
710 " update_time INTEGER,"
711 " cache_size INTEGER)" }, // intentionally not normalized
717 " response_id INTEGER,"
718 " response_size INTEGER)" },
720 { kFallbackNameSpacesTable,
722 " origin TEXT," // intentionally not normalized
723 " namespace_url TEXT,"
724 " fallback_entry_url TEXT)" },
726 { kOnlineWhiteListsTable,
728 " namespace_url TEXT)" },
730 { kDeletableResponseIdsTable,
731 "(response_id INTEGER NOT NULL)" },
735 const char* index_name;
736 const char* table_name;
740 { "GroupsOriginIndex",
745 { "GroupsManifestIndex",
750 { "CachesGroupIndex",
755 { "EntriesCacheIndex",
760 { "EntriesCacheAndUrlIndex",
765 { "EntriesResponseIdIndex",
770 { "FallbackNameSpacesCacheIndex",
771 kFallbackNameSpacesTable,
775 { "FallbackNameSpacesOriginIndex",
776 kFallbackNameSpacesTable,
780 { "FallbackNameSpacesCacheAndUrlIndex",
781 kFallbackNameSpacesTable,
782 "(cache_id, namespace_url)",
785 { "OnlineWhiteListCacheIndex",
786 kOnlineWhiteListsTable,
790 { "DeletableResponsesIdIndex",
791 kDeletableResponseIdsTable,
796 const int kTableCount3 = ARRAYSIZE_UNSAFE(kTables3);
797 const int kIndexCount3 = ARRAYSIZE_UNSAFE(kIndexes3);
799 sql::Connection connection;
800 EXPECT_TRUE(connection.Open(kDbFile));
802 sql::Transaction transaction(&connection);
803 EXPECT_TRUE(transaction.Begin());
805 sql::MetaTable meta_table;
806 EXPECT_TRUE(meta_table.Init(&connection, kVersion3, kVersion3));
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()));
815 for (int i = 0; i < kIndexCount3; ++i) {
817 if (kIndexes3[i].unique)
818 sql += "CREATE UNIQUE INDEX ";
820 sql += "CREATE INDEX ";
821 sql += kIndexes3[i].index_name;
823 sql += kIndexes3[i].table_name;
824 sql += kIndexes3[i].columns;
825 EXPECT_TRUE(connection.Execute(sql.c_str()));
829 "INSERT INTO FallbackNameSpaces"
830 " (cache_id, origin, namespace_url, fallback_entry_url)"
831 " VALUES (?, ?, ?, ?)";
833 sql::Statement statement;
834 statement.Assign(connection.GetUniqueStatement(kSql));
835 EXPECT_TRUE(statement.is_valid());
836 for (int i = 0; i < kNumNamespaces; ++i) {
838 kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i)));
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);
849 EXPECT_TRUE(transaction.Commit());
852 // Open that database and verify that it got updated.
853 AppCacheDatabase db(kDbFile);
854 EXPECT_TRUE(db.LazyOpen(true));
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"));
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"));
868 EXPECT_EQ(5, db.meta_table_->GetVersionNumber());
869 EXPECT_EQ(5, db.meta_table_->GetCompatibleVersionNumber());
871 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
872 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
873 EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts,
875 EXPECT_TRUE(intercepts.empty());
876 EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size()));
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)));
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);
892 #endif // !APPCACHE_USE_SIMPLE_CACHE
894 #if defined(APPCACHE_USE_SIMPLE_CACHE)
895 // There is no such upgrade path in this case.
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");
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;
910 // Create a v4 schema based database containing some fallback records.
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";
921 const char* table_name;
926 const char* index_name;
927 const char* table_name;
932 const TableInfo kTables4[] = {
934 "(group_id INTEGER PRIMARY KEY,"
936 " manifest_url TEXT,"
937 " creation_time INTEGER,"
938 " last_access_time INTEGER)" },
941 "(cache_id INTEGER PRIMARY KEY,"
943 " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
944 " update_time INTEGER,"
945 " cache_size INTEGER)" }, // intentionally not normalized
951 " response_id INTEGER,"
952 " response_size INTEGER)" },
956 " origin TEXT," // intentionally not normalized
958 " namespace_url TEXT,"
959 " target_url TEXT)" },
961 { kOnlineWhiteListsTable,
963 " namespace_url TEXT)" },
965 { kDeletableResponseIdsTable,
966 "(response_id INTEGER NOT NULL)" },
969 const IndexInfo kIndexes4[] = {
970 { "GroupsOriginIndex",
975 { "GroupsManifestIndex",
980 { "CachesGroupIndex",
985 { "EntriesCacheIndex",
990 { "EntriesCacheAndUrlIndex",
995 { "EntriesResponseIdIndex",
1000 { "NamespacesCacheIndex",
1005 { "NamespacesOriginIndex",
1010 { "NamespacesCacheAndUrlIndex",
1012 "(cache_id, namespace_url)",
1015 { "OnlineWhiteListCacheIndex",
1016 kOnlineWhiteListsTable,
1020 { "DeletableResponsesIdIndex",
1021 kDeletableResponseIdsTable,
1026 const int kTableCount4 = ARRAYSIZE_UNSAFE(kTables4);
1027 const int kIndexCount4 = ARRAYSIZE_UNSAFE(kIndexes4);
1029 sql::Connection connection;
1030 EXPECT_TRUE(connection.Open(kDbFile));
1032 sql::Transaction transaction(&connection);
1033 EXPECT_TRUE(transaction.Begin());
1035 sql::MetaTable meta_table;
1036 EXPECT_TRUE(meta_table.Init(&connection, kVersion4, kVersion4));
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()));
1045 for (int i = 0; i < kIndexCount4; ++i) {
1047 if (kIndexes4[i].unique)
1048 sql += "CREATE UNIQUE INDEX ";
1050 sql += "CREATE INDEX ";
1051 sql += kIndexes4[i].index_name;
1053 sql += kIndexes4[i].table_name;
1054 sql += kIndexes4[i].columns;
1055 EXPECT_TRUE(connection.Execute(sql.c_str()));
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) {
1067 kMockOrigin.Resolve(base::StringPrintf(kNamespaceUrlFormat, i)));
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);
1079 const char* kWhitelistsSql =
1080 "INSERT INTO OnlineWhiteLists"
1081 " (cache_id, namespace_url)"
1083 statement.Assign(connection.GetUniqueStatement(kWhitelistsSql));
1084 EXPECT_TRUE(statement.is_valid());
1085 for (int i = 0; i < kNumNamespaces; ++i) {
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);
1094 EXPECT_TRUE(transaction.Commit());
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());
1105 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1106 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1107 EXPECT_TRUE(db.FindNamespacesForOrigin(kMockOrigin, &intercepts,
1109 EXPECT_TRUE(intercepts.empty());
1110 EXPECT_EQ(kNumNamespaces, static_cast<int>(fallbacks.size()));
1112 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1113 EXPECT_TRUE(db.FindOnlineWhiteListForCache(kWhitelistCacheId, &whitelists));
1114 EXPECT_EQ(kNumNamespaces, static_cast<int>(whitelists.size()));
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)));
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);
1134 #endif // !APPCACHE_USE_SIMPLE_CACHE
1136 } // namespace appcache